WebSocket API 参考¶
本页定义对外 WebSocket 实时推送接口。服务间内部事件通信请参考 Redis 事件总线。
版本说明:
| 版本 | 端点数 | 差异 |
|---|---|---|
| V1 (MVP) | 4 个 | 单策略 (baseline_rev),基础仓位/组合/告警/服务状态推送 |
| V2 | 4 + 1 个 | 多策略支持,增强载荷字段,新增 /ws/signals |
一、连接信息¶
开发环境¶
ws://localhost:8000/ws/positions
ws://localhost:8000/ws/portfolio
ws://localhost:8000/ws/alerts
ws://localhost:8000/ws/services
ws://localhost:8000/ws/signals [V2]
生产环境¶
二、通用协议¶
2.1 消息结构¶
所有服务端推送消息统一为:
| 字段 | 类型 | 说明 |
|---|---|---|
type |
string | 消息类型标识 |
data |
object | 业务载荷 |
timestamp |
string (ISO 8601) | 消息时间 (UTC) |
2.2 心跳协议¶
客户端每 30s 发送心跳,服务端响应:
// 客户端 → 服务端
{ "type": "ping" }
// 服务端 → 客户端
{ "type": "pong", "timestamp": "2026-03-02T23:59:00Z" }
超过 90s 未收到客户端 ping,服务端可主动断开连接。
2.3 错误消息¶
当发生异常时推送:
{
"type": "error",
"data": {
"code": 50001,
"message": "Redis connection lost, retrying..."
},
"timestamp": "2026-03-02T23:59:00Z"
}
2.4 重连建议¶
- 客户端收到
close/error后做指数退避重连 - 退避窗口:
3s → 6s → 12s → 24s,最大重试 10 次 - 重连成功后服务端自动推送最新全量快照
三、V1 端点¶
3.1 /ws/positions — 仓位快照¶
推送频率: 每 30 秒
推送内容: 当前仓位快照 + 目标仓位偏差
数据来源: Redis quant:account:positions + quant:signal:latest
后端实现路径: controller/routes/ws_positions.py
首条全量快照 (连接/重连后)¶
{
"type": "positions_snapshot",
"data": {
"positions": [
{
"symbol": "BTC/USDT:USDT",
"side": "long",
"contracts": 0.005,
"entry_price": 62450.00,
"mark_price": 62800.00,
"actual_weight": 0.0155,
"target_weight": 0.0167,
"deviation_pct": -7.2,
"unrealized_pnl": 1.75,
"leverage": 1
},
{
"symbol": "DOGE/USDT:USDT",
"side": "short",
"contracts": 500.0,
"entry_price": 0.1520,
"mark_price": 0.1505,
"actual_weight": -0.0162,
"target_weight": -0.0167,
"deviation_pct": 3.0,
"unrealized_pnl": 0.75,
"leverage": 1
}
],
"summary": {
"total_positions": 45,
"long_count": 30,
"short_count": 15,
"total_deviation": 0.045,
"missing_positions": 5,
"extra_positions": 2
},
"strategy_name": "baseline_rev",
"signal_timestamp": "2026-03-02T23:55:00Z"
},
"timestamp": "2026-03-02T23:59:00Z"
}
增量更新 (每 30s)¶
{
"type": "positions_update",
"data": {
"positions": [ ],
"summary": {
"total_positions": 45,
"long_count": 30,
"short_count": 15,
"total_deviation": 0.042,
"missing_positions": 4,
"extra_positions": 2
},
"strategy_name": "baseline_rev",
"signal_timestamp": "2026-03-02T23:55:00Z"
},
"timestamp": "2026-03-02T23:59:30Z"
}
字段说明¶
| 字段 | 类型 | 说明 |
|---|---|---|
positions[].symbol |
string | 交易对 (CCXT 统一格式) |
positions[].side |
string | "long" | "short" |
positions[].contracts |
float | 持仓合约数 |
positions[].entry_price |
float | 开仓均价 |
positions[].mark_price |
float | 标记价格 |
positions[].actual_weight |
float | 实际仓位权重 (占总权益比) |
positions[].target_weight |
float | 目标仓位权重 (来自策略信号) |
positions[].deviation_pct |
float | 偏差百分比 (actual - target) / target × 100 |
positions[].unrealized_pnl |
float | 未实现盈亏 (USDT) |
positions[].leverage |
int | 杠杆倍数 |
summary.total_positions |
int | 持仓总数 |
summary.long_count |
int | 多头数量 |
summary.short_count |
int | 空头数量 |
summary.total_deviation |
float | 平均偏差绝对值 |
summary.missing_positions |
int | 目标有但实际无的仓位数 |
summary.extra_positions |
int | 实际有但目标无的仓位数 |
strategy_name |
string | V1 固定 "baseline_rev" |
signal_timestamp |
string (ISO 8601) | 信号生成时间 |
3.2 /ws/portfolio — 组合指标¶
推送频率: 每 60 秒
推送内容: NAV / PnL / 回撤 / 波动率核心指标
数据来源: Redis quant:portfolio:snapshot
后端实现路径: controller/routes/ws_portfolio.py
首条全量快照¶
{
"type": "portfolio_snapshot",
"data": {
"nav": 10234.56,
"initial_nav": 10000.00,
"total_return": 0.023456,
"daily_pnl": -12.50,
"daily_pnl_pct": -0.0012,
"drawdown": -0.053,
"max_drawdown": -0.082,
"max_drawdown_date": "2026-02-20",
"sharpe_30d": 1.85,
"volatility_30d": 0.185,
"calmar_30d": 2.47,
"win_rate_30d": 0.62,
"total_equity": 10234.56,
"available_balance": 5120.30,
"used_margin": 5114.26,
"unrealized_pnl": 123.45,
"strategy_name": "baseline_rev",
"dry_run": true,
"trading_days": 61
},
"timestamp": "2026-03-02T23:59:00Z"
}
增量更新 (每 60s)¶
{
"type": "portfolio_update",
"data": {
"nav": 10234.56,
"total_return": 0.023456,
"daily_pnl": -12.50,
"daily_pnl_pct": -0.0012,
"drawdown": -0.053,
"max_drawdown": -0.082,
"sharpe_30d": 1.85,
"volatility_30d": 0.185,
"total_equity": 10234.56,
"unrealized_pnl": 123.45
},
"timestamp": "2026-03-02T24:00:00Z"
}
字段说明¶
| 字段 | 类型 | 全量 | 增量 | 说明 |
|---|---|---|---|---|
nav |
float | ✓ | ✓ | 当前 NAV 净值 |
initial_nav |
float | ✓ | 初始 NAV | |
total_return |
float | ✓ | ✓ | 累计收益率 |
daily_pnl |
float | ✓ | ✓ | 当日 PnL (USDT) |
daily_pnl_pct |
float | ✓ | ✓ | 当日 PnL 百分比 |
drawdown |
float | ✓ | ✓ | 当前回撤 (负数) |
max_drawdown |
float | ✓ | ✓ | 最大历史回撤 |
max_drawdown_date |
string | ✓ | 最大回撤发生日期 | |
sharpe_30d |
float | ✓ | ✓ | 30 日滚动 Sharpe |
volatility_30d |
float | ✓ | ✓ | 30 日滚动年化波动率 |
calmar_30d |
float | ✓ | 30 日 Calmar 比率 | |
win_rate_30d |
float | ✓ | 30 日胜率 | |
total_equity |
float | ✓ | ✓ | 总权益 (USDT) |
available_balance |
float | ✓ | 可用余额 | |
used_margin |
float | ✓ | 已用保证金 | |
unrealized_pnl |
float | ✓ | ✓ | 未实现盈亏 |
strategy_name |
string | ✓ | V1: "baseline_rev" |
|
dry_run |
bool | ✓ | 是否为模拟盘 | |
trading_days |
int | ✓ | 运行交易日数 |
3.3 /ws/alerts — 告警推送¶
推送频率: 实时 (事件触发)
推送内容: 风控告警 + 执行告警
数据来源: 订阅 Redis Pub/Sub quant:risk_rejected, quant:order_failed
后端实现路径: controller/routes/ws_alerts.py
风控拒绝告警¶
{
"type": "alert",
"data": {
"alert_id": "alt-20260302-001",
"severity": "critical",
"category": "risk_rejected",
"rule_name": "max_drawdown_halt",
"display_name": "最大回撤止损",
"message": "当前回撤 32% 超过阈值 30%, 触发暂停交易",
"details": {
"threshold": 0.30,
"actual": 0.32,
"strategy_name": "baseline_rev",
"rebalance_id": "rb-20260302-001"
},
"timestamp": "2026-03-02T23:59:01Z"
},
"timestamp": "2026-03-02T23:59:01Z"
}
订单失败告警¶
{
"type": "alert",
"data": {
"alert_id": "alt-20260302-002",
"severity": "warning",
"category": "order_failed",
"rule_name": "order_execution_failed",
"display_name": "下单执行失败",
"message": "下单失败: ETH/USDT:USDT, InsufficientBalance",
"details": {
"symbol": "ETH/USDT:USDT",
"side": "buy",
"error_code": "InsufficientBalance",
"retry_count": 3,
"order_id": "ord-20260302-005"
},
"timestamp": "2026-03-02T23:59:08Z"
},
"timestamp": "2026-03-02T23:59:08Z"
}
字段说明¶
| 字段 | 类型 | 说明 |
|---|---|---|
alert_id |
string | 告警唯一 ID,格式 alt-{YYYYMMDD}-{seq} |
severity |
string | "info" | "warning" | "critical" |
category |
string | 告警来源类别: "risk_rejected" | "order_failed" |
rule_name |
string | 触发的规则标识 |
display_name |
string | 规则显示名 (中文) |
message |
string | 可读告警描述 |
details |
object | 告警详细信息 (结构因 category 不同而异) |
timestamp |
string (ISO 8601) | 告警发生时间 |
3.4 /ws/services — 服务状态¶
推送频率: 每 30 秒
推送内容: 所有服务的心跳状态
数据来源: Redis quant:heartbeat:{service}
后端实现路径: controller/routes/ws_services.py
首条全量快照¶
{
"type": "services_snapshot",
"data": {
"services": [
{
"name": "asset_pool_service",
"display_name": "资产池",
"status": "healthy",
"last_heartbeat": "2026-03-02T23:58:30Z",
"uptime_seconds": 86400,
"latency_ms": 2,
"metrics": {
"symbols_count": 100,
"last_update": "2026-03-02T00:00:00Z"
}
},
{
"name": "aggregator_service",
"display_name": "K 线聚合",
"status": "healthy",
"last_heartbeat": "2026-03-02T23:58:28Z",
"uptime_seconds": 86400,
"latency_ms": 5,
"metrics": {
"klines_stored": 4200,
"symbols_streaming": 100
}
},
{
"name": "feature_service",
"display_name": "特征计算",
"status": "degraded",
"last_heartbeat": "2026-03-02T23:55:00Z",
"uptime_seconds": 86400,
"latency_ms": 240000,
"metrics": {
"last_calculation": "2026-03-02T23:54:50Z",
"symbols_calculated": 98
}
},
{
"name": "strategy_service",
"display_name": "策略引擎",
"status": "healthy",
"last_heartbeat": "2026-03-02T23:58:30Z",
"uptime_seconds": 86400,
"latency_ms": 3,
"metrics": {
"active_strategy": "baseline_rev",
"last_signal_time": "2026-03-02T23:55:00Z"
}
},
{
"name": "risk_service",
"display_name": "风控",
"status": "healthy",
"last_heartbeat": "2026-03-02T23:58:30Z",
"uptime_seconds": 86400,
"latency_ms": 2,
"metrics": {
"rules_active": 5,
"last_check": "2026-03-02T23:55:01Z"
}
},
{
"name": "order_service",
"display_name": "订单执行",
"status": "healthy",
"last_heartbeat": "2026-03-02T23:58:30Z",
"uptime_seconds": 86400,
"latency_ms": 2,
"metrics": {
"dry_run": true,
"last_orders_count": 12
}
},
{
"name": "account_service",
"display_name": "账户同步",
"status": "healthy",
"last_heartbeat": "2026-03-02T23:58:30Z",
"uptime_seconds": 86400,
"latency_ms": 2,
"metrics": {
"sync_interval": 30,
"last_sync": "2026-03-02T23:58:30Z"
}
}
],
"pipeline_status": "healthy",
"total_services": 7,
"healthy_count": 6,
"degraded_count": 1,
"down_count": 0
},
"timestamp": "2026-03-02T23:59:00Z"
}
增量更新 (每 30s)¶
{
"type": "services_update",
"data": {
"services": [ ],
"pipeline_status": "healthy",
"total_services": 7,
"healthy_count": 6,
"degraded_count": 1,
"down_count": 0
},
"timestamp": "2026-03-02T23:59:30Z"
}
字段说明¶
| 字段 | 类型 | 说明 |
|---|---|---|
services[].name |
string | 服务标识名 |
services[].display_name |
string | 显示名 (中文) |
services[].status |
string | "healthy" | "degraded" | "down" |
services[].last_heartbeat |
string (ISO 8601) | 最后一次心跳时间 |
services[].uptime_seconds |
int | 连续运行秒数 |
services[].latency_ms |
int | 距上次心跳的延迟 (毫秒)。>120000 → degraded,heartbeat 过期 → down |
services[].metrics |
object | 服务特有指标 (结构因服务不同而异) |
pipeline_status |
string | 管线整体状态。全部 healthy → "healthy";任一 degraded → "degraded";任一 down → "down" |
total_services |
int | 总服务数 |
healthy_count |
int | 健康服务数 |
degraded_count |
int | 降级服务数 |
down_count |
int | 宕机服务数 |
V1 服务列表¶
| 服务名 | display_name | 说明 |
|---|---|---|
asset_pool_service |
资产池 | 24h 更新 |
aggregator_service |
K 线聚合 | 拉取 kline |
feature_service |
特征计算 | ret/zscore |
strategy_service |
策略引擎 | baseline_rev |
risk_service |
风控 | 规则检查 |
order_service |
订单执行 | 差量下单 |
account_service |
账户同步 | 30s 轮询 |
四、V2 增强 [V2]¶
4.1 /ws/positions 增强 [V2]¶
V2 多策略模式下,仓位推送增加策略来源信息:
新增字段:
{
"type": "positions_update",
"data": {
"positions": [
{
"symbol": "BTC/USDT:USDT",
"side": "long",
"contracts": 0.005,
"entry_price": 62450.00,
"mark_price": 62800.00,
"actual_weight": 0.0155,
"target_weight": 0.0167,
"deviation_pct": -7.2,
"unrealized_pnl": 1.75,
"leverage": 1,
"strategy_source": "baseline_rev",
"ensemble_contribution": 0.3
}
],
"summary": {
"total_positions": 45,
"long_count": 30,
"short_count": 15,
"total_deviation": 0.042,
"missing_positions": 4,
"extra_positions": 2
},
"mode": "ensemble",
"active_strategies": ["baseline_rev", "rev_x_inv_vpin", "ofi_14d"],
"signal_timestamp": "2026-03-02T23:55:00Z"
},
"timestamp": "2026-03-02T23:59:00Z"
}
| 新增字段 | 类型 | 说明 |
|---|---|---|
positions[].strategy_source |
string | 该仓位来自哪个策略 |
positions[].ensemble_contribution |
float | ensemble 模式下该策略的权重贡献 |
mode |
string | "single" | "ensemble" |
active_strategies |
string[] | 当前激活的策略列表 |
V2 中 strategy_name 字段替换为 mode + active_strategies。V1 客户端兼容: mode 不存在时按 strategy_name 处理。
4.2 /ws/portfolio 增强 [V2]¶
V2 新增按策略拆分的指标:
{
"type": "portfolio_update",
"data": {
"nav": 10234.56,
"total_return": 0.023456,
"daily_pnl": -12.50,
"daily_pnl_pct": -0.0012,
"drawdown": -0.053,
"max_drawdown": -0.082,
"sharpe_30d": 1.85,
"volatility_30d": 0.185,
"total_equity": 10234.56,
"unrealized_pnl": 123.45,
"mode": "ensemble",
"per_strategy_metrics": [
{
"strategy_name": "baseline_rev",
"weight": 0.3,
"pool_name": "default",
"contribution_pnl": -4.50,
"long_count": 30,
"short_count": 30
},
{
"strategy_name": "rev_x_inv_vpin",
"weight": 0.3,
"pool_name": "default",
"contribution_pnl": 2.80,
"long_count": 10,
"short_count": 10
},
{
"strategy_name": "ofi_14d",
"weight": 0.4,
"pool_name": "t50_monthly",
"contribution_pnl": -10.80,
"long_count": 15,
"short_count": 15
}
]
},
"timestamp": "2026-03-02T23:59:00Z"
}
| 新增字段 | 类型 | 说明 |
|---|---|---|
mode |
string | "single" | "ensemble" |
per_strategy_metrics |
object[] | 各策略的贡献指标 (仅 ensemble 模式) |
per_strategy_metrics[].strategy_name |
string | 策略名 |
per_strategy_metrics[].weight |
float | ensemble 权重 |
per_strategy_metrics[].pool_name |
string | 使用的资产池 |
per_strategy_metrics[].contribution_pnl |
float | 该策略对当日 PnL 的贡献 |
per_strategy_metrics[].long_count |
int | 多头数量 |
per_strategy_metrics[].short_count |
int | 空头数量 |
4.3 /ws/alerts 增强 [V2]¶
V2 新增 bar_source_mismatch 告警类别:
{
"type": "alert",
"data": {
"alert_id": "alt-20260302-003",
"severity": "warning",
"category": "bar_source_mismatch",
"rule_name": "bar_source_deviation",
"display_name": "双源数据偏差",
"message": "BTC/USDT:USDT 双源 close 偏差 4.8bps, 连续 3 次",
"details": {
"symbol": "BTC/USDT:USDT",
"mismatch_type": "close_price",
"deviation_bps": 4.8,
"threshold_bps": 5,
"consecutive_mismatches": 3,
"auto_fallback_triggered": false
},
"timestamp": "2026-03-02T14:53:00Z"
},
"timestamp": "2026-03-02T14:53:00Z"
}
V2 告警 category 取值扩展为: "risk_rejected" | "order_failed" | "bar_source_mismatch"
4.4 /ws/signals — 策略信号推送 [V2 新增]¶
推送频率: 事件触发 (每次 signal_generated 后)
推送内容: 最新策略信号快照
数据来源: 订阅 Redis Pub/Sub quant:signal_generated
后端实现路径: controller/routes/ws_signals.py
消息格式¶
{
"type": "signal_update",
"data": {
"mode": "ensemble",
"signal_timestamp": "2026-03-02T23:59:00Z",
"rebalance_id": "rb-20260302-001",
"ensemble_positions": [
{
"symbol": "BTC/USDT:USDT",
"side": "long",
"weight": 0.0125,
"rank": 1
}
],
"per_strategy_signals": [
{
"strategy_name": "baseline_rev",
"pool_name": "default",
"long_count": 30,
"short_count": 30,
"top_signals": [
{ "symbol": "BTC/USDT:USDT", "signal_value": 1.85, "side": "long", "rank": 1 },
{ "symbol": "DOGE/USDT:USDT", "signal_value": -2.10, "side": "short", "rank": 480 }
]
},
{
"strategy_name": "ofi_14d",
"pool_name": "t50_monthly",
"long_count": 15,
"short_count": 15,
"top_signals": [
{ "symbol": "SOL/USDT:USDT", "signal_value": 2.45, "side": "long", "rank": 1 },
{ "symbol": "AVAX/USDT:USDT", "signal_value": -1.80, "side": "short", "rank": 50 }
]
}
],
"total_symbols_in_pool": 488
},
"timestamp": "2026-03-02T23:59:00Z"
}
| 字段 | 类型 | 说明 |
|---|---|---|
mode |
string | "single" | "ensemble" |
signal_timestamp |
string (ISO 8601) | 信号计算时间 |
rebalance_id |
string | 换仓 ID |
ensemble_positions |
object[] | ensemble 加权后的最终目标仓位 (仅 ensemble 模式) |
per_strategy_signals |
object[] | 各策略独立信号摘要 |
per_strategy_signals[].strategy_name |
string | 策略名 |
per_strategy_signals[].pool_name |
string | 资产池 |
per_strategy_signals[].long_count |
int | 多头数量 |
per_strategy_signals[].short_count |
int | 空头数量 |
per_strategy_signals[].top_signals |
object[] | Top/Bottom 信号摘要 (各取前 5) |
total_symbols_in_pool |
int | 资产池总 symbol 数 |
4.5 V2 服务列表扩展 [V2]¶
V2 的 /ws/services 新增以下服务:
| 新增服务名 | display_name | 说明 |
|---|---|---|
data_ingestion_service |
数据采集 | aggTrade WebSocket |
dollar_bar_service |
Dollar Bar 聚合 | 自适应阈值 |
tick_feature_service |
Tick 特征 | 9 个微观特征 |
bar_source_adapter_service |
Bar 适配层 | 双源归一化 |
monitor_service |
监控告警 | 心跳检查 + 告警 |
五、版本兼容性¶
| 场景 | V1 客户端连接 V2 服务端 | V2 客户端连接 V1 服务端 |
|---|---|---|
/ws/positions |
兼容。忽略新增字段 (strategy_source, mode 等) |
兼容。新增字段不存在时使用默认值 |
/ws/portfolio |
兼容。忽略 per_strategy_metrics |
兼容。per_strategy_metrics 为 null |
/ws/alerts |
兼容。新 category 按 "warning" 显示 |
兼容。不会收到 V2 专有告警 |
/ws/services |
兼容。新增服务正常显示 | 兼容。缺少的服务不显示 |
/ws/signals |
不适用 (V1 无此端点) | 连接失败,降级为轮询 HTTP |