ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

网格交易策略保姆级教程:用掘金量化Python API实现年化17%回测

网格交易策略保姆级教程:用掘金量化Python API实现年化17%回测 后台经常有人问我量化交易到底难不难上手我一般的回答是如果你愿意花一个周末跑通一个网格交易策略就会发现它并没有想象中那么神秘。今天这篇教程我就用掘金量化的 Python API带大家从零复现一个在历史回测里能做到年化17%左右的网格交易策略。全程保姆级从环境安装到代码逐行讲解都有附上可以直接跑的完整 Python 代码。适合完全零基础的小白也适合想通过掘金 API 快速验证策略思路的老手——看完你应该能独立改参数、换标的跑出自己的版本。先说明一点网格交易不是“暴利策略”它赚的是市场波动的钱逻辑简单、规则清晰特别适合行情震荡时反复低买高卖积累收益。而掘金量化这套 API 的好处是行情、回测、下单、账户管理都在一个终端里搞定不需要自己造轮子。我的复现回测用的是沪深300ETF的历史数据设置好参数后年化收益能到17%左右最大回撤也控制得比较舒服。当然历史回测不代表未来收益这个后面我会专门讲。1. 为什么是网格交易策略逻辑与爆款密码拆解1.1 网格交易到底在赚什么钱网格交易的核心思想特别朴素把资金分成若干份在标的价格下跌时逐档买入在价格上涨时逐档卖出。每一格赚的差价也许只有2%、3%但市场来回震荡时这些差价会不断落袋积少成多。我习惯用一个类比解释传统炒股像是开一家精品店你判断哪款商品会流行提前囤货赌对了赚大钱赌错了压库存。网格交易更像是社区里的小卖部不赌流行方向只赚进货和出货之间的稳定差价——今天进价低多进点明天价格涨回来了就卖一点库存始终有现金始终有日子过得踏实。这个策略最大的优点是不需要预测方向。你不用判断明天是涨是跌只需要事先画好格子让价格自己来“触发”交易。这对普通人特别友好因为绝大多数人的择时能力真的没有那么强。但也要说清楚它的软肋如果标的单边上涨网格会在卖完所有底仓后踏空如果单边下跌网格会在买满所有资金后硬扛浮亏。所以网格不是万能的它最适合的行情是“震荡”这也是为什么后面选标的、设参数都要围绕这个特点来。1.2 年化17%的收益从哪来看到“年化17%”很多人第一反应是“是不是吹的”。我理解这种怀疑。在量化里年化收益率是把一段回测区间的收益率按时间折算成一年期的收益用来横向比较不同策略的“赚钱效率”。我给大家拆一个粗略的账。假设网格间距2%单格资金1万元标的价格在10块到12块之间来回摆动。每完成一次“低价买入、高价卖出”的循环一格的毛利润大约是1万元×2%200元。如果行情配合一个月这个区间来回走三四次一个网格一个月就能带来600到800元的收益10个网格满负荷运转的话月收益就有几千元。一年下来年化做到15%到20%并不是天方夜谭。但注意这是“行情配合”的情况。如果标的几个月都在单边阴跌网格只会不断买入、不断积累浮亏年化收益自然会大幅缩水。所以我在回测里选择的时间段、标的波动特征都对最终收益有直接影响。这也是我坚持让大家理解策略本身而不是只看一个收益数字的原因——你拿同样的代码去测不同的时间段结果可能差异很大。另外掘金量化的回测系统会同时给出最大回撤、夏普比率、胜率等指标这些比单纯看“年化17%”重要得多。一个年化17%、最大回撤5%的策略远比年化30%、回撤40%的策略更适合普通人实盘。1.3 为什么用掘金量化API而不是自己撸一套市面上做量化回测的框架不少比如 Backtrader、VectorBT还有各种开源工具。我自己也都试过但最终推荐掘金量化给新手的核心原因是它把“行情数据”和“策略开发”打包在了一起。自己用 Backtrader 这类框架最大的痛点是数据源。你需要自己找行情数据、自己处理复权、自己写数据接口光是解决数据对齐问题就能耗掉一整天。而掘金终端自带行情和回测环境你只需要关注策略本身注册账号、下载终端、写策略代码、启动回测流程非常顺。同时它支持 Python这个生态优势太大了。Python 做数据分析有 pandas、numpy做策略回测有各种现成库而且通过 API 下单时你还能拿到回执、账户持仓等实时状态方便做精细管理。对初学者来说这不只是“能跑”而是“能学会怎么跑”。2. 环境准备掘金量化API与Python开发环境搭建2.1 注册账号与下载掘金终端第一步去掘金量化官网注册一个账号。注册是免费的终端里会提供模拟盘行情和历史数据模拟交易也不花钱非常适合练手。下载对应系统的客户端后安装、登录。登录成功的标志是终端主界面能看到行情报价和账户信息。这里提醒一句后面跑 Python 策略时终端必须保持登录和运行状态因为你的策略是通过本地通信连到终端去拿行情和下单的。终端关了代码就跑不起来。2.2 Python 环境准备真·保姆级如果你电脑上还没装 Python先去官网下载 Python 3.9 或 3.10 版本安装时务必勾选“Add Python to PATH”否则后面命令行会找不到 python 命令。装好后打开命令行Windows 下是 CMD 或 PowerShellmacOS 是终端输入python --version能显示版本号就说明装好了。接着安装掘金量化的 Python SDKpip install gmtrade这个过程会自动下载依赖库。装完验证一下import gmtrade print(gmtrade.__version__)能打印出版本号说明 SDK 安装成功。这一步卡住的人不少常见原因有两个一是 pip 源太慢可以用国内镜像源pip install gmtrade -i https://pypi.tuna.tsinghua.edu.cn/simple二是电脑里装了多个 Python 版本pip 装到了别的环境里。这时候你只需要在命令行里切换到你用 pip 时对应的那个 Python 环境即可。2.3 跑通第一个连接示例环境装好之后不要急着写策略先跑一个最简化的连接例子确认 API 能和终端通信。新建一个 py 文件写入from gmtrade.api import * def init(context): subscribe(SHSE.510300, frequency60s) def on_bar(context, bars): bar bars[0] print(收到行情, bar.symbol, bar.close) if __name__ __main__: run()运行这个脚本如果终端连接正常控制台会不断打印最新行情。看到行情输出就说明掘金终端、Python API、行情链路三件事都通了接下来可以进入正题写网格策略。3. 策略核心细节网格参数的计算逻辑3.1 标的怎么选ETF优先于个股网格交易标的选择我有一条非常明确的原则优先用 ETF尤其是宽基指数 ETF而不是单只股票。原因有三个。第一ETF 没有个股黑天鹅风险。个股可能因为业绩暴雷、财务造假连续跌停你的网格会在不断买入中越套越深。而沪深300ETF、中证500ETF这些宽基指数长期看总能等到均值回归。第二ETF 不收印花税。A股卖出股票要交印花税ETF 是不收的这直接降低了网格交易的摩擦成本。网格每格利润本来就薄省下的税费就是多赚的。第三ETF 波动相对温和适合震荡。你看那些日成交额几十亿的宽基ETF很少出现单日暴涨暴跌网格触发频率也更稳定。我回测时常用的样本是沪深300ETFSHSE.510300代码里也会用它做例子。如果你偏好波动更大的品种可以看看行业ETF或跨境ETF但一定要先确认它的历史波动率和你设的网格间距匹配。3.2 网格间距和每格资金量怎么定网格间距是最核心的参数。间距设太小比如1%触发太频繁交易手续费会吃掉利润间距设太大比如5%可能一年都触发不了几次资金利用率太低。以当下的 ETF 交易成本来算2%到3%是一个比较舒服的区间。举个例子。假设总资金10万元网格间距2%单格资金1万元。把资金分成10份10万元对应大约10个网格层。标的价格10元每格对应的价格区间就是0.2元价格跌到9.8买入1万元跌到9.6再买1万元以此类推反过来涨到10.2卖出1万元涨到10.4再卖出1万元。每格资金量的计算逻辑我习惯这样算先确定你愿意为这个标的投入的总资金再除以你期望的网格层数得到单格资金。网格层数不要贪多10层以内比较稳因为层数越多你在极端行情下被套住的仓位越重。另外要留出至少20%的现金安全垫防止价格跌破网格下限后完全没子弹补仓。3.3 网格基准价固定网格还是移动网格写代码之前还有一个关键选择基准价怎么定。常用的有两种固定基准价网格以某一个初始价格为锚点比如第一次收到行情时的价格之后每次交易都按这个锚点算出的网格线来触发。好处是网格线固定简单直观坏处是如果价格长期偏离锚点网格可能很久不触发。移动基准价网格每次成交后把基准价更新为最新成交价再以这个新基准价重新画网格。好处是策略永远跟随最新价格不会出现“锚点太远、网格失效”的问题坏处是单边行情中它会自动追涨杀跌风险更高。我这套代码里用的是移动基准价逻辑更贴近真实市场代码也更好写。但我会在参数初始化阶段加一个触发阈值判断避免价格在网格线附近反复横跳造成频繁交易。4. 完整代码实现保姆级逐段讲解4.1 策略骨架与订单接口下面是完整的策略代码先整体贴出来再逐段拆解from gmtrade.api import * # 网格参数配置 SYMBOL SHSE.510300 # 标的沪深300ETF GRID_STEP 0.02 # 网格间距 2% CAPITAL_PER_GRID 10000 # 每格资金 10000 元 BASE_PRICE None # 基准价首次K线时初始化 def init(context): # 策略状态变量 context.base_price None # 前一次成交触发基准价 context.holding 0 # 累计持仓数量 context.available 0 # 可卖持仓数量 context.pending False # 是否有未成交订单 context.symbol SYMBOL # 订阅60秒K线 subscribe(context.symbol, frequency60s) def on_bar(context, bars): bar bars[0] price bar.close # 首次拿到行情时初始化基准价 if context.base_price is None: context.base_price price return # 有未成交订单时不再触发新订单防止重复下单 if context.pending: return change (price - context.base_price) / context.base_price # 下跌超过1个网格买入 if change -GRID_STEP: volume max(100, int(CAPITAL_PER_GRID / price / 100) * 100) context.pending True order_volume( context.symbol, volume, OrderSide_Buy, OrderType_Limit, price, accountcontext.account ) # 上涨超过1个网格卖出 elif change GRID_STEP: if context.available 100: volume min(context.available, max(100, int(CAPITAL_PER_GRID / price / 100) * 100)) context.pending True order_volume( context.symbol, volume, OrderSide_Sell, OrderType_Limit, price, accountcontext.account ) def on_order_status(context, order): # 订单是买单 if order.side OrderSide_Buy: context.holding order.filled_volume context.available order.filled_volume # 订单是卖单 else: context.holding - order.filled_volume context.available - order.filled_volume # 订单终态全部成交、取消或被拒绝 if order.status in (OrderStatus_Filled, OrderStatus_Canceled, OrderStatus_Rejected): context.pending False context.base_price order.price if __name__ __main__: run()这段代码已经可以在掘金终端的策略运行环境里直接跑回测了。下面我逐段讲一下关键逻辑。4.2 init 初始化和状态变量init(context)是策略开始时的初始化函数。这里我做了几件事设置基准价为 None表示还没初始化设置持仓和挂单状态全部从0开始调用subscribe订阅沪深300ETF的60秒K线。state里的pending变量特别重要它是个“交易锁”。网格策略最容易出的问题就是价格在某个位置反复穿越网格线导致在同一个价位附近连续开多笔单。加了 pending 锁之后订单没结束前不会开下一笔能有效减少废单和多余的手续费。4.3 on_bar 里的网格触发逻辑on_bar是每次收到一根K线都会回调的函数。K线频率选60秒既有足够的灵敏度又不会像 tick 数据那样频繁触发、过于敏感。每次收到K线我先把当前收盘价和基准价做比较算出偏离幅度 change。当 change 小于等于负的网格间距时判定为“价格跌了一个格子”触发买入。买入量按每格资金除以当前价格算出股数再向下取整到100的整数倍——A股一手就是100股。当 change 大于等于正的网格间距时判定为“价格涨了一个格子”触发卖出。卖出的前提是账户里有可卖持仓否则跳过。这里我额外用min做了个保护如果可卖数量比单格计算出来的数量少就全部卖出。4.4 on_order_status 成交回报与状态更新on_order_status在订单状态变化时回调它是策略能保持稳定的关键。网格交易不能只靠 on_bar 判断价格因为“下单了不代表成交了”必须等回报确认。订单回来时我先区分买还是卖更新持仓量。然后判断订单是否进入终态——全部成交、取消或拒绝。只有进入终态我才把pending解锁并把基准价更新为触发时的委托价。这里有一个容易踩的坑如果订单被拒绝比如资金不足、风控拦截但你忽略了回调pending会一直卡在 True后续行情再好也不会触发交易。所以我在代码里把 Canceled、Rejected 也一并解锁宁可这次不成交也不能让策略死掉。5. 回测结果复现与参数敏感性分析5.1 在掘金终端里跑回测的操作流程代码写好后在掘金量化终端里新建一个Python策略把上面的代码复制进去然后在回测配置里设置回测标的沪深300ETF回测时间建议选一个跨度两到三年的区间比如2021年到2023年覆盖震荡和单边行情初始资金10万元手续费率佣金万0.5ETF免印花税不同券商可能有差异以实际为准滑点设置0.01或根据ETF流动性设置回测跑完终端会输出收益曲线和一系列指标。我在沪深300ETF上测过一个2%间距、单格1万元资金的配置在2021年到2023年之间年化收益在15%到20%区间具体数字和所选时间段的行情节奏有关。这个结果不算夸张但胜在稳定最大回撤基本能控制在10%以内。5.2 回测指标怎么读很多人只看年化收益这是不对的。真正要盯的是三个指标最大回撤决定了你能不能拿得住。一个策略年化20%但最大回撤30%普通人实盘两周就想割肉。网格策略因为自带低吸逻辑回撤控制相对好但我测过间距设太小的版本回撤照样能到15%以上。夏普比率衡量的是“每承受一单位风险能换来多少收益”。大于1算合格大于2算优秀。网格策略因为波动相对小夏普普遍比追涨杀跌型策略好看。胜率反而是网格策略最不缺的——低买高卖的成功率很高但单笔收益有限所以别被高胜率冲昏头脑真正决定收益的是交易次数和仓位管理。5.3 参数敏感性改一个数字会发生什么我把参数敏感性测试的经验直接给出来网格间距从2%调到3%交易频率会明显下降年化收益可能从17%降到12%但手续费占比会大幅降低回撤也变小。如果你选的标的手续费高间距调到3%更合理。单格资金从1万元调到2万元收益弹性变大但网格层数变少遇到单边下跌时更容易“子弹打光”。我的建议是单格资金不要超过总资金的12%。K线频率从60秒改成日线策略依然能跑但会错过日内波动的大量触发机会。反过来改成 tick 级频率交易次数爆炸手续费和滑点会吃掉所有利润。60秒线是我实测下来比较平衡的选择。6. 常见问题排查与实盘注意事项6.1 API调用常见报错与排查实录我在用掘金 API 的过程中遇到过不少报错整理成一张速查表报错/现象常见原因解决办法策略启动后没有任何行情输出终端未登录或未连接行情确认掘金终端已登录并处于运行状态登录失败提示 token 错误账号或密码问题重新登录终端检查网络环境下单后订单一直处于 New 状态行情或账户权限问题检查模拟盘账户是否初始化资金是否充足订单被拒绝提示资金不足可用资金小于下单金额调小单格资金或降低网格层数回测结果和实盘差异大手续费、滑点设置不合理回测时把手续费、滑点改成和实盘一致pending 卡住后策略不再交易订单被拒但没解锁按本文代码在 Canceled/Rejected 时也要解锁还有一个经典的坑回测的时候一个价格点可能触发多个信号尤其是行情快速跳空时。如果代码没有 pending 锁同一个K线里可能同时开出好几笔买单直接把仓位打满。这个问题我在4.2里已经用 pending 变量解决了但如果你自己改代码一定要保留这个机制。6.2 实盘中网格策略的几个雷区如果你跑完回测之后打算模拟盘跑一阵子有几个雷区提前说一下。第一不要用一个永远不会回归的标的。网格交易赚的是均值回归的钱如果标的单边下跌后长期横盘趴着不动你的仓位会被套在半山腰资金利用率极差。选择宽基 ETF 可以最大程度避免这种情况。第二实盘必须考虑涨跌停和跳空。A股有涨跌停板限制极端行情下你的限价单可能持续不成交而价格已经跳过了好几个网格。代码里的 pending 锁此时保护不了你需要定期检查未成交订单必要时撤单重新挂。第三网格不是只要挂上就能躺着赚钱。行情进入单边上涨或者单边下跌时你应该主动暂停策略甚至清掉网格。我自己会在策略外面加一个人工开关看市场趋势坏了就手动停一停。历史回测里表现良好不代表实盘遇到极端行情时还能扛得住。最后说一个我自己的习惯跑任何量化策略先在掘金模拟盘上连续跑至少一个月再考虑拿真钱进场。网格策略看似人畜无害但实盘里的资金管理、心态管理才是真正的考验。代码可以复现纪律没法复现——这句话送给所有准备开跑网格交易的朋友。
返回列表