1
关注
99
关注者

期货行情引爆的导火线?量价关系的量化研究

创建于: 2025-02-14 17:37:53, 更新于: 2025-02-19 14:18:32
comments   0
hits   21

期货行情引爆的导火线?量价关系的量化研究

各位期友们,如果问你们对哪个期货品种记忆犹新,锰硅(SM888)绝对能排进前三!这个品种平时像个“佛系青年”,不温不火,可一旦行情启动,那简直是“平地惊雷”,涨跌都能让你怀疑人生。比如2024年4月初到5月底,锰硅从6000点一路狂飙到近10000点,仿佛坐上了火箭。然而,好景不长,接下来的一个半月,它又从高点跌回6000点,简直是“过山车”行情。最近,由于锰矿原产地的供应问题,锰硅又上演了一波“旱地拔葱”,短短几个交易日拉高了1400点,结果传闻被证伪后,又迅速打回原形,真是让人哭笑不得。

期货行情引爆的导火线?量价关系的量化研究

很多散户朋友在这波行情中可能经历了“多空双杀”,苦不堪言。由于信息不对称,散户常常被大行情“玩弄于股掌之间”。那么,有没有一种方法可以帮助我们识别行情的引爆点呢?今天,我们就从量价关系的角度,带大家一探究竟。

量价关系:期货行情的“晴雨表”

我们经常在期货行情软件上看到“量增价减”、“量减价减”、“量减价增”、“量增价增”这些术语。听起来很高大上,但它们到底是什么意思?这些现象出现后,期货行情会不会迎来大爆发?今天,我们就用量化研究的方法,在优宽量化平台上为大家揭开这些术语背后的秘密。

期货行情引爆的导火线?量价关系的量化研究

代码逻辑解析

首先,我们来看一下代码的逻辑。这段代码的核心是通过分析历史数据,识别四种量价关系,并跟踪这些事件发生后的市场表现。以下是代码的主要步骤:

  1. 初始化数据结构:我们创建了一个tracking_events队列,用于存储正在跟踪的事件。同时,定义了一个followup_days变量,表示我们需要跟踪事件发生后的5天内的市场表现。

  2. 获取历史数据:通过exchange.GetRecords函数获取锰硅(SM888)的历史数据。如果数据不足22根K线,程序会暂停1秒后重新尝试。

  3. 检测量价关系:代码会检测四种量价关系:

    • 量减价跌:成交量和持仓量减少,价格下跌。
    • 量减价涨:成交量和持仓量减少,价格上涨。
    • 量增价跌:成交量和持仓量增加,价格下跌。
    • 量增价涨:成交量和持仓量增加,价格上涨。

每种量价关系的判断标准都基于当前K线与前一根K线的收盘价、成交量和持仓量的变化。

  1. 跟踪事件:一旦检测到某种量价关系,代码会将该事件加入tracking_events队列,并开始跟踪该事件发生后的市场表现。跟踪的时间长度为followup_days(5天)。

  2. 计算波动幅度:在跟踪期间,代码会记录价格的最高点、最低点,并计算相对于事件发生时的波动幅度。

  3. 保存结果:最终,所有检测到的事件及其后续表现会被保存到一个CSV文件中,方便后续分析。

'''backtest
start: 2020-01-03 00:00:00
end: 2025-02-12 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}]
'''

import pandas as pd

def main():
    # 初始化数据结构
    tracking_events = []  # 正在跟踪的事件队列
    
    followup_days = 5  # 需要跟踪的天数
    symbol = 'SM888'
    markTime = 0
    
    # 创建用于存储结果的DataFrame
    results_df = pd.DataFrame(columns=[
        'EventType', 
        'StartDate',
        'OpenPrice',
        'MaxHigh',
        'MinLow',
        'MaxAmplitude',
        'MinAmplitude'
    ])

    while True:
        # 获取当前交易对的历史数据
        records = exchange.GetRecords(symbol, PERIOD_D1)
        
        # 如果数据为空或不足22根K线,则跳过当前循环
        if not records or len(records) < 22:
            Sleep(1000)  # 暂停1秒
            continue
        
        # 检查数据时间是否更新,如果更新则继续处理
        if markTime != records[-2].Time:
            markTime = records[-2].Time

            # 将数据转换为DataFrame,方便后续处理
            data = [{
                'Time': record.Time,
                'Open': record.Open,
                'High': record.High,
                'Low': record.Low,
                'Close': record.Close,
                'Volume': record.Volume,
                'OpenInterest': record.OpenInterest
            } for record in records]

            try:
                df = pd.DataFrame(data)
            except Exception as e:
                Log(f"创建DataFrame时出错: {e}")
                continue

            df = df[-22:-1]  # 取最近20根有效K线
            
            # 获取当前与前一根K线的各项统计指标
            current_close, prev_close = df.iloc[-1]['Close'], df.iloc[-2]['Close']
            current_volume, prev_volume = df.iloc[-1]['Volume'], df.iloc[-2]['Volume']
            current_int, prev_int = df.iloc[-1]['OpenInterest'], df.iloc[-2]['OpenInterest']

            # 检测四种量价关系
            events = []

            # 量减价跌
            if (current_close / prev_close < 0.9925 and 
                current_volume / prev_volume < 0.8 and 
                current_int / prev_int < 0.95):
                Log('量减价减')
                events.append('numMinpriMin')
                
            # 量减价涨
            if (current_close / prev_close > 1.0075 and 
                current_volume / prev_volume < 0.8 and 
                current_int / prev_int < 0.95):
                Log('量减价增')
                events.append('numMinpriAdd')
                
            # 量增价跌
            if (current_close / prev_close < 0.9925 and 
                current_volume / prev_volume > 1.3 and 
                current_int / prev_int > 1.1):
                Log('量增价减')
                events.append('numAddpriMin')
                
            # 量增价增
            if (current_close / prev_close > 1.0075 and 
                current_volume / prev_volume > 1.3 and 
                current_int / prev_int > 1.1):
                Log('量增价增')
                events.append('numAddpriAdd')

            # 将新检测到的事件添加到跟踪队列中
            for event_type in events:
                tracking_events.append({
                    'type': event_type,
                    'start_time': records[-1]['Time'],
                    'opens': [records[-1]['Open']],
                    'highs': [records[-1]['Open']],
                    'lows': [records[-1]['Open']],
                    'days_collected': 0
                })

            # 处理正在跟踪的事件,逐天收集数据
            for event in tracking_events[:]:  # 使用副本避免在循环中修改原列表
                # 获取事件发生后的后续数据
                if event['days_collected'] == 0:
                    event['days_collected'] = 1
                    break 
                if event['days_collected'] < followup_days + 1:
                    event['days_collected'] += 1
                    event['opens'].append(records[-1]['Open'])
                    event['highs'].append(records[-2]['High'])
                    event['lows'].append(records[-2]['Low'])

                # 如果已收集足够天数,处理并移除事件
                if event['days_collected'] >= followup_days + 1:
                    first_close = event['opens'][0]
                    max_high = max(event['highs'])
                    min_low = min(event['lows'])
                    
                    # 计算波动幅度
                    max_amplitude = (max_high - first_close) / first_close * 100
                    min_amplitude = (first_close - min_low) / first_close * 100
                    
                    # 存入结果
                    # 创建一个新的行数据
                    new_row = pd.DataFrame({
                        'EventType': [event['type']],
                        'StartDate': [pd.to_datetime(event['start_time'], unit='ms')],
                        'OpenPrice': [first_close],
                        'MaxHigh': [max_high],
                        'MinLow': [min_low],
                        'MaxAmplitude': [f"{max_amplitude:.2f}%"],
                        'MinAmplitude': [f"{min_amplitude:.2f}%"]
                    })

                    # 使用 pd.concat 添加新行
                    results_df = pd.concat([results_df, new_row], ignore_index=True)
                    
                    # 移除已完成的事件
                    tracking_events.remove(event)

            # 每轮循环结束后,将结果保存到CSV文件
            results_df.to_csv('量价关系.csv', index=False)
            
        # 等待下一根K线
        Sleep(1000 * 60 * 5)  # 5分钟周期调整为对应时间

量价关系的秘密:数据告诉你真相

数据回测事件为2020年1月至2025年2月,各事件类型的出现频率,涨跌幅统计特征值在下面表格中进行呈现。根据我们的量化研究,我们得到了以下结果:

事件类型 计数 涨幅最大值 涨幅最小值 跌幅最大值 跌幅最小值 涨幅均值 跌幅均值
量增价增 25 17.77% 0.00% 7.84% 0.06% 4.94% 2.86%
量增价减 21 8.59% 0.05% 5.53% 0.00% 2.65% 1.84%
量减价增 12 8.64% 0.28% 8.22% 0.28% 2.94% 3.41%
量减价减 12 6.45% 0.35% 25.98% 0.44% 2.62% 5.77%

期货行情引爆的导火线?量价关系的量化研究

数据回测事件为2020年1月至2025年2月,各事件类型的出现频率

1. 量增价增(numAddpriAdd):最容易出现“巨涨”行情

  • 当成交量和价格同时增加时,市场情绪通常非常乐观,资金大量涌入,推动价格快速上涨。根据数据,这种情况下,价格的最大涨幅平均为4.94%,而最大跌幅仅为2.86%。这意味着,量增价增往往是行情爆发的信号,适合做多。

2. 量增价减(numAddpriMin):小心“狂跌”行情

  • 当成交量增加但价格下跌时,市场可能出现了“出货”现象。大资金可能在悄悄离场,导致价格承压。根据数据,这种情况下,价格的最大跌幅平均为1.84%,而最大涨幅仅为2.65%。这意味着,量增价减可能是行情反转的信号,适合谨慎操作。

3. 量减价增(numMinpriAdd):行情可能“虚胖”

  • 当成交量减少但价格上涨时,市场可能缺乏足够的资金支持,价格上涨的可持续性存疑。根据数据,这种情况下,价格的最大涨幅平均为2.94%,而最大跌幅为3.41%。这意味着,量减价增可能是行情虚高的信号,适合警惕回调。

4. 量减价减(numMinpriMin):行情可能“躺平”

  • 当成交量和价格同时减少时,市场通常处于低迷状态,缺乏明确的方向。根据数据,这种情况下,价格的最大跌幅平均为5.77%,而最大涨幅仅为2.62%。这意味着,量减价减可能是市场进入盘整或下跌的信号,适合观望或做空。

总结:量价关系是你的“行情指南针”

通过这次量化研究,我们发现,量价关系确实是期货行情的“晴雨表”。不同的量价组合,往往预示着不同的市场走势。对于散户朋友来说,掌握这些规律,可以帮助你更好地识别行情的引爆点,避免被大行情“玩弄”。

  • 量增价增:行情爆发的信号,适合做多。
  • 量增价减:行情反转的信号,适合谨慎操作。
  • 量减价增:行情虚高的信号,适合警惕回调。
  • 量减价减:市场低迷的信号,适合观望或做空。

当然,市场永远是复杂多变的,量价关系只是其中的一个参考指标。在实际操作中,还需要结合其他技术指标和基本面分析,才能做出更准确的判断。希望这篇文章能为大家提供一些有用的参考,祝各位期友在期货市场中乘风破浪,不受庄家摆布!

温馨提示:期货市场风险较大,入市需谨慎。量价关系虽好,但不可盲目依赖哦!

更多内容