
做市商策略跑了大半年账户里BTC现货底仓最多的时候有几百个币。平时还好行情一波动我第一反应是打开合约面板手动开空单做对冲。直到某个凌晨行情一分钟内抽了4%我手一抖方向点反了——本想开空结果点成了开多。那一瞬间爆仓线离我只有几个点我盯着屏幕整个人都是麻的。那次之后我花了三周时间把整套手动对冲流程重写成了一套自动对冲系统代号AutoHedge。上线至今跑了快五个月经历了两次极端行情、三次交易所API故障、一次云服务器秒级宕机整体没出过重大事故。这篇文章把我这五个月的架构设计、踩坑记录、参数调优过程和上线运营经验全部摊开讲送给准备自研对冲系统、或者正在犹豫要不要把手工操作自动化的人。1. 为什么我决定做AutoHedge手动对冲的痛与自动化对冲的切入点1.1 一个让我熬夜到凌晨三点的对冲事故先说说那晚的具体情况。当时我的现货账户持有约50BTC成本均价大概在28000附近。那天晚上行情从29500开始急跌15分钟内跌到28400我判断短期还要往下走准备在合约账户开空单做对冲。问题出在哪第一我开的是逐仓保证金留得不多点单的时候心里慌把数量栏手滑多打了一个0第二方向选错原本该做空页面切到永续合约那个Tab时我下意识点了买入开多。两秒钟后我反应过来但那一口多单已经吃进去账户浮动亏损瞬间扩大。那一夜我做的最正确的一件事是没有继续手动操作去补救而是把单子平掉关掉电脑坐在阳台上吹了半小时冷风。天亮后我决定这类需要极快反应、又极其依赖纪律的操作不应该交给一个凌晨三点精神状态堪忧的人类。这个判断是AutoHedge项目的真正起点。1.2 谁适合自研自动对冲系统如果你想做一套自动对冲先别急着写代码冷静评估一下自己到底属于哪种情况。根据我这段时间的观察适合自研的人群主要有这么几类手里有大量现货底仓又不愿意直接清仓踏空后续行情的囤币型玩家做市商、网格、套利策略的运营者账户里有实时变动的风险敞口需要频繁调整高频参与合约交易但经常因为情绪化操作亏钱需要纪律约束的执行型玩家手里握着多种资产、多个账户手工统计持仓和敞口已经算不过来的组合投资者而如果你只是偶尔持有一点现货一个月交易不了几次那完全没必要自己造这个轮子。交易所自带的套保功能、条件单、止盈止损单已经够用。自动对冲系统的复杂度是实打实的没有一定频率和规模支撑投入产出比不划算。1.3 自动对冲的三条设计底线做AutoHedge之前我先给自己定了三条底线后续所有架构设计都围绕这三条展开第一不丢失订单。系统可以慢可以延迟开仓但绝不能出现“我以为开了单实际没开出去”的情况。每一笔订单的状态必须有持久化记录进程崩溃后可以恢复。第二不踩穿交易所限频。宁可排队等也不去挑战API的请求频率上限。一旦触发限频往往不是被拒绝一次而是短时间内所有请求都被卡住这在行情剧烈波动时是致命的。第三不死循环。系统不能出现“因为对不上账所以反复重试因为反复重试所以更对不上账”的恶性循环。所有重试都必须有次数上限和退避策略超过上限必须停下来报警而不是无脑继续。这三条底线看着简单实际落地时会牵出一堆细节。后面每一章的踩坑记录几乎都能对应到其中一条底线被挑战的场景。2. AutoHedge的核心架构与关键模块拆解2.1 整体设计事件驱动而非定时轮询我在设计AutoHedge时选用的核心范式是事件驱动。原因很简单行情数据本质上是离散事件的连续流——每一笔成交、每一条深度变化、每一次资金费率更新都是一个独立事件。如果采用定时轮询的方式比如每500毫秒抓一次价格、算一次敞口、判断一次要不要下单会带来两个问题一是延迟高错过行情的中间态二是逻辑脆弱容易把系统状态耦合在调度顺序里。AutoHedge的核心组件包含行情接入器、敞口计算引擎、对冲执行器、风控守护进程四大部分。它们之间通过一个本地的消息队列通信。每个模块都是独立的进程模块之间不直接调用函数而是通过事件消息解耦。我用一个生活化的类比来解释这个架构想象你家里装了烟雾报警器、自动喷水系统、燃气阀门和手机通知App。如果设计成“每10秒检查一次有没有火灾”那从起火到发现可能已经过了十秒火势早起来了。事件驱动的方式是烟雾报警器一旦检测到浓度超标立刻推送事件喷水系统马上启动燃气阀门自动关闭手机App同步收到通知——每个模块都是被事件唤醒的而不是被动等待轮询。2.2 行情接入层选型与数据去重策略行情接入层是整个AutoHedge的数据源头我在这里踩的坑最多所以单独拿出来细说。我最终选型用的是交易所官方的WebSocket接口而不是第三方聚合数据源。原因有三个一是官方接口延迟最低这对对冲决策至关重要二是数据格式稳定、文档清晰出问题好排查三是不用担心中间商的稳定性问题——你依赖的第三方一旦挂掉你的对冲系统就瞎了这个风险没必要承担。WebSocket接入后的第一件事是数据清洗这里面最大的坑是重复消息。交易所的WebSocket在断线重连后通常会补推重连期间漏掉的数据这个补推机制会导致同一笔成交被推送多次。如果不对消息做去重敞口计算引擎就会把同一笔成交算两次持仓数据直接错乱。我的去重方案是每笔成交都有唯一的trade_id维护一个固定大小的去重缓存用Redis的SET实现trade_id已经在缓存里就直接丢弃不在就写入并继续处理。缓存容量根据行情频率动态调整BTC永续合约高峰期每秒几十笔成交缓存保留最近5万条消息基本够用。这里有个细节去重缓存不能只判断一次就完事因为交易所在极端情况下会推同一个trade_id但不同Time的重复消息还需要再比对一下时间戳。2.3 敞口计算引擎Delta、Gamma和持仓映射敞口计算引擎负责回答一个问题当前账户的风险敞口到底是多少对AutoHedge来说我关心三个核心指标Delta、Gamma和Vega。Delta衡量价格变动对持仓价值的敏感度。拿最简单的现货合约组合举例持有1BTC现货Delta就是1.0同时开1张BTC永续空单如果每张合约对应0.001BTC那合约的Delta就是-0.001乘以合约张数。净Delta 现货Delta 合约Delta 期权Delta。AutoHedge的核心目标就是让净Delta始终逼近0——也就是所谓的Delta中性。Gamma衡量Delta本身会怎么随价格变化。如果是纯现货合约组合Gamma为0因为现货的Delta永远是1合约的Delta也基本不随价格变化。但如果组合里包含期权Gamma就会非常关键。AutoHedge上线初期我只做现货合约的对冲Gamma直接置0跳过后面加了期权头寸后才把Gamma计算接进来。持仓映射这块也容易出问题。不同交易所的合约面值不一样有的1张0.001BTC有的1张0.01BTC还有的1张1BTC。如果内部统一用“张”来记录换一个交易对或者换一个交易所数量换算错了会出大事。我的做法是内部一律以币本位为唯一计量单位不管交易所返回的是多少张先乘以面值换算成BTC再参与敞口计算。2.4 对冲执行模块下单、撤单、重试的优先级管理计算公式写清楚之后最难的部分是对冲执行。敞口计算引擎每秒钟会产出几十次“当前需要调整敞口”的信号但不可能每次都直接下单——那样手续费会把你吃干净还会被交易所限频。所以执行模块的关键在于什么时候动、动多少、按什么顺序动。AutoHedge的默认执行策略是维护一个目标敞口区间当净Delta偏离0超过阈值时触发对冲触发后不是一次性把偏离全部打回去而是分3到5批下单每批之间间隔几百毫秒观察市场价格有没有因为自己的单子而移动。这里要特别说明撤单和重试的优先级管理。我的执行队列里不同消息被赋予不同的动态优先级消息类型默认优先级说明持仓偏离超过三倍阈值P0必须立即下市价单哪怕多付点手续费普通对冲触发P1按计划分批下限价单订单超时未成交P2撤单后重新挂单最多重试3次资金费率结算前调整P3在结算前预留缓冲时间调整仓位一个容易被忽略的细节撤单和下单的API调用频率权重不同。撤单请求的限频额度比下单更严格所以程序里撤单的尝试次数必须限制不能无脑循环撤单-重挂否则触发限频后想买买不进、想卖卖不出。2.5 风控熔断什么情况下必须停下来AutoHedge的熔断机制设计遵循一个原则安全优先宁可错杀不可放过。系统的熔断分两级一级熔断是硬熔断触发条件包括持仓偏离超过设定极值比如5倍阈值、连续5次下单操作失败、与交易所的WebSocket连接中断超过10秒、系统检测到账号权益相对于上一分钟下跌超过2%。硬熔断一触发整个对冲执行器立刻暂停所有挂单全部撤销保留现货底仓不动然后发送P0级别告警到手机和邮件。二级熔断是软熔断触发条件相对宽松某次下单的滑点超过预设最大值、某交易对的对冲频率过高触发了限频预警、系统内存或CPU占用率持续超过80%。软熔断不会停止整个系统而是自动切换到更保守的参数——扩大触发阈值、减少单批下单数量、降低下单频率。熔断之后的恢复逻辑也很重要不能人为干预一下就直接恢复运行。AutoHedge的恢复流程是先检查当前净Delta是否已经回到安全区间再检查交易所API连接是否稳定最后检查系统自身状态是否正常。三个条件全部满足后先跑5分钟“观察模式”——只计算敞口不下单确认系统稳定后才真正恢复自动交易。3. 实测中的翻车现场与排查链路3.1 问题一对冲延迟导致滑点吞噬利润AutoHedge上线第一周就遇到了滑点问题。当时我的敞口阈值设得比较紧只要净Delta偏离0.5个BTC就触发对冲。某天半夜行情突然单边下挫系统在0.3秒内就发出了对冲信号但执行完成后我拉了对账数据发现这一笔对冲的成交均价距离信号发出时的市场中间价差了将近80美元。排查过程是这样的我先看了行情接入层的日志发现价格数据从交易所推送到达AutoHedge的时间戳到我本地系统打上接收时间戳中间差了大概350毫秒。这个延迟来自两段——交易所服务器到云服务器的网络传输以及WebSocket库内部的消息队列排队。然后我又对比了下单链路发现从触发信号到订单实际提交到交易所中间经历了行情转换、敞口计算、策略判断、下单构造、签名、发送六个环节合计延迟约450毫秒。这两个延迟叠在一起等我的限价单挂上去了市场价格早就跑远了。修复方案分两步。第一把行情数据的处理链路由同步改为异步流水线每个环节独立处理上一环节的结果减少相互等待第二触发对冲时不再直接挂限价单而是先按当前市场中间价加减一个缓冲价位提交一个“侦察单”——如果侦察单能快速成交说明市场流动性足够继续按计划加量如果侦察单长期未成交说明行情可能正在快速移动要立即转换成市价单模式。这个小改进把平均滑点从80美元降到了15美元左右。3.2 问题二API限频触发连锁撤单第二次大事故发生在一次消息推送风暴期间。那天有重大行情事件整个市场的交易量暴增我的WebSocket订阅行情流和REST API下单共用同一个API Key的限频额度。现象是行情流推送频率暴增WebSocket连接占掉了大部分限频配额导致执行器发出的下单请求频繁返回限频错误。我的第一版代码里限频错误会被当作“临时错误”进入重试逻辑于是下单模块疯狂重试进一步加剧了限频形成了一个自我强化的恶性循环。更糟的是有一笔需要撤单重挂的订单撤单请求也被限频卡住了导致旧订单还挂在账面上新的对冲单又进来了持仓偏离一度飙到设定阈值的四倍。排查的过程中我在日志里看到了一段典型的“雪崩前兆”——同一秒内有超过30条带限频率的报错。我立刻手动触发了一级熔断整个系统暂停了三分钟等限频窗口缓和后才恢复。这事之后我做了一个重要改动把行情订阅和交易下单拆分成两个不同的API Key各自拥有独立的限频额度。同时在程序里对限频错误单独处理——一旦检测到限频立即停止当前交易对的全部下单行为进入冷却期而不是普通重试。另外所有错误重试都加了指数退避逻辑第一次等待500毫秒第二次等待1秒第三次等待2秒最多重试三次三次全部失败就触发告警交给人工处理。3.3 问题三盈亏数据对不上——精度与口径的坑第三个印象深刻的问题是数据对不上账。上线两周后我在做日对账时发现AutoHedge记录的已实现盈亏和交易所账户里的实际资金变化差了大约200美元。这个数说大不大但如果不查清楚迟早会捅出更大的篓子。排查链路从日志开始。我先核对每一笔对冲单的成交记录发现系统记录的每张合约成交价格、数量和实际订单详情完全吻合说明下单和成交记录没有丢失。接着我检查资金费率记录发现这200美元的差额恰好涵盖了这几天的资金费率收支。问题找到了AutoHedge的已实现盈亏模块只统计了开平仓的价差收益完全没把资金费率的收支算进去。这暴露了一个设计上的盲区——对于永续合约来说资金费率是持仓成本里不可忽视的一部分。AutoHedge对冲持仓往往长达几天资金费率的累积可能占到总收益的30%以上。如果不计入盈亏统计你做策略回测、做收益归因时得到的结论都会有偏差。修复思路很简单把资金费率收支并入已实现盈亏的统计口径。但这里也埋了一个坑——资金费率是由交易所统一结算的不是逐笔计算的。做日对账时不能自己估算资金费率必须直接读取交易所账户的资金流水记录以它为准进行校准。从此之后AutoHedge的日出账报表里增加了“资金费率收支”一栏日对账的误差控制在0.5美元以内。4. 参数调优与回测AutoHedge能不能稳吃的关键4.1 对冲阈值怎么定边际成本的思维AutoHedge的核心参数是“净Delta偏离多少才触发对冲”。这个阈值设太紧系统会频繁交易手续费和滑点的磨损会把利润吃掉设太松敞口暴露过大行情一旦剧烈波动对冲就成了马后炮。我建议用边际成本的思路来推导这个阈值。你的对冲操作有三项固定成本开仓手续费、平仓手续费和平均滑点。以某交易所永续合约为例taker手续费率是0.05%那么一买一卖的总手续费是0.1%。假设你平均滑点约0.02%那么一次完整对冲操作的总成本大约是0.12%。这时候就能算账了如果你把对冲阈值设为0.5BTC的Delta偏离意味着你有0.5BTC的裸敞口在场。假设BTC价格波动率为每日2%那么这0.5BTC裸敞口一天可能产生的最大期望亏损大约等于0.5BTC乘以2%——如果币价是30000美元就是300美元。而触发一次对冲的成本是多少如果你一次要对冲的仓位是0.5BTC按0.12%的成本算大约是18美元。明显是触发对冲更划算。实际操作中我不会只用公式算一次就完事。AutoHedge支持动态调整阈值默认情况下阈值会根据近30分钟的已实现波动率自动上下浮动——波动率高时自动收紧波动率低时自动放宽。这个动态参数让系统在震荡市里少磨损在趋势市里也能及时反应。4.2 手续费模型对策略频率的影响手续费是自动对冲策略里最容易被低估的一个变量但它是决定策略生死的关键。很多人回测时只按固定费率算但真实交易中手续费跟你的交易量等级、是否使用平台币抵扣、VIP等级都有关。AutoHedge在回测时把手续费拆成了三个场景保守场景全额费率、中性场景八折费率、乐观场景五折费率。策略在这三个场景下都能跑出正收益才真正值得上实盘。我举个例子说明手续费影响有多大。假设你设了一个非常紧的阈值每天触发20次对冲每次对冲一买一卖共0.1%的手续费那每天手续费就是0.1%乘以20次——足足2%的本金损耗。但如果你把阈值放宽到每天只触发3次手续费损耗就是0.3%。两者的手续费差距是巨大的但风险敞口只多暴露一点点。AutoHedge在参数优化时的目标函数不是“最小化最终敞口”而是“在手续费损耗和风险暴露之间取得最优平衡”。在实盘配置里我最终给AutoHedge设的默认参数是正常行情下每天触发4到6次对冲极端行情下可能会在几分钟内连续触发两三次但当天总触发次数设有上限默认是20次超过之后当天不再自动交易只报警。4.3 回测框架的冷启动别被历史数据骗了回测是AutoHedge开发过程中比较难熬的部分因为这类策略的收益主要来自“规避极端损失”而非“获取超额收益”所以在普通行情下回测曲线看起来平平无奇有些人因此误判策略没用。我在回测框架里特别强调三点。第一数据质量。回测用的行情数据必须包含每一笔成交而不是只有K线。K线级别的回测会漏掉滑点和盘口深度的变化导致结果过于理想。第二手续费和资金费率的建模。资金费率在回测中尤其容易被忽略但永续合约的资金费率是影响总收益的核心变量之一。你可以在历史数据里直接调用交易所公布的资金费率记录把它作为持仓期间的成本项。第三也是最重要的一点回测必须包含至少一次完整的极端行情。如果在过去一年的数据里没有经历过单日跌超10%的情形你要人为加入一个压力测试场景假设BTC价格在5分钟内暴跌15%期间流动性枯竭、盘口深度下降70%AutoHedge还能不能把净Delta控制住我的回测框架里专门内置了一个“黑天鹅模拟器”可以自定义暴跌的斜率、深度和恢复时间用来测试系统在最恶劣环境下的表现。5. 上线后的运营经验与易忽视的细节5.1 监控告警分级把精力花在刀刃上AutoHedge上线后我建立了一套监控告警体系。这套体系的核心是分级管理不同级别的告警对应不同的处理力度和响应时间避免让操作者被海量低级别消息刷屏结果真正重要的告警反而被淹没。P0级系统宕机、持仓偏离超过极值、API密钥失效、资金费率结算异常。这类告警必须立即响应通过电话、短信、邮件同步强推每5分钟重发一次直到确认。P1级单笔滑点超过预期、某个交易对连续3次下单失败、熔断被触发。需要操作者在10分钟内介入关注。P2级行情源延迟超过阈值、数据库查询变慢、某个参数偏离正常范围。记录到日报里次日处理即可。这里有个经验告警不是越灵敏越好。初期我把阈值设太灵敏结果一天收到几十条P1告警真正有问题时反而麻木了。后来把P1的标准从“某次滑点超过预期”改成“连续3次滑点超过预期”误报率大幅下降。阈值调优的原则是宁可让告警少一点也要保证每条告警都是真的值得处理的。5.2 日志设计审计日志是排障的救命稻草经历了几次线上问题后我意识到日志设计必须提前规划不能等到出事了再补。AutoHedge的日志体系分三层第一层是事件日志记录系统内部每一个关键决策。比如为什么这次触发了对冲阈值是多少当前净Delta是多少下单的期望成交均价是多少这些信息帮助你事后复盘每一次交易决策是否合理。第二层是审计日志记录所有对外部系统的调用。每一笔下单请求的原始参数、交易所返回的响应、订单状态的变化时间线、撤单的原因全部要记录下来。这层日志的目的是如果某一笔订单出了问题你能完整还原从发起到最终成交的全过程查清楚到底是哪一环出了问题。第三层是性能日志记录各模块的处理耗时、内存占用、API调用频率等系统级指标。这层日志服务于容量规划和性能优化通过观察性能日志你能提前发现潜在瓶颈。审计日志尤其重要。有一次AutoHedge连续开了两笔方向相反的单而且间隔只有200毫秒要不是审计日志完整记录了整个过程根本不可能定位到是执行模块的异步任务竞态条件导致的问题。5.3 资金费率套利AutoHedge的意外收获AutoHedge跑了一段时间后我发现一个额外的好处由于系统本身始终保持Delta中性只需在资金费率为正时增加空头合约、资金费率为负时增加多头合约就能在不承担方向风险的前提下赚取资金费率的稳定收益。具体操作是这样的当某个交易所的永续合约资金费率是正数比如每8小时0.05%这意味着多头要向空头支付资金费。一个Delta中性的对冲账户如果选择持有更多的空头合约就能在保持中性的同时每个结算周期收取资金费。只要年化资金费率超过手续费磨损这笔钱就是纯增量。AutoHedge的资金费率套利模块会自动监控各交易所的资金费率动态调整空头和多头合约的比例在不改变净Delta的前提下优化资金费收入。这一段想说明什么自动对冲系统本质上是一个基础设施它不只可以做对冲还可以利用永续合约的定价机制做额外的收益增强。在搭建AutoHedge的过程里我把“写代码实现一个对冲策略”想简单了它更多的是在搭建一整套围绕Delta中性的资金管理系统交易本身只是其中一环。AutoHedge上线运行到现在我最大的体会反而是克制。在合约市场让人觉得踏实的从来不是某一次操作特别精准而是无论行情怎么走账户始终在自己的预判框架里。真正让我下定决心做自动化的是那次凌晨三点的手动错误操作但让我坚持迭代下来的是后面无数个“系统自动处理了而我甚至没察觉”的平静夜晚。如果你也在做同类系统我的建议是先保证熔断逻辑可靠再设计策略逻辑。活得久比赚得快重要得多。