第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。做高频套利的话,这个延迟会吃掉利润
  • 订单状态机:下单后不是马上成交的。要维护一个状态机:已报、部成、全成、已撤
  • 重连机制:交易接口断开了怎么办?我建议用心跳检测+自动重连
我的经验:接口开发完成后,一定要做压力测试。我曾经在实盘前用模拟环境发了10万笔订单,结果发现内存泄漏了。还好发现了,不然实盘就炸了。

28.2 风控规则引擎

规则引擎,就是给系统装个大脑。什么单子能下,什么单子不能下,它说了算。

我设计规则引擎时,用了三层架构:

  1. 基础规则层:资金检查、持仓限制、涨跌停检查
  2. 策略规则层:基差阈值、套利比例、敞口限制
  3. 应急规则层:异常波动、连续亏损、系统故障

看一个规则引擎的核心逻辑:

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);
    }
};

为什么会这样设计?

因为规则要有优先级。基础规则是底线,不能破。策略规则是战术,可以调整。应急规则是保险,平时不触发,触发就停盘。

避坑指南:我曾经把规则写得太死。有一次基差突然扩大,系统直接拒绝所有交易。结果呢?错过了最好的套利机会。后来我加了"规则熔断"机制——连续触发3次规则后,自动降级为人工审核。

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);
    }
};
关键点:止损单一定要用市价单。限价单可能成交不了,那就白设了。我吃过这个亏,一次基差瞬间扩大,限价单没成交,亏损从5万变成了20万。

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检查一次
        }
    }
};

切换流程我总结为四步:

  1. 检测:心跳超时3次,判定为故障
  2. 冻结:停止主节点所有操作,防止数据混乱
  3. 激活:备节点接管,加载最新状态
  4. 恢复:重新连接交易所,恢复交易
注意:切换时间要控制在5秒以内。超过10秒,行情可能已经变了,基差可能已经偏离了。我实测过,从检测到切换完成,平均耗时2.3秒。

另外,别忘了数据同步。主节点和备节点之间,要实时同步持仓、订单、资金等信息。我用的方法是"增量同步+全量校验"——每笔交易实时同步,每5分钟做一次全量校验。

知识体系总览

下面这张图,把整个自动化系统的架构串起来了:

基差交易自动化系统架构 自动化交易接口 CTP/易盛/飞马 行情订阅 订单管理 重连机制 风控规则引擎 基础规则 策略规则 应急规则 规则熔断 资金/持仓/涨跌停 基差/套利/敞口 异常/亏损/故障 自动化止损执行 一级止损(基差偏离) 二级止损(连续亏损) 三级止损(系统异常) 系统故障切换机制(主备双活)

这套架构,我用了三年。从最开始的手动交易,到半自动化,再到全自动化。每一步都踩过坑,但每一步都值得。

最后说一句:系统再自动化,也要有人盯着。我每周都会做一次人工巡检,检查日志、核对数据、测试切换。自动化是工具,不是甩手掌柜。


公众号:蓝海资料掘金营,微信deep3321