网格交易这策略,表面上看起来特别简单:跌了买一格、涨了卖一格,低买高卖赚震荡的钱。但真正想验证“这策略到底能不能赚钱”,你会发现市面上能用的工具几乎没有几个顺手的。用Excel手算只能应付三五笔交易,用通用量化框架跑又总觉得哪里不对劲——成交价对不上、手续费算不准、T+1没处理、涨跌停还照样成交。我陆陆续续折腾了快两个月,最后决定自己写一套A股与ETF通用的网格交易回测工具,核心就抓两件事:参数深度自定义、高精度策略验证。这篇文章就把这套工具从设计思路到回测引擎的完整实现拆开讲清楚,给同样在做网格策略验证的朋友一条可以复现的路。
1. 网格交易回测难在哪:先想清楚问题再动手
1.1 网格策略的本质是路径依赖
要理解网格回测为什么难做,得先理解网格策略本身的特性。一个标准等距网格,比如以基准价4.0元为中心、每隔0.1元挂一档,上面每卖出一格赚0.1元差价,下面每买入一格则等待反弹卖出。这个逻辑看起来只跟价格点位有关,但实际盈亏高度依赖价格运行的“路线”:
同样是三个月后价格回到4.0元,如果期间价格在3.8到4.2之间来回震荡了二十次,网格策略会收获二十次低买高卖的利润;如果价格一路下跌到3.5再涨回4.0,整个过程只成交了几笔买入,账户处于浮亏状态。两个场景的起点终点完全一样,持仓结果却天差地别。
这就是所谓的“路径依赖”策略。它决定了网格回测必须用尽可能细的行情数据逐笔模拟,日线级别只能看到一个点,根本没有路径可言。用日K线做网格回测,等于拿一张照片去判断一个人跑步的轨迹,误差大到没有参考价值。
1.2 通用回测框架为什么做不了网格
我最初也尝试过用现成的量化回测框架,接入数据、写策略逻辑、跑回测,流程上似乎都能走通,但一深入就发现各种别扭。
第一问题是网格本质上是“多档位条件单的同时挂起”。一般的回测框架设计逻辑是“每个bar产生一个信号,然后执行一个动作”,而网格要维护一整张挂单表,任何一个价格点都可能触发其中某一档或某几档,这跟“信号-动作”的单线程思路根本不对付。
第二个是成交细节。真实网格交易里,买单挂3.90,价格只要碰到3.90就必须成交,而不会像某些框架默认的那样在K线收盘后以收盘价统一撮合。价格盘中先触3.90又拉回3.95,如果按收盘价撮合,这笔成交就完全丢失,或者被错误地以收盘价成交。这种误差在单笔交易上看着不大,但网格交易恰恰是高频次交易逻辑,几百笔成交每笔差几分钱甚至几毛钱,累积起来足以把策略的盈亏结论彻底扭曲。
第三是A股的特殊规则。100股整数倍下单、T+1卖出限制、涨停无法买入、跌停无法卖出、停牌期间挂单失效,这些规则对网格交易的影响极大,但通用框架往往不处理或者处理得很粗糙。
1.3 我设计工具时确定的核心目标
踩过这些坑之后,我给自己定下五个设计目标:
- 通用性:同一套引擎既能回测A股个股,也能回测ETF,对于印花税、佣金差异做参数化配置;
- 高精度:使用分钟级或tick级数据,按价格触发即时撮合,手续费、滑点、涨停跌停全部建模;
- 深度自定义:网格间距、档位、仓位、基准价、上下边界、风控规则全部外置为配置项,不改代码就能调整策略;
- 可解释:每一笔成交都能追溯,回测报告能回答“这笔为什么成交”“那笔为什么没成交”;
- 可复现:固定随机种子、固定行情数据版本,同一份配置在任何时候跑出来的结果完全一致。
这五个目标实际上就是后面所有模块设计的纲领。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 工具架构与回测主流程:一次行情扫描如何变成完整买卖
2.1 数据层设计
工具的整体架构分成四层:数据层、策略层、撮合层、统计层。数据层是整个系统的基础,这一层做不好,后面全是空中楼阁。
对于网格回测,我强烈建议至少使用分钟级K线。如果能拿到tick级数据更好,但tick数据体积大、获取门槛高,对多数场景来说分钟级已经够用——前提是你接受“这一分钟内价格曾经达到触发价”这个近似。如果你想精确模拟“达到触发价后一定成交”,分钟级数据其实会略微高估成交概率,因为价格可能只在那一分钟内插针触碰,真实挂单未必来得及成交。对此我提供了两档精度模式:标准模式用分钟K线的最高最低价判断是否触碰;严格模式则要求价格必须以有利方向穿透触发价才认为可能成交。
数据源我用的是国内常见的数据服务接口,A股和ETF的日线、分钟线都能拉,前复权、后复权都支持。这里有个容易被忽视的问题:网格策略的触发价是绝对价格,而除权除息会造成价格跳空,所以回测必须使用复权数据做价格判断,但成本计算里又要按真实价格计算成交金额。我的做法是:复权后的价格负责“是否触发”的判断,交易数量按真实持仓逻辑处理后,再乘以原始价格计算成交金额和手续费。两者分开,不要混在一起。
2.2 策略引擎与撮合逻辑
策略层的核心不是“信号生成”,而是“挂单表管理”。每创建一个网格,实际上就是生成了两个方向的挂单集合:基准价上方的一组卖单、下方的一组买单。
每个网格档位我设计成一张长生命周期条件单,带以下属性:
- 触发价格(买入档或卖出档)
- 状态(有效、已触发待成交、已成交、已撤销)
- 所属网格ID(用于成交后配对)
- 方向(buy/sell)
- 对应数量
当行情数据流进来,撮合层按时间顺序一档一档检查所有有效挂单。这里要注意,行情到来时必须同时检查买卖两个方向,因为价格剧烈波动时可能连续穿透多个网格档位。一个严谨的撮合循环大致是这样:
python复制for bar in bars:
# 更新当前价格区间
price_high = bar.high
price_low = bar.low
# 先处理买单:价格下探到触发价
for buy_grid in active_buy_grids:
if buy_grid.trigger_price >= price_low and buy_grid.trigger_price <= price_high:
# 检查资金、可买数量、涨停状态、T+1买入解锁
if canbuy(buy_grid, bar):
fill = execute_buy(bar, buy_grid)
apply_fee(fill)
# 买入成交后,在原触发价上方生成对应卖单
register_sell_grid(fill)
# 记录持仓锁定状态
lock_position(fill, lock_days=1)
# 再处理卖单:价格上探到触发价
for sell_grid in active_sell_grids:
if sell_grid.trigger_price <= price_high and sell_grid.trigger_price >= price_low:
if cansell(sell_grid, bar):
fill = execute_sell(bar, sell_grid)
apply_fee(fill)
# 卖出成交后,买回网格不自动恢复,等待下一轮价格回落
unregister_buy_grid(fill)
这段逻辑拆开看并不复杂,但真正决定精度的地方都在细节里。比如必须先检查买单还是先检查卖单,这会影响到同一根K线内先买后卖和先卖后买的资金状态差异。我默认按“先开后收”的原则:同一个bar内,先处理卖单再处理买单,因为开盘阶段更容易出现冲高卖出,而尾盘跳水更常见买入触发,这个顺序对资金利用率影响明显。
再比如“涨停状态”。A股主板个股上涨10%触及涨停后,理论上还有封单可以排队买入,但大概率买不到。回测里如果简单认为“涨停价可以买入”,会制造大量虚假成交。我的工具里提供三档模式:忽略涨停(宽松)、涨停禁止买入(保守)、涨停按一个可配置的成交概率买入(介于两者之间)。网格回测本身是低频买入逻辑,这种情况下“涨停禁止买入”最贴近实盘。
2.3 资金账户模型
网格交易本质上是分批建仓、滚动止盈的仓位管理游戏,所以资金账户模型必须分得清楚。账户里我维护七个字段:
- 初始资金(配置项)
- 可用现金(用于计算可买数量)
- 冻结现金(网格买单触发后但尚未完成的资金占用,我的实现里因为检查到资金才买入,所以冻结场景主要在T+1限制)
- 持仓市值(按最新价)
- 持仓数量(按证券维度,支持多标的)
- 锁定持仓数量(当日买入,T+1不可卖出)
- 已实现盈亏(每次卖出的差价累计)
这个账户模型看起来常规,但对网格策略有一个特别重要的点:持仓成本信息必须独立记录。网格买入是分批进行的,每格买入成本不同,卖出时到底赚多少钱,取决于配对方式。常见的有两种:先进先出(FIFO)和均价法。对网格策略而言,我推荐FIFO而不是均价法,因为均价法会把早期低位买入的成本和后期高位买入的成本混淆,导致卖出档位的盈亏虚高或虚低,影响后续策略参数判断。
3. 深度参数自定义:从网格间距到触发边界都能调
3.1 网格几何:等差、等比与自定义档位
参数自定义是这套工具的招牌功能。网格间距的几何形态直接决定策略的性格,所以第一步把间距做成三种模式。
等差网格:每档间隔固定为绝对价格差异。比如基准价4.0元,间距0.1元,则下方依次是3.9、3.8、3.7。等差网格的逻辑是“每格价差收益固定”,但它有个问题——对于低价位的支撑能力判断比较粗糙,价格4元的ETF跌到3元和跌到2元,绝对波动意义差别很大。
等比网格:每档间隔固定为百分比。比如间距2%,那么下方档位是4.0 * 0.98 = 3.92、3.92 * 0.98 = 3.8416。等比网格更符合波动率交易直觉,价格越低间距越密,意味着越往下买入越频繁,摊平成本的力度越强。
自定义档位:直接传入一个价格列表,完全手动控制每一档的触发价。这适合有特定支撑压力位判断的选手,比如你在某只ETF的长期筹码密集区手动布网格。
我的配置形如:
python复制grid_config = {
"grid": {
"mode": "percent", # delta / percent / custom
"delta": 0.02, # 等比间距2%
"base_price": 4.0, # 基准价
"upper_bound": 4.6, # 网格上边界
"lower_bound": 3.4, # 网格下边界
"custom_prices": [3.5, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6],
}
}
上下边界的作用很关键:价格突破上边界后,网格停止继续生成卖单,但已有持仓继续持有还是全部清仓?价格跌破下边界后,是停止买入保持沉默,还是启动止损清仓?这些行为在后面的风控参数里配置。
3.2 仓位与资金分配策略
网格的每一格应该买多少,直接决定回撤深度和资金利用率。工具里我实现了三种分配模式:
第一种是固定金额模式。每次触发买入,使用固定的资金量,比如每格买入1万元。这个方式简单直观,但要注意在价格很低时,1万元按100股整数倍可能无法精确花完,需要向下取整。
第二种是可用资金百分比模式。每次触发买入,使用当前可用现金的10%。这个模式的特点是越跌买得越少,因为每次买入消耗了资金,剩余可用资金变少,后续每格买入金额递减。它在极端下跌行情下能拉长“子弹”消耗时间,但也会导致低位买入仓位不足,反弹时吃不到足够利润。很多人用百分比模式算出来的回测结果漂亮,其实是没仔细想过这个问题。
第三种是固定股数模式。每次固定买入1000股,逻辑最简单,每格买入的市值随价格变动。这是我个人最推荐网格新手使用的模式,因为它直观、好算、不易出错。
所有模式的买入数量都必须向100股整数倍取整,卖出时如果持仓不是100股的整数倍,则允许一次性卖出剩余的零股。这个细节真实交易中很常见,不处理的话回测和实盘会差出不少来。
3.3 触发条件与基准价机制
网格策略的“锚”——基准价——什么时候更新,是一个容易忽略但影响巨大的参数。我做了三种模式:固定基准、移动基准、回摆基准。
固定基准最简单:以首次建仓时的价格作为基准,后续网格始终围绕这个价格上下挂单,基准不更新。它的问题在于标的长期上涨后,上方网格被逐步卖光,策略会失去买入机会;长期下跌后,下方网格被深度套牢。
移动基准是每次成交后,把基准价移动到最新成交价或最新触发价,再重新计算整张网格表。这种方式保证网格始终贴着最新价格运行,但代价是频繁移动网格会导致“上涨时追高买入、下跌时追跌卖出”,反而放大风险。
回摆基准是折中方案:价格在网格内波动时不更新基准,只在价格突破了上边界或下边界并回落时才更新基准。例如价格向上突破上边界4.6后回落,工具将基准价重置为回落时刻的价格,并基于新基准重新生成网格。这个机制比较接近实战中网格玩家的手动操作习惯,也是我这套工具里默认推荐的模式。
触发模式上,我额外支持是否只在“价格从不利方向穿越到有利方向”时成交。比如买入档3.9,价格从4.0跌到3.85再涨回3.95,严格模式认为价格穿越了3.9但方向是先向下穿,这确实应该算买入;而更严格的“先触即买”模式认为只要最低价低于等于3.9就算触发。这个差异在分钟级回测里不容易察觉,但在tick级里影响很大。
3.4 动态网格与风控参数
静态网格在震荡市表现最好,但一旦遇到趋势行情就很容易破网。我加入了两个动态能力。
一个是波动率自适应间距。把网格间距设置成ATR的倍数,比如间距 = 最近14日ATR × 0.5。当波动变大时,网格间距变大,避免价格轻易穿过多个格子;当波动收窄时,网格间距变小,保留足够的交易频率。这是我在实盘里觉得最有价值的网格进化功能。
另一个是通道自适应边界。网格上下边界不再写死,而是跟随布林带或滚动最高最低价调整,破上轨才考虑卖出清仓、破下轨才考虑停止买入。这套逻辑让网格策略能从震荡市平滑过渡到趋势市,但参数变多,调参难度也上升。
风控参数则是硬约束,我配置了四个常用项:
- 最大持仓市值比例(比如总资金的80%,防止单一标过度集中)
- 单日最大买入次数(防止极端行情下网格被瞬间打穿)
- 账户最大回撤止损线(例如回撤达到15%时全部清仓停止策略)
- 跌破下边界后的动作(停止买入 / 全部清仓 / 双倍网格下注——最后一项我强烈不建议)
风控参数里最容易被忽略的是“单日最大买入次数”。很多网格爱好者复盘亏损时发现,账户巨亏往往不是每天亏一点,而是在某个暴跌日网格被连续触发十几次、单日买入金额远超计划,然后继续下跌导致整体深度套牢。没有这个限制的网格回测,会好看得让人产生幻觉。
4. 高精度回测的隐藏代价:手续费、滑点、涨跌停与除权除息
4.1 A股交易成本建模
标题里写了“高精度策略验证”,这个精度很大程度体现在交易成本建模上。网格交易单笔利润本来就不高,一个2%的网格毛利,扣掉手续费可能只剩1.5%,再扣滑点可能只剩1.2%。如果回测忽略这些成本,等于策略已经被悄悄美化了几十个百分点。
A股股票的交易成本分四块:买入佣金、卖出佣金、印花税、过户费。ETF则免印花税,这是它跟股票在网格场景下的一大区别。
我的费用配置示例:
python复制fee_config = {
"stock": {
"commission_rate": 0.00025, # 万2.5佣金
"min_commission": 5.0, # 最低佣金5元
"stamp_tax_rate": 0.0005, # 卖出印花税
"transfer_fee_rate": 0.00001, # 过户费
"etf_stamp_tax": False, # ETF免印花税
}
}
值得反复强调的是最低佣金5元这个坑。资金量小的时候,每格买入1万元,按万2.5佣金算应该是2.5元,但实际收5元,佣金直接翻倍。回测里如果忽略最低佣金,小资金网格的回测结果会被严重高估。我自己调试时发现,一个资金20万的网格回测,忽略最低佣金后年化收益虚高了约8个百分点。
4.2 滑点与成交确定性
滑点建模是我这套工具比普通回测框架精细的地方。网格策略的触发价是固定价格,但真实成交价很少恰好等于触发价。买单触发时,价格往往正处于下跌过程中,市价单会以更差的价格成交;卖单触发时同理。我提供了三种滑点模式:
- 固定跳价滑点:买单在触发价基础上加一个tick,卖单减一个tick。ETF的tick通常0.001元,股票则视股价大小而定;
- 百分比滑点:按成交金额的固定比例(如0.1%)加滑点成本,适合模拟流动性一般的标的;
- 冲击成本模型:按照“每分钟成交量”和“委托量占比”估算价格冲击,适合大资金场景,小资金用不上。
这里面有个技巧:如果回测标的是像沪深300ETF这类流动性极好的品种,固定1个tick的滑点基本够用;如果是小盘股或者LOF基金,建议用百分比滑点,甚至滑点到0.2%都不为过。网格交易本来就是赚小差价的钱,滑点稍微一高,整个策略就变味了。
4.3 除权除息与网格密度失真
这可能是网格回测里最隐蔽的一个坑。股票或ETF在除权除息日会有一个价格跳空,比如除息前4.00元,每份分红0.2元,除息后开盘价会跳到3.80附近。如果你的网格是绝对价格挂单,除息跳空会导致网格出现一系列虚假触发:之前挂在3.90的买单会突然“成交”,但实际上你并没有买到便宜货,而是权力除息后的正常价格重定价。
处理方式有两种。第一种是数据层直接使用后复权价格做全流程回测,任何除权除息导致的跳空都被复权因子抹平,网格逻辑完全不受影响。但后复权价格的弊病是计算收益率时会失真,因为它把历史价格做了比例缩放。第二种是使用真实价格回测,在除权除息日检测到价格跳空时,自动重置网格基准价到最新价,并清除原有未触发挂单。这种处理逻辑更接近实盘操作:成熟投资者在除息日前通常会重新审视网格,而不是机械执行。
我自己的工具选择第二种,因为它更能反映真实操作的应变过程。同时在报告中标记出每一个除权除息日,提示这个日期网格被重置过,避免使用者看到收益曲线时的疑惑。
4.4 T+1、涨跌停与停牌的处理
这三条A股特有规则,每一条单拎出来都能让普通回测结果“失真一个级别”。
先说T+1。网格策略很多时候依赖“当天买入的仓位当天卖出”来实现日内套利——比如上午买入,下午反弹后卖出。但A股不支持,当日买入的持仓必须次日才能卖。如果回测框架忽略T+1,等于凭空多给了策略一半的灵活性。我的实现里,买入成交后,该笔持仓会被锁定,直到下一个交易日开盘才解锁可卖。这个细节对网格策略的影响有多大?我的实测数据是:忽略T+1的网格回测年化收益会比真实情况高出10到20个百分点,尤其在高波动交易日密集的区间。
涨跌停的处理前面提过。再补充一点:跌停时不能卖出,意味着网格策略在极端下跌中可能面临“想卖出止盈但卖不掉”的困局,这不算坏事,因为在跌停前其实已经触发了卖出;但如果你想买却因为涨停买不到,就会错过后续上涨。这些不对称性必须如实建模。
停牌处理相对简单但容易漏:停牌期间所有挂单都应该视为无效,复牌后恢复。这个工具里通过数据源的交易状态字段判断,停牌日不参与撮合。
5. 回测结果怎么解读:不要被漂亮曲线骗了
5.1 核心指标体系和回测报告
网格策略的回测报告跟普通趋势策略的需求不太一样,我按实用程度排了序,最重要的五个指标:
- 累计收益率与年化收益率:这是常规指标,但网格策略的年化要结合资金利用率看才有意义;
- 最大回撤:网格策略最大回撤往往发生在单边下跌行情里,因为网格会持续买入摊薄,价格跌得越深,回撤越大。报告里我额外记录了“回撤发生时间区间”,方便对照行情数据看是哪个阶段造成的;
- 交易次数与胜率:网格的“胜率”不是按单笔交易算,而是按“完成一次买入-卖出闭环”的胜率算。如果中途网格被击穿,单边下跌后很多买入没有对应的卖出闭环,胜负比要分开统计;
- 资金利用率:网格策略最大的软肋就是资金效率低。可用现金长期趴在账上。报告里我用“成交金额 / 平均可用资金”来估算,这个数字如果低于40%,说明策略偏保守,资金在闲置;
- 每格收益贡献:按网格档位维度统计,哪个价位的买入贡献了主要利润,哪个价位的买入是亏损主力。这一项对调参特别有用。
5.2 参数敏感性检验
网格参数非常多且相互耦合,间距、仓位、上下边界三者共同决定策略的资金消耗速率和止盈频率。这时候只跑一组参数得出一个漂亮结果,没有任何意义,因为它可能是参数过拟合下的偶然产物。
所以工具内置了一个参数扫描器,支持对指定的两个参数做网格搜索,输出收益热力图。举例来说,固定其他参数,分别扫描网格间距从1%到4%(步长0.2%),仓位百分比从5%到20%(步长1%),跑完25组回测后在热力图上观察:收益是否在一个连续区域都比较稳定?还是只在某一点特别高,周围就塌方?
“参数高原”现象是我判断策略稳健性的核心标准:如果最优解周围是一片收益率高地,说明策略对参数不敏感,实盘执行时小误差不会导致结论剧变;如果最优解只是孤峰,那回测越漂亮越危险,实盘稍有偏差就会完全失效。
5.3 样本外验证和实盘校验
回测做完不意味着结束。我会把历史数据切分成探索集和验证集,前70%的数据用于调参,后30%的数据完全不动,调出最优参数后直接拿到后30%上跑,看结果是否退化。网格策略的适用性跟市场环境高度绑定,震荡市表现好、单边市表现差是天然属性,所以验证期最好能覆盖一段明显的单边下跌行情,检验最坏情况。
最后还有一个很多回测工具给不了但我坚持加上的功能:实盘-回测偏差报告。我建议所有使用者在模拟盘运行两周,然后把模拟盘的真实成交记录导入工具,跟回测结果逐笔对比。重点看四类偏差:滑点是否比模型估计的大、最低佣金是否造成额外损耗、开盘跳空时是否经常错过触发价、涨停跌停时的成交概率假设是否正确。这四类偏差往往比回测模型本身的误差还要大。
5.4 几个让我印象深刻的实测教训
写这套工具期间我跑过不少真实标的的回测,有几组结果印象很深,分享出来供参考。
一只高波动的行业ETF,等距网格间距2%,回测年化看着很诱人——最大回撤控制在12%以内,年化收益接近15%。但把数据放大到分钟级、加上T+1和涨停跌停限制后,年化直接掉到7%左右。主要原因是日线级别回测错误地让“当日买入当日卖出”发生了太多次,高估了交易频率。
另一个例子是低佣金ETF网格。券商给到万1的佣金且没有最低5元限制时,网格策略的盈利能力明显提升,收益率比万2.5佣金高出2到3个百分点。这本身不意外,但我想强调的是,这个差异在参数敏感性检验中会导致最优网格间距发生偏移。许多人在一个券商的佣金环境下调好的参数,换到另一家券商实盘直接变形,根子就在这里。
还有一个回测中容易犯的傻:把网格上边界设得太高。回测里价格大部分时间在低位震荡,上方卖单不断成交,收益曲线一路上涨;但偶尔来一波大牛市,价格突破上边界后,策略的所有仓位都卖光了,只能眼巴巴看着行情上涨,收益被趋势策略远远甩开。网格策略的收益天花板是真实存在的,回测报告里必须把这个“踏空损失”也统计出来,给用户一个完整的收益来源拆解。
我个人运行了这套工具一年多后的体会是:网格回测最有价值的产出并不是“这个参数组合年化能到多少”,而是让你在真实行情到来之前,就知道自己的策略会在什么环境下失效、最大回撤发生在哪个区间、资金会被锁死到什么程度。把这些最坏情况看清楚之后,实盘执行时的心态会稳很多。回测的本质是给策略做压力测试,而不是给未来的收益打包票。想明白这一点,工具的使用方式自然就会从“调参凑好结果”转向“理解策略边界”,这比多几个点的回测收益重要得多。
