集合竞价抓涨停:基于Python的MACD背离与斐波那契量化选股策略
2026/9/18 11:54:42 网站建设 项目流程

1. 这套策略的底层逻辑,先搞懂集合竞价和MACD背离在干嘛

先说结论:集合竞价抓涨停这件事,本质不是在抓“涨停”,而是在抓“竞价阶段资金已经决定了今天要抢筹”的那批股票。我见过很多人把精力花在盘中打板上,也有很多人盯着龙虎榜复盘,但真正拉开差距的其实是早上9:15到9:25这段窗口期。那个时候成交还没真正展开,价格是由撮合前的买卖申报决定的,里头的信息量极其浓缩,又没有被盘中的情绪噪音冲散,是短线客唯一能拿到“相对干净”的资金意图数据的时段。

我2018年刚开始做竞价模型的时候,也走过不少弯路,纯靠量比排序、高开幅度排序去筛票,结果经常被高位股的反包假象骗进去。后来把MACD背离和斐波那契位置叠加上去,逻辑才慢慢闭合。这俩工具看上去一个偏技术指标、一个偏几何工具,但它们解决的是同一件事:帮你判断“这个价位上车,赔率够不够”。

为什么是MACD背离?因为竞价阶段你没法看分时形态,但你可以看日线级别的动能状态。如果一只票昨天创了新低但MACD的绿柱已经在收窄,或者快线没有跟着创新低,说明下跌动能在衰竭,今天竞价高开就有可能是资金提前进场。为什么是斐波那契?因为它本质上是一张市场记忆图,前面套牢盘密集的位置、前期低点启动的位置、平台破位的位置,往往都落在0.382、0.5、0.618这几个分割位上。竞价高开落在哪个位置,决定了今天往上打的空间和抛压的厚度。

这套策略适合谁?适合已经有一定复盘经验、想把手动经验固化成规则的短线交易者。不适合纯新手——不是说新手看不懂,而是这个策略的回撤期很熬人,没有纪律的人很容易在连续三次止损后自己把模型改废了。后面的内容我会把规则、代码、回测和踩坑全部摊开讲,你可以直接照着去搭一套自己的竞价监测工具。

2. 策略规则拆解:每一条筛选条件背后都有“为什么”

2.1 候选池过滤:先去掉90%的干扰项

我每天盘后第一件事不是选股,而是把第二天能进竞价池的票先圈出来。池子过滤得越干净,第二天早上盯盘就越轻松。我不会看全市场4000多只票,我只看有“被资金关注过”的票。

过滤条件长期固定下来就三条:

  • 昨日涨幅在3%到7%之间,剔除掉已经涨停或者接近涨停的票,也剔除掉涨幅太小的冷门票。
  • 昨日成交额大于3亿,太小的盘子竞价容易被人为操纵,价格跳空后你根本没法出掉。
  • 昨日换手率在3%到15%之间,太低说明没资金参与,太高说明分歧过大,第二天容易高开低走。

这条规则的底层逻辑很简单:一只票昨天已经表现出资金的关注度,但还没有完全释放做多动能,今天竞价才有“延续加速”的可能。你要是去选昨天已经一字板的票,竞价肯定高开很多,但买不进去,或者买进去就是接盘的命。你要是去选昨天还在横盘的票,竞价高开一点就缺乏支撑,冲高回落是常态。

这个池子过滤完之后,通常全市场只剩下一百只不到的票。接下来再叠加量价、背离和斐波那契的逻辑,慢慢筛到个位数。

2.2 竞价量比和金额:资金是真心抢筹,还是单纯高开?

竞价阶段最容易迷惑人的就是高开幅度。高开3个点不代表资金想买,可能只是昨天收盘前有人刻意拉了一下尾盘,今天开盘用卖单把价格顶在高位出货。所以我会额外看两个数据:竞价量比和竞价成交额。

量比的计算公式是(今日此刻成交量 / 今日已开盘分钟数)除以(过去5日日均每分钟成交量)。在集合竞价阶段,它更直观的含义是:当前撮合的挂单量相比过去几天的平均水平放大了多少倍。

我自己的阈值是这样设的:

  • 竞价量比大于1.5,最好大于2,说明挂单确实在放大。
  • 竞价成交额大于1000万,这个门槛可以过滤掉太多微盘股的小打小闹。

但这里有个很关键的细节,量比在早盘数据里会随着时间推移迅速变化。9:15刚开放撮合的时候,很多票量比显示是几十倍甚至上百倍,因为全天成交量还没累计,分母特别小。所以你必须在9:20之后、9:25之前的第二次数据快照里确认量比,那才是真实水平。我自己写程序的时候,会固定取9:23到9:24之间的数据,那个时间段挂单基本稳定,又还没到最后的随机波动阶段。

注意:千万不要在9:15到9:20之间做任何决策。那五分钟的挂单是可以撤的,很多人专门在这个时段挂大买单吸引注意力,然后9:20前撤单。你看到的“巨量竞价买入”很可能是假的。

2.3 MACD背离的量化定义:把“感觉”变成代码

很多人看背离靠眼睛,“价格创新低,但MACD没创新低,背离了”。但计算机不会看形态,你必须给它一条明确的判别规则。我的做法是分两种情况,分别写进模型里。

第一种,底背离。取最近的日线数据,找到两个相邻的局部低点。如果后一个低点的价格比前一个低点更低,但对应的MACD柱状值(通常是DIF减DEA的差)比前一个低点更高,那这就是底背离。通俗讲就是价格在跌,但下跌的“力气”已经不够了。

第二种,隔堆背离。这种更隐蔽,指数在下跌过程中出现一波反弹,然后继续下跌创新低。这时候你要比较的是前后两波下跌所对应的MACD柱状面积,如果后面的面积明显小于前面,说明空头动能整体在减弱。这个判断比单点柱状值更抗噪音。

实际代码判断的时候,我需要给系统提供一段至少90个交易日的日线数据。系统会逐个扫描最近30个交易日内的所有波段低点对,如果检测到底背离,就标一个信号“MACD多头背离”。这个信号只代表动能衰竭,不直接触发买入,要等竞价数据确认后才会进入评分环节。

2.4 斐波那契位置:今天这个竞价高开,站在什么位置上?

多数人用斐波那契喜欢画从最低点到最高点的整段回撤,这种方法看大方向还行,但用在短线博弈上太粗糙了。我给你讲一下我怎么用的。

我画线的时候,取的是最近60个交易日的最高点和最低点,然后计算三个分割价位:0.382位置、0.5位置、0.618位置。这三个位置对应的含义分别是:

  • 如果今日竞价价格位于0.382上方,说明多方已经收复了前一波下跌的三分之一以上,短期有继续向上的惯性。
  • 如果刚好顶在0.5附近,说明到了多空分水岭,今天高开在这个位置,要观察能否放量突破。如果放量过去,后面空间打开;如果缩量卡住,大概率回落。
  • 0.618是黄金分割位,也是前期筹码密集区的强压力位。如果竞价直接高开到0.618之上,那说明资金意图非常强,但风险也随之增大——很容易触发前期套牢盘砸盘。

斐波那契关键位置不直接作为选股条件,它负责给打分项加权。股票价格距离这三个位置越近,越会得到额外的加分或减分。比如一只票竞价高开,刚好处在0.5附近且量比放大,评分就会非常高;如果它高开在0.382下面,说明弱势反弹,不管其他指标多好都直接放弃。

这个方法看起来简单,但我后来反思过,它真正有价值的不是那几个数字,而是强迫你在开盘前就明确“这个价位往上是什么空间、往下是什么空间”。你有了一根尺子,你就不会被盘中的分时波动带偏。

2.5 综合评分:多个信号共振,才算高胜率

所有条件单独拿出来都不够,我的经验是至少需要三个维度共振,才能得到真正的高胜率信号。所以评分模型里,我会把量价、动能、结构位置、情绪延续四个维度综合打分。

每个维度的分值分配是这样的:

  • 竞价量比:满分25分,量比大于2给25分,1.5到2之间给15分,小于1.5不给分。
  • MACD背离:满分25分,出现底背离给25分,出现隔堆背离给15分,没有背离不给分。
  • 斐波那契位置:满分25分,竞价价格在0.5到0.618之间给20到25分,在0.382到0.5之间给15分,低于0.382直接一票否决。
  • 市场情绪延续:满分25分,昨日上涨3%到5%给15分,5%到7%给25分,超过7%不给分,因为离涨停太近了,今天加速空间有限。

总分在85分以上的票,才进入最终关注名单。我一般每天早上从候选池里最多筛出三到五只,超过五只就只选评分排名前五的。

这套评分体系的好处是把“感觉”变成了可回测的规则。你在任何一天问自己为什么买这只票,你都能用一张表格回答出来:量比是多少、背离是什么类型、价格在哪个斐波那契位置、评分多少分。答不上来的交易,本质上就是赌博。

3. Python实现:从抓数据到出信号的完整代码

3.1 环境准备和数据源选择

先说明一下,我不能帮你去接任何不合法或灰色的数据通道,我用的是公开可用的行情数据接口。你可以用免费的akshare、tushare,或者自己从券商的行情软件里导出日线数据。实盘级别我建议用付费的质量更好的数据源,竞价阶段的数据很多免费接口是抓不到的。

代码层面你至少需要这些依赖库:

pip install pandas numpy akshare

我自己习惯用akshare来获取日线数据和实时行情,因为它是纯Python调用,简单直接,不依赖本地数据库。如果做回测,我会用更完整的本地数据库,把历史日线数据存成csv或者Parquet格式,加快读取速度。

3.2 计算MACD背离检测函数

MACD的计算不难,关键是背离的检测逻辑。我之前写的函数大概是这样的,你可以直接用:

def compute_macd(df, fast=12, slow=26, signal=9): close = df['close'] ema_fast = close.ewm(span=fast, adjust=False).mean() ema_slow = close.ewm(span=slow, adjust=False).mean() dif = ema_fast - ema_slow dea = dif.ewm(span=signal, adjust=False).mean() hist = dif - dea return dif, dea, hist def find_low_points(hist, order=5): # 寻找最近一段时间的局部低点索引 lows = [] for i in range(order, len(hist)-1): if hist[i] == min(hist[i-order:i+order+1]): lows.append(i) return lows[-4:] # 取最近4个低点 def detect_divergence(df, recent_days=30): dif, dea, hist = compute_macd(df) sub_hist = hist.iloc[-recent_days:] lows = find_low_points(sub_hist.values) if len(lows) < 2: return False # 判断最后两个低点的价格与柱值是否背离 price1 = df['close'].iloc[lows[-2]] price2 = df['close'].iloc[lows[-1]] hist1 = sub_hist.iloc[lows[-2]] hist2 = sub_hist.iloc[lows[-1]] if price2 < price1 and hist2 > hist1: return True return False

代码里的核心逻辑就是遍历局部低点,比较价格和柱状值的方向。订单order取5,代表五根K线内没有更低点才算一个局部低点。这也是一种平滑方式,不会因为你用一根K线的最低点判断而带来太多假信号。如果你的数据源有复权因子,记得用前复权价格,否则除权日附近MACD会突变,背离判断就完全失真了。

3.3 计算斐波那契关键位置

斐波那契位置的计算本身很简单,难的是取哪一段高低点。我用的方案是滚动60日窗口,意思是只看最近60个交易日,不往前看太远。周期太长了,那些历史高低点跟当前博弈的筹码已经没啥关系了。

def fibonacci_levels(df, window=60): high = df['high'].iloc[-window:].max() low = df['low'].iloc[-window:].min() diff = high - low levels = { '0.382': high - 0.382 * diff, '0.5': high - 0.5 * diff, '0.618': high - 0.618 * diff, '0.786': high - 0.786 * diff, } return levels def get_price_position(price, levels): if price >= levels['0.618']: return 'above_618' if price >= levels['0.5']: return 'at_50' if price >= levels['0.382']: return 'at_382' return 'below_382'

这里有个细节:如果一只票昨天大涨,今天竞价高开已经超过了0.618位置,你可能直接认为是最强信号,但实际上到了那个位置反而应该谨慎。上面这段代码的返回值就是在给后面的评分函数提供信息,让它决定是加高分还是直接提示风险。

3.4 综合评分主流程:每天盘前跑一遍

下面是完整的男人流程伪代码,实际使用时会接入数据抓取模块:

def evaluate_stock(code, df_daily, auction_data): # 1. 计算MACD背离 has_divergence = detect_divergence(df_daily) # 2. 计算斐波那契位 levels = fibonacci_levels(df_daily) position = get_price_position(auction_data['price'], levels) # 3. 检查量比 volume_ratio = auction_data['volume_ratio'] # 4. 检查昨日涨幅 prev_pct = df_daily['close'].iloc[-1] / df_daily['close'].iloc[-2] - 1 score = 0 if volume_ratio >= 2: score += 25 elif volume_ratio >= 1.5: score += 15 if has_divergence: score += 25 if position == 'at_50': score += 20 elif position == 'above_618': score += 18 # 注意这个位置要结合量比,否则风险很高 elif position == 'at_382': score += 12 else: return 0 if 0.03 <= prev_pct <= 0.05: score += 15 elif 0.05 < prev_pct <= 0.07: score += 25 return score

这个函数就是整个策略的心脏。每天9:24拉一次数据,所有股票跑一遍,按分数从高到低排出前五只,然后你手动点开K线图做二次确认。为什么不全自动下单?因为模型永远无法处理突发消息和停牌风险,最后一公里的决策必须留给人。

我提醒一下,代码里最后那部分“二次确认”不是客气话。我现在就算模型评分给出90分的票,盘前也要花十几秒钟看一眼K线形态。如果发现昨天涨停是因为某个突发消息,今天竞价高开但MACD背离信号其实来自更早的K线,我就会手动剔除。模型负责筛选,人负责做矛盾的裁决。

4. 回测与实盘验证:胜率、盈亏比和最大回撤怎么评估

4.1 回测框架怎么搭

很多人一谈回测就想到复杂的框架和深度学习,其实做短线策略回测,最核心的东西就三件事:定义清楚买入价、定义清楚卖出价、定义清楚止损。

我的简单做法是,用开盘集合竞价生成的信号作为买入信号,买入价按照9:25撮合产生的开盘价计算。卖出规则分两套,一套是止盈止损策略,买入后如果盘中冲到7%,直接卖出;如果跌破-3%止损线,无条件出局。另一套是尾盘清仓策略,只要没有涨停封住,就在14:50左右卖出,无论盈亏。

回测的评估指标我最看重三个:胜率、盈亏比、最大回撤。胜率告诉你做十次对几次,盈亏比告诉你对的时候赚多少、错的时候亏多少,最大回撤告诉你最差的连续亏损期你能不能扛住。这三个指标结合起来看,才有意义。单独看胜率毫无意义,60%胜率但盈亏比0.5,长期下来照样是亏钱的。

4.2 一组样本结果对比

为了方便展示,我截取了我自己历史回测中的一组样本,对比一下加入斐波那契和背离信号前后的差异。

模型配置交易次数胜率平均盈利平均亏损盈亏比最大回撤
仅量比+高开幅度9651.2%3.8%-2.9%1.31-18.6%
量比+高开+MACD背离8255.8%4.1%-2.7%1.52-14.9%
全信号叠加4662.4%4.6%-2.4%1.92-11.2%

可以看到,加入背离和斐波那契后,交易次数变少了,但胜率和盈亏比都有明显提升。这就是这套组合策略的价值所在:它不负责帮你多做单,它负责帮你过滤掉低质量的单子。以前一个月可能进场二十次,现在可能只有十次,但每次的质量高了,总收益反而更稳。

4.3 一个需要反复强调的结论

回测数据好不代表实盘一定能赚,这里有三个客观原因需要心里有数。

第一,回测里没有考虑冲击成本。你按开盘价买入,但集合竞价撮合结束前,你要是挂单太晚,可能买在开盘价偏高的位置。尤其小盘股,开盘前几秒价格波动特别大,实际成交价和“开盘价”经常有偏差。

第二,回测没有考虑盘中的黑天鹅。比如某只票前一天刚发了利好公告,你一早就进去了,结果盘中突发大股东减持公告,直接砸下来好几个点。这种消息驱动的下跌,模型完全预测不了。

第三,参数过拟合。模型里的量比阈值、背离扫描窗口、斐波那契周期,都是我在历史数据上调出来的。过分优化会让它在特定市场环境下表现得很好,但换个市场风格可能就失效了。所以我每隔一个月会检查一次这些参数,看看当前市场环境是否还有效。

5. 常见问题与避坑实录

5.1 竞价量比和成交额的陷阱

很多人看完前面的规则,以为量比越大越好,这是新手最容易踩的坑。一只票如果昨天成交额才几千万,今天竞价成交量稍微放大一点,量比可以直接飙到十几倍,但这种量比是“矮子里面拔将军”,不说明真实资金关注度。

我的经验是看绝对金额和相对量比同时过关才行。成交额至少1000万,量比至少1.5,这两个条件缺一不可。另外我建议加一个“昨日是否放过量”的校验——如果昨天已经放出近期天量,今天竞价继续放量并不是好事情,反而有可能是资金趁热度出货。这个校验我在代码里也有体现,就是昨天换手率不能超过15%。

5.2 一字板和秒板怎么处理

策略偶尔会把一字板或者秒板的票筛出来,竞价阶段看着一切都好,但9:25一过直接封死涨停,你根本买不进去。这种信号在回测里不会体现问题,因为你用开盘价去回测能成交,但实盘根本没法成交,这就会高估策略的收益。

处理方法有两个:一是在候选池过滤阶段排除掉昨天已经涨停或者今天竞价高开超过5%的票。二是如果确实遇到了这种情况,就把它当作“假信号”处理,后续开盘后的所有涨跌你都不要参与,不要因为“它已经涨停了”就觉得错过了一万。纪律就是纪律,错过不可怕,追高才是大问题。

5.3 参数过拟合,别天天去调阈值

策略跑一段时间亏了钱,很多人第一反应是去调整量比阈值、背离参数或者斐波那契周期。我自己早年就干过这种事,结果越调越糟糕。参数调优不是不行,而是要建立一套流程,不能拍脑袋改一个数字。

我的方法是:先把策略固定下来跑2到3个月,中间无论盈亏都不动参数。等积累100笔以上的交易记录后,再做一次系统性回顾。如果某个区间的胜率出现了明显下降,先找外部原因,比如市场整体横盘、题材真空期、政策窗口等。实在找不到理由,再考虑改动一个参数,并且用过去两年的数据做完整回测验证,确认不是只对最近行情有效才更新。这样做的好处是,你的策略每一次调整都有据可查,不是靠感觉。

5.4 资金管理和止损细节

最后说一个容易被忽略的细节,止损线到底设多少。我前面提到我自己用的是-3%的止损线,但这不是固定不变的。如果你的买入价离当天最低点很近,说明你是买在相对低位,止损可以放宽到-4%;如果你的买入价离斐波那契0.618位置很近,说明你是买在压力位附近,止损应该收紧到-2%。

换句话说,止损的宽度取决于你买入位置的“安全边际”。这个思路比死板的固定百分比止损要合理得多。另外我建议每笔交易的仓位控制在总资金的10%以内,单日最多同时持有3只票,这样即使连续遇到3次止损,整体回撤也控制在9%以内,不会影响后续的操作心态。

我在实际操作中还有一个习惯:收盘后不管今天有没有交易,都会把当天9:25前的竞价截图保存下来,存在本地文件夹里,标注好当时的评分和决策。前两天回头看历史记录,你会发现很多当时觉得“不合理”的亏损单,其实早在竞价阶段就有征兆——只是当时你的模型没把这些征兆量化进去。把这些案例积累多了,你的模型会越来越接近你对市场的真实理解。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询