第28章 基差交易系统自动化:自动化交易接口开发、风控规则引擎、自动化止损执行、系统故障切换机制
做基差交易这些年,我越来越觉得——人盯盘的时代过去了。
你想想看,基差波动就那么几个点,手动下单慢半拍,利润就没了。更别说风控了,人工止损?我见过太多人犹豫一下,亏损就翻倍了。
所以,系统自动化不是选择题,是必答题。
这一章,我把这些年搭建自动化系统的经验拆开来讲。四个核心模块:交易接口、规则引擎、止损执行、故障切换。咱们一个一个过。
28.1 自动化交易接口开发
接口开发,说白了就是让系统能自己下单。
我个人习惯用C++写核心交易引擎,Python做策略层。为什么?C++快,Python灵活。
先看一个简单的期货交易接口封装示例:
// CTP交易接口封装(简化版)
class CtpTrader {
public:
// 登录
int Login(const string& brokerId, const string& userId,
const string& password) {
// 我遇到过登录超时的问题,后来加了重试机制
int retry = 3;
while (retry-- > 0) {
int result = m_pUserApi->ReqUserLogin(req, 0);
if (result == 0) return 0;
Sleep(100);
}
return -1;
}
// 下单
int InsertOrder(const OrderField& order) {
// 这里要注意:价格精度检查
if (order.LimitPrice <= 0) {
Log("价格异常,拒绝下单");
return -1;
}
return m_pUserApi->ReqOrderInsert(&order, 0);
}
// 撤单
int CancelOrder(const string& orderRef) {
return m_pUserApi->ReqOrderAction(&action, 0);
}
};
嗯,这里要注意几个坑:
- 行情延迟:我实测过,CTP行情到本地平均延迟2-5ms。做高频套利的话,这个延迟会吃掉利润
- 订单状态机:下单后不是马上成交的。要维护一个状态机:已报、部成、全成、已撤
- 重连机制:交易接口断开了怎么办?我建议用心跳检测+自动重连
28.2 风控规则引擎
规则引擎,就是给系统装个大脑。什么单子能下,什么单子不能下,它说了算。
我设计规则引擎时,用了三层架构:
- 基础规则层:资金检查、持仓限制、涨跌停检查
- 策略规则层:基差阈值、套利比例、敞口限制
- 应急规则层:异常波动、连续亏损、系统故障
看一个规则引擎的核心逻辑:
class RiskRuleEngine {
public:
bool CheckOrder(const OrderField& order) {
// 规则1:资金检查
if (!CheckCapital(order)) {
Log("资金不足,拒绝下单");
return false;
}
// 规则2:持仓限制
if (!CheckPositionLimit(order)) {
Log("超仓限制,拒绝下单");
return false;
}
// 规则3:基差阈值检查
if (!CheckBasisSpread(order)) {
Log("基差超出阈值,拒绝下单");
return false;
}
// 规则4:涨跌停检查
if (!CheckPriceLimit(order)) {
Log("涨跌停附近,拒绝下单");
return false;
}
return true;
}
private:
bool CheckBasisSpread(const OrderField& order) {
// 计算当前基差
double basis = GetCurrentBasis(order.InstrumentID);
// 基差必须在[-50, 50]区间内
return (basis >= -50 && basis <= 50);
}
};
为什么会这样设计?
因为规则要有优先级。基础规则是底线,不能破。策略规则是战术,可以调整。应急规则是保险,平时不触发,触发就停盘。
28.3 自动化止损执行
止损,是风控的最后一道防线。
我见过太多人,止损单设了,但没执行。为什么?因为系统卡了、网络断了、或者人犹豫了。
自动化止损,就是要解决这个问题。
我的止损执行策略分三级:
| 级别 | 触发条件 | 执行动作 | 响应时间 |
|---|---|---|---|
| 一级止损 | 基差偏离阈值 | 自动平仓 | < 100ms |
| 二级止损 | 连续亏损次数 | 暂停交易+通知 | < 1s |
| 三级止损 | 系统异常 | 全部平仓+切换 | < 5s |
看代码实现:
class AutoStopLoss {
public:
void MonitorAndExecute() {
while (m_running) {
// 检查每个持仓的止损条件
for (auto& pos : m_positions) {
double currentBasis = GetBasis(pos.InstrumentID);
double stopLossLevel = pos.StopLossLevel;
// 一级止损:基差突破
if (abs(currentBasis) > stopLossLevel) {
ExecuteStopLoss(pos, LEVEL_1);
}
// 二级止损:连续亏损
if (pos.ConsecutiveLosses >= 3) {
ExecuteStopLoss(pos, LEVEL_2);
}
}
// 每10ms检查一次
Sleep(10);
}
}
private:
void ExecuteStopLoss(const Position& pos, int level) {
// 生成止损单
OrderField order;
order.InstrumentID = pos.InstrumentID;
order.Direction = (pos.Direction == LONG) ? SELL : BUY;
order.Volume = pos.Volume;
order.OrderType = MARKET_ORDER; // 市价单,确保成交
// 发送止损单
m_trader->InsertOrder(order);
// 记录日志
Log("止损执行: %s, 级别: %d, 数量: %d",
pos.InstrumentID.c_str(), level, pos.Volume);
}
};
28.4 系统故障切换机制
系统总会出问题。服务器宕机、网络中断、交易所故障……
故障切换,就是让系统在出问题时还能继续跑。
我设计的是"主备双活"架构:
// 故障切换核心逻辑
class FailoverManager {
public:
void Start() {
// 启动主节点
m_primary.Start();
// 启动备节点(热备模式)
m_backup.Start();
m_backup.SyncState(m_primary.GetState());
// 开始监控
StartMonitor();
}
private:
void StartMonitor() {
while (true) {
// 检查主节点心跳
if (!m_primary.IsAlive()) {
Log("主节点宕机,开始切换");
// 1. 冻结主节点
m_primary.Freeze();
// 2. 激活备节点
m_backup.Activate();
// 3. 切换交易接口
m_trader.SwitchTo(m_backup);
// 4. 恢复交易
m_backup.ResumeTrading();
Log("切换完成,耗时: %dms", GetElapsedTime());
}
Sleep(100); // 每100ms检查一次
}
}
};
切换流程我总结为四步:
- 检测:心跳超时3次,判定为故障
- 冻结:停止主节点所有操作,防止数据混乱
- 激活:备节点接管,加载最新状态
- 恢复:重新连接交易所,恢复交易
另外,别忘了数据同步。主节点和备节点之间,要实时同步持仓、订单、资金等信息。我用的方法是"增量同步+全量校验"——每笔交易实时同步,每5分钟做一次全量校验。
知识体系总览
下面这张图,把整个自动化系统的架构串起来了:
这套架构,我用了三年。从最开始的手动交易,到半自动化,再到全自动化。每一步都踩过坑,但每一步都值得。
最后说一句:系统再自动化,也要有人盯着。我每周都会做一次人工巡检,检查日志、核对数据、测试切换。自动化是工具,不是甩手掌柜。
公众号:蓝海资料掘金营,微信deep3321