实盘运维与策略监控

实盘运维与策略监控的完整实践:从仿真盘到实盘的上线流程与资金递增节奏、策略健康度指标体系、资金曲线与回撤告警设计、盘中异常处置与人工干预、故障切换与高可用架构、日终复盘与收益归因、策略衰减识别与下线决策以及值班与应急预案,回答如何区分正常波动与真实故障。

实盘运维是把策略「养活」的过程。研究和回测解决的是「能不能赚钱」,运维解决的是「能不能持续赚钱、出问题能不能及时发现」。很多团队在策略研究上投入大量精力,却在运维上几乎裸奔,结果是策略明明有效,却因为一次未监控的故障亏掉了几个月的收益。

真正难的地方在于区分「正常波动」和「真实故障」。策略回撤 5% 可能是正常波动,也可能是模型失效的前兆;行情延迟 100 毫秒可能是网络抖动,也可能是通道故障的早期信号。运维系统的价值就是在噪声中识别出真正的异常。

本文按「上线 → 监控 → 告警 → 处置 → 高可用 → 复盘 → 衰减 → 应急」的顺序展开。账务层面的核对在 清结算与对账体系 中讨论,本文聚焦运行期的运维。

目录

  1. 上线流程:从仿真盘到实盘
  2. 灰度与资金递增
  3. 策略健康度监控
  4. 资金曲线与回撤告警
  5. 盘中异常处置
  6. 故障切换与高可用
  7. 日终复盘与归因
  8. 策略衰减与下线决策
  9. 值班与应急预案

1. 上线流程:从仿真盘到实盘

策略上线的四道关卡,每道都有明确的通过标准:

关卡时长通过标准
回测天级样本外年化 > 15%,Sharpe > 1.5
仿真盘20 交易日与回测日收益相关性 > 0.8
小资金实盘1 个月滑点与仿真偏差 < 20%
逐步加仓2 周/档每档观察期无异常

仿真盘(paper trading)不能省。它暴露的问题回测永远覆盖不到:

- 柜台拒单(资金不足、涨跌停、非交易时段)
- 部分成交与撤单竞态
- 行情丢包与重连
- 订单状态机未覆盖的状态
- 报单延迟的真实分布

仿真盘的实现方式是用真实行情驱动真实 OMS,但不下真单(或下模拟单)。它与回测的最大区别是实时性:回测可以加速,仿真盘必须按真实时间跑,因此能暴露所有时序相关的问题。

class PaperTradingOMS(RealOMS):
    def send_order(self, order):
        fill = self.simulator.match(order, self.current_tick)   # 不下真单,本地撮合
        self.on_exec_report(fill)      # 走真实的回报处理路径
        return order.id

2. 灰度与资金递增

策略上线不是「全量开启」,而是「小资金验证 + 逐步加仓」:

第 1 档:10% 目标资金,观察 2 周
第 2 档:25%,观察 2 周
第 3 档:50%,观察 2 周
第 4 档:100%

每一档的观察指标:

def can_promote(stats, target_vol):
    checks = {
        'sharpe':      stats.sharpe > 1.0,              # 风险调整收益达标
        'max_dd':      stats.max_drawdown < 0.10,       # 回撤可控
        'slippage':    stats.slippage_bps < 15,         # 滑点在预期内
        'fill_rate':   stats.fill_rate > 0.95,          # 成交率正常
        'reject_rate': stats.reject_rate < 0.02,        # 拒单率低
    }
    return all(checks.values()), checks

降档的规则必须同样明确:如果实盘回撤超过回测最大回撤的 1.5 倍,自动降到上一档。这个机制比「人工判断」可靠得多,因为人在亏损时容易抱有侥幸心理。

3. 策略健康度监控

策略监控不能只看盈亏,要监控一整组指标:

指标含义异常阈值
信号数量每周期产生的信号数偏离历史均值 ±50%
成交率成交单/报单< 90%
滑点实际成交价 vs 决策价> 20 bp
持仓偏离实际 vs 目标持仓> 5%
行情延迟tick 到达延迟P99 > 500 ms
报单延迟报单到确认P99 > 100 ms
通道状态连接是否正常断连即告警

信号数量是最灵敏的预警指标。如果某天信号数量骤降 80%,可能是数据管道断了、也可能是因子计算出错。它比盈亏更早发现问题,因为盈亏有滞后性。

def check_signal_health(today_count, history):
    mean = np.mean(history[-20:])
    std = np.std(history[-20:])
    z = (today_count - mean) / std if std > 0 else 0
    if abs(z) > 3:
        return f"信号数量异常:今日 {today_count},历史均值 {mean:.0f},z={z:.1f}"
    return None

监控数据的采集与可视化需要一套覆盖指标、日志、链路三者的可观测性栈,且要保证交易时段的采集本身不成为性能瓶颈。

4. 资金曲线与回撤告警

资金曲线是最直观的监控对象,但要区分几个层次:

账户净值 = 总资产(含浮盈浮亏)
已实现净值 = 只含已平仓盈亏(更平滑)
超额净值 = 相对基准的表现(策略真实能力)

回撤告警要分级,并且要基于回测的统计特征而不是拍脑袋:

def drawdown_alert(current_dd, backtest_max_dd):   # 以回测最大回撤为基准
    if current_dd > backtest_max_dd * 2.0:
        return 'CRITICAL'      # 严重偏离,可能模型失效
    if current_dd > backtest_max_dd * 1.5:
        return 'WARNING'       # 显著偏离,降档观察
    if current_dd > backtest_max_dd * 1.2:
        return 'NOTICE'        # 轻微偏离,留意
    return None

回撤告警必须带上下文,否则会淹没在噪声里:

当前回撤:6.2%
回测最大回撤:8.0%(P95 分位 5.1%)
持续天数:8 个交易日
历史相似回撤的平均恢复天数:12 天
当前是否超出 95% 置信区间:否

有了这些上下文,值班人员才能判断是否需要干预。只报一个「回撤 6.2%」的数字,接收者无法决策。

5. 盘中异常处置

盘中异常的处置必须有预案、可执行,不能临场发挥。常见异常与对应动作:

异常现象处置
行情中断长时间无 tick停止开仓,等待恢复
报单超时报单无回报主动查询订单状态
持仓偏离实际与目标差异大暂停策略,人工确认
亏损超限单日亏损触发硬限熔断,人工介入
通道断开连接状态异常切换备用通道
策略异常报单频率暴增立即停止策略

处置动作要分级且可逆:

class IncidentHandler:
    def on_market_data_stale(self, age_ms):
        if age_ms > 30000:
            self.emergency_stop('行情中断超 30 秒')     # 全停
        elif age_ms > 5000:
            self.pause_new_positions('行情延迟超 5 秒') # 只停开仓

    def emergency_stop(self, reason):
        self.cancel_all_orders()      # 撤所有挂单
        self.disable_strategy()       # 停止策略
        self.alert('CRITICAL', reason) # 告警

「停止开仓但允许平仓」是最常用的中间档。它能在行情异常时控制风险,又不至于让持仓失去管理。

6. 故障切换与高可用

交易系统的高可用有两个层次:进程级和通道级。

层次故障切换方式目标 RTO
进程级策略进程崩溃主备进程 + 心跳< 5 秒
通道级报单通道断开主备通道< 10 秒
机房级托管机房故障异地切换分钟级

主备进程的状态同步是关键。备用进程必须实时同步主进程的订单状态,否则切换后会重复下单:

class StandbySync:
    def __init__(self, standby):
        self.standby = standby

    def on_state_change(self, event):
        self.standby.apply(event)   # 每个状态变更都同步到备用进程

    def heartbeat(self):
        self.standby.last_heartbeat = time.time()   # 超时则由备用进程接管

切换的幂等性至关重要:切换后第一件事是查询所有未完成订单的真实状态,而不是直接用本地缓存的状态继续。这与 分布式幂等与可靠性 中的恢复逻辑一致。

切换必须演练。没有演练过的切换流程,在真实故障时大概率会失败(备用进程配置过期、切换脚本路径错误、权限不足)。

7. 日终复盘与归因

日终复盘回答三个问题:赚在哪、亏在哪、与预期差多少。

def daily_review(actual, expected):
    return {
        'pnl_actual':   actual.pnl,
        'pnl_expected': expected.pnl,        # 按模型预期
        'deviation':    actual.pnl - expected.pnl,
        'by_symbol':    group_pnl(actual.trades, 'symbol'),   # 分标的
        'by_factor':    group_pnl(actual.trades, 'factor'),   # 分因子
        'by_hour':      group_pnl(actual.trades, 'hour'),     # 分时段
        'cost': {
            'commission': actual.commission,
            'slippage':   actual.slippage,
            'impact':     actual.impact,
        },
    }

成本归因是复盘的必备项。如果某天亏损主要来自滑点,说明执行有问题(可能是拆单过粗或流动性判断错误),而不是策略有问题。区分这两者决定了修复方向。

归因项含义修复方向
Alpha 亏损选股/择时失效策略研究
成本超支滑点/手续费超预期执行优化
偏离亏损未按信号执行运维排查
暴露亏损风格暴露反向组合中性化

8. 策略衰减与下线决策

所有策略都会衰减。原因有三:市场结构变化、竞争者涌入、因子被套利掉。识别衰减并及时下线,比研究新策略同样重要。

衰减的信号:

1. 滚动 60 日 Sharpe 持续低于 0.5(回测为 1.5)
2. IC 均值连续 3 个月下降
3. 策略容量下降(同样的资金,滑点上升)
4. 与同类的相关性上升(说明在承担相同的风险)
5. 因子暴露漂移(实际持仓的风格暴露偏离目标)
def decay_score(stats):
    score = 0
    if stats.rolling_sharpe_60d < 0.5:
        score += 2
    if stats.ic_trend_3m < 0:
        score += 2
    if stats.slippage_trend > 0.3:      # 滑点上升 30%
        score += 1
    if stats.style_drift > 0.2:         # 风格漂移
        score += 1
    return score   # >= 4 建议下线;>= 3 降档观察

下线的决策要果断。很多团队在策略已经明显失效后仍继续运行,理由是「等它恢复」。这个心理陷阱的代价是持续亏损。预设的规则是:衰减分数达到阈值,自动降档;连续两周未改善,下线。

9. 值班与应急预案

实盘运维需要值班机制,尤其是在极端行情下。值班的核心是明确的升级路径:

一级(自动化):熔断、停止开仓、切换通道 —— 无需人工
二级(值班工程师):确认异常、执行预案 —— 5 分钟内响应
三级(策略负责人):决策是否下线策略 —— 15 分钟内响应
四级(管理层):重大损失的处理决策 —— 30 分钟内响应

应急预案必须书面化且定期演练:

场景 1:行情中断超过 30 秒
  动作:暂停开仓 → 确认行情源状态 → 切换备用源 → 恢复
  负责人:值班工程师

场景 2:策略异常报单(频率暴增)
  动作:立即停止策略 → 撤销所有挂单 → 排查代码/数据 → 恢复
  负责人:值班工程师 + 策略负责人

场景 3:单日亏损超过硬限
  动作:自动熔断 → 通知负责人 → 人工决策是否继续
  负责人:策略负责人

告警的通道要分级且冗余:一般告警走 IM,严重告警走短信 + 电话。告警通道本身也要有监控(心跳检测),否则告警系统挂了都不知道。相关实践参考 告警设计与事故响应 。

权衡取舍

维度保守运维激进运维
资金递增慢(月级)快(周级)
熔断阈值低(易触发)高(少干扰)
人工干预频繁少
收益速度慢快
事故风险低高

保守与激进的取舍取决于资金属性和团队能力。自有资金可以激进,客户资金必须保守;团队有成熟的自动化处置能力可以激进,依赖人工的必须保守。

监控粒度的取舍同样明显:监控太粗会漏掉问题,太细会被噪声淹没。判断标准是告警的可执行性——如果一个告警发出后值班人员不知道该做什么,这个告警就不该存在。

常见坑清单

  1. 跳过仿真盘直接实盘:柜台拒单、部分成交等问题只能在仿真盘暴露。
  2. 一次全量上线:没有灰度,出问题时损失是全量的。
  3. 只监控盈亏:信号数量、成交率、延迟等指标更早预警。
  4. 回撤告警无上下文:只报数字,接收者无法判断是否需要干预。
  5. 切换未演练:真实故障时备用进程配置过期、脚本失败。
  6. 切换后直接用本地状态:未查询订单真实状态,可能重复下单。
  7. 成本不归因:分不清是策略问题还是执行问题,修复方向错误。
  8. 策略衰减无规则:凭感觉决定是否下线,往往下得太晚。
  9. 告警通道单一:IM 挂了告警就发不出,严重事故必须走电话。
  10. 应急预案只写在文档里:从未演练,真实事故时无人知道流程。

小结

实盘运维的核心是把「人的判断」尽可能变成「系统的规则」。什么时候降档、什么时候熔断、什么时候下线,都应该有明确的量化标准。人的判断在亏损时会被情绪影响,而规则不会。

判断运维体系是否成熟,最快的检验是故障演练:随机制造行情中断、通道断开、进程崩溃等场景,看系统能否自动处置、告警能否触达、恢复流程是否顺畅。演练中暴露的问题,比真实事故中暴露的便宜得多。

下一步建议阅读 交易合规与监管要求 ,看运维过程中产生的日志与数据如何满足监管要求。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「量化交易」更多文章

  1. 风险模型与因子归因
  2. 回测偏差与过拟合防范
  3. 市场微结构与流动性