
为什么你的量化策略总在实盘掉链子
很多人写策略回测年化百分之几十,一上实盘就各种幺蛾子。下单没成交、持仓对不上、行情卡半秒、平仓变开仓。根子不在策略逻辑,在量化交易系统跟券商期货公司之间的API规范没吃透。
API规范不是技术文档里那些冷冰冰的字段列表。它是策略程序跟交易通道之间的合同。合同没签好,策略再聪明也白搭。
股票和期货的API长得完全不一样
股票接口通常走券商柜台,期货接口走CTP或者飞马。股票下单字段少,价格类型就限价和市价两种。期货多出投机套保、平今平昨、组合持仓这些花样。

同一个策略跑股票和期货,代码里到处是if else判断品种。规范的做法是抽象一层交易网关,把股票和期货的差异封装在网关内部。策略只调用统一的下单接口,传标准化的订单对象。
class Order:
def __init__(self, symbol, direction, offset, price_type, volume, price=0):
self.symbol = symbol
self.direction = direction # BUY / SELL
self.offset = offset # OPEN / CLOSE / CLOSE_TODAY
self.price_type = price_type
self.volume = volume
self.price = price
class TradingGateway:
def send_order(self, order: Order):
raise NotImplementedError
class StockGateway(TradingGateway):
def send_order(self, order: Order):
# 忽略offset,股票无平今概念
return stock_api.place_order(order.symbol, order.direction, order.volume, order.price)
class FuturesGateway(TradingGateway):
def send_order(self, order: Order):
# 必须传offset和price_type
return futures_api.insert_order(order.symbol, order.direction, order.offset, order.price, order.volume, order.price_type)
股票没有平今平昨,期货有。股票卖出自动扣可卖持仓,期货平仓要指定平昨还是平今。这些差异不封在网关里,策略里全是坑。
订单字段最容易出事的几个地方
价格类型。股票限价单传价格,市价单很多柜台要求价格填0。期货市价单有的交易所不支持,只能用限价单加对手价。API规范里必须明确每个品种支持哪些价格类型。
数量单位。股票是股,期货是手。一手螺纹钢是10吨,一手原油是1000桶。策略发单前必须把数量换算成API要求的单位。发错单位,一手变一股,成交不了还占保证金。
开平标志。股票买入就是开仓,卖出就是平仓。期货买入可能是开多,也可能是平空。卖出可能是开空,也可能是平多。API规范里要定义清楚每个方向跟开平组合的合法取值。
错误处理比下单本身还重要
API返回错误码不能只看成功失败。期货CTP有一堆错误码,比如资金不足、持仓不足、价格超出涨跌停、非交易时段。策略收到错误码要能区分是重试还是放弃。
价格超出涨跌停,重试没用,要改价格。资金不足,重试也没用,要等出金或者减仓。网络超时,可能已经成交了,不能盲目重发。
def handle_order_error(error_code):
if error_code == 'PRICE_OUT_OF_LIMIT':
return 'ADJUST_PRICE'
elif error_code == 'INSUFFICIENT_FUNDS':
return 'WAIT_OR_REDUCE'
elif error_code == 'NETWORK_TIMEOUT':
return 'QUERY_ORDER_STATUS'
else:
return 'RETRY'
规范里要约定,网络超时后先查订单状态,不能直接重发。很多策略亏钱就亏在重复下单上。
限流和幂等,散户最容易忽略
券商和期货公司API都有频率限制。股票接口每秒可能只让发几笔,期货CTP有流控。策略回测时随便发单,实盘一秒钟发一百笔,直接被柜台拉黑。
规范里要定好:每秒钟最多发多少笔,每只股票或者每个合约最多挂多少笔未成交单。策略内部加个令牌桶,发单前先拿令牌。
幂等更关键。网络抖动导致重发,同一个订单号发两次,柜台可能当成两笔单。规范要求每笔订单有唯一客户端订单号,柜台根据这个号去重。策略重发时带同一个号,柜台只认第一笔。
import time
class RateLimiter:
def __init__(self, max_per_sec):
self.max_per_sec = max_per_sec
self.tokens = max_per_sec
self.last_time = time.time()
def acquire(self):
now = time.time()
elapsed = now - self.last_time
self.tokens = min(self.max_per_sec, self.tokens + elapsed * self.max_per_sec)
self.last_time = now
if self.tokens >= 1:
self.tokens -= 1
return True
return False
行情API的规范同样要命
股票行情和期货行情推送频率不一样。股票Level1三秒一笔,期货Tick可能一秒两笔。策略订阅行情时,规范要说明推送频率和字段含义。
期货行情有今开、昨收、昨结、最新价、买一卖一。股票行情有最新价、买卖五档。策略计算指标时用错字段,信号就全歪了。
行情API还要处理断线重连。重连后要重新订阅,并且补上断线期间的数据。规范里要约定补数据的方式,是按时间戳拉取还是让柜台推送。
回测和实盘共用一套API规范
回测时用模拟撮合,实盘用真实柜台。两边的API规范要尽量一致。回测里下的单,字段和实盘一样。这样策略从回测切实盘,不用改代码。
很多量化平台回测和实盘两套接口,策略移植时全是bug。自己搭系统的话,把交易网关做成可替换的,回测网关模拟成交,实盘网关对接柜台。策略只认订单对象和回报事件。
规范落地要写进代码注释和测试用例
API规范不是文档写完就完事。每个字段的取值范围、错误码的处理方式、限流参数,都要写成测试用例。策略发单前跑一遍单元测试,确保订单对象合法。
团队协作时,API规范是策略研究员和开发之间的接口文档。研究员不用管CTP怎么连,开发不用管策略逻辑。双方按订单对象和回报事件对接,效率高很多。
量化交易系统API规范做好了,策略才能专注在信号和仓位上。规范没做好,天天修bug,策略再好也跑不出该有的收益。