darkeril

V5.4 Strategy Factory 数据合约文档

V5.4 策略工厂完整数据合约,包含所有表结构、API 接口、字段约束、迁移方案

V5.4 Strategy Factory 数据合约文档

版本:v1.0
日期:2026-03-11
作者:露露
状态:待范总 + 小范 + 小周 Review
原则:设计优先于实现;可扩展性优先于性能;字段语义必须清晰


1. 设计原则

  1. 数据优先:所有结构在编码前确定,不在编码过程中随意增减字段
  2. 可扩展:预留 schema_version,参数结构变更时向后兼容
  3. 可溯源:历史记录永久保留,所有状态变更记录时间戳
  4. 冗余快照:关键关联字段(如策略名)在写入时做快照,防止改名后历史数据断层
  5. 执行与展示分离:执行相关字段和展示/说明字段在表设计和代码中明确区分,避免相互干扰

2. 核心表结构

2.1 strategies 表(策略配置主表)

每一行代表一个策略实例(一个币种 × 一套参数配置)。

CREATE TABLE strategies (
  -- ─── 标识 ──────────────────────────────────────────────────
  strategy_id         UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  display_name        TEXT NOT NULL,                        -- 用户自定义名称,可改
  
  -- ─── 版本控制 ────────────────────────────────────────────────
  schema_version      INT NOT NULL DEFAULT 1,               -- 参数结构版本,升级时递增
  
  -- ─── 状态 ────────────────────────────────────────────────────
  status              TEXT NOT NULL DEFAULT 'running'
                      CHECK (status IN ('running', 'paused', 'deprecated')),
  status_changed_at   TIMESTAMP,                            -- 最近一次状态变更时间
  last_run_at         TIMESTAMP,                            -- 最近一次 Worker 评估时间(心跳用)
  deprecated_at       TIMESTAMP,                           -- 废弃时间(nullable)
  
  -- ─── 基础配置(执行层)────────────────────────────────────────
  symbol              TEXT NOT NULL
                      CHECK (symbol IN ('BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'XRPUSDT')),
  direction           TEXT NOT NULL DEFAULT 'both'
                      CHECK (direction IN ('long_only', 'short_only', 'both')),
  
  -- ─── CVD 窗口(执行层)────────────────────────────────────────
  cvd_fast_window     TEXT NOT NULL DEFAULT '30m'
                      CHECK (cvd_fast_window IN ('5m', '15m', '30m')),
  cvd_slow_window     TEXT NOT NULL DEFAULT '4h'
                      CHECK (cvd_slow_window IN ('1h', '4h')),
  
  -- ─── 四层权重(执行层,合计必须 = 100)────────────────────────
  weight_direction    INT NOT NULL DEFAULT 55
                      CHECK (weight_direction BETWEEN 10 AND 80),
  weight_env          INT NOT NULL DEFAULT 25
                      CHECK (weight_env BETWEEN 5 AND 60),
  weight_aux          INT NOT NULL DEFAULT 15
                      CHECK (weight_aux BETWEEN 0 AND 40),
  weight_momentum     INT NOT NULL DEFAULT 5
                      CHECK (weight_momentum BETWEEN 0 AND 20),
  -- 应用层校验:weight_direction + weight_env + weight_aux + weight_momentum = 100
  
  -- ─── 入场阈值(执行层)────────────────────────────────────────
  entry_score         INT NOT NULL DEFAULT 75
                      CHECK (entry_score BETWEEN 60 AND 95),
  
  -- ─── 四道 Gate(执行层)───────────────────────────────────────
  gate_obi_enabled        BOOL NOT NULL DEFAULT TRUE,
  obi_threshold           FLOAT NOT NULL DEFAULT 0.3
                          CHECK (obi_threshold BETWEEN 0.1 AND 0.9),
  
  gate_whale_enabled      BOOL NOT NULL DEFAULT TRUE,
  whale_cvd_threshold     FLOAT NOT NULL DEFAULT 0.0
                          CHECK (whale_cvd_threshold BETWEEN -1.0 AND 1.0),
  
  gate_vol_enabled        BOOL NOT NULL DEFAULT TRUE,
  atr_percentile_min      INT NOT NULL DEFAULT 20
                          CHECK (atr_percentile_min BETWEEN 5 AND 80),
  
  gate_spot_perp_enabled  BOOL NOT NULL DEFAULT FALSE,
  spot_perp_threshold     FLOAT NOT NULL DEFAULT 0.002
                          CHECK (spot_perp_threshold BETWEEN 0.0005 AND 0.01),
  
  -- ─── 风控参数(执行层)────────────────────────────────────────
  sl_atr_multiplier   FLOAT NOT NULL DEFAULT 1.5
                      CHECK (sl_atr_multiplier BETWEEN 0.5 AND 3.0),
  tp1_ratio           FLOAT NOT NULL DEFAULT 0.75
                      CHECK (tp1_ratio BETWEEN 0.3 AND 2.0),
  tp2_ratio           FLOAT NOT NULL DEFAULT 1.5
                      CHECK (tp2_ratio BETWEEN 0.5 AND 4.0),
  timeout_minutes     INT NOT NULL DEFAULT 240
                      CHECK (timeout_minutes BETWEEN 30 AND 1440),
  flip_threshold      INT NOT NULL DEFAULT 80
                      CHECK (flip_threshold BETWEEN 60 AND 95),
  
  -- ─── 资金(执行层)────────────────────────────────────────────
  initial_balance     FLOAT NOT NULL DEFAULT 10000.0
                      CHECK (initial_balance >= 1000),
  current_balance     FLOAT NOT NULL DEFAULT 10000.0,
  
  -- ─── 元数据(展示层,不影响执行)──────────────────────────────
  description         TEXT,                                 -- 策略描述,可选
  tags                TEXT[],                              -- 标签,可选
  
  -- ─── 时间戳 ──────────────────────────────────────────────────
  created_at          TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at          TIMESTAMP NOT NULL DEFAULT NOW()
);

-- 索引
CREATE INDEX idx_strategies_status ON strategies(status);
CREATE INDEX idx_strategies_symbol ON strategies(symbol);
CREATE INDEX idx_strategies_last_run ON strategies(last_run_at);

字段约束说明

分组字段是否影响执行备注
执行层symbol, direction, cvd_, weight_, entry_score, gate_, sl_, tp_, timeout_, flip_*✅ 是Worker 每周期读取这些字段做决策
展示层display_name, description, tags❌ 否仅前端展示,修改不影响运行
状态层status, *_at 时间戳部分status 影响 Worker 是否运行;时间戳仅记录

2.2 paper_trades 表(模拟盘交易记录,修改项)

在现有基础上新增/修改以下字段:

ALTER TABLE paper_trades
  -- 新增:策略UUID外键(新数据用UUID,旧数据回填后也有)
  ADD COLUMN strategy_id UUID REFERENCES strategies(strategy_id),
  
  -- 新增:写入时快照策略名称,防止改名后历史断层
  ADD COLUMN strategy_name_snapshot TEXT,
  
  -- 保留:旧的 strategy 文本字段改为只读(迁移后不再写入,仅查询兼容用)
  -- 注:旧字段 strategy TEXT 继续保留,不删除
  ;

-- 新数据索引
CREATE INDEX idx_paper_trades_strategy_id ON paper_trades(strategy_id);

迁移后写入规则

  • strategy_id:必填,写入 UUID
  • strategy_name_snapshot:必填,写入当时的 display_name
  • strategy(旧字段):不再写入,仅保留历史数据,只读

2.3 signal_indicators 表(信号记录,修改项)

ALTER TABLE signal_indicators
  ADD COLUMN strategy_id UUID REFERENCES strategies(strategy_id),
  ADD COLUMN strategy_name_snapshot TEXT;

paper_trades,旧 strategy 字段保留只读。


2.4 paper_positions 表(持仓记录,修改项)

ALTER TABLE paper_positions
  ADD COLUMN strategy_id UUID REFERENCES strategies(strategy_id),
  ADD COLUMN strategy_name_snapshot TEXT;

3. 迁移方案

3.1 旧策略固定 UUID 映射

迁移时为现有三条策略分配固定 UUID(预先确定,写入迁移脚本):

旧策略名固定 UUID备注
v5300000000-0000-0000-0000-000000000053便于识别
v53_middle00000000-0000-0000-0000-000000000054便于识别
v53_fast00000000-0000-0000-0000-000000000055已废弃但数据保留

3.2 迁移脚本逻辑(伪代码)

-- Step 1: 在 strategies 表插入三条旧策略记录
INSERT INTO strategies (strategy_id, display_name, symbol, status, schema_version, ...)
VALUES
  ('00000000-...0053', 'V5.3 Standard (BTC)', 'BTCUSDT', 'running', 1, ...),
  -- 注:v53 是多币种策略,每个币种各插一条
  ...;

-- Step 2: 回填 paper_trades
UPDATE paper_trades
SET strategy_id = '00000000-...0053',
    strategy_name_snapshot = 'V5.3 Standard'
WHERE strategy = 'v53';

-- Step 3: 回填 signal_indicators、paper_positions(同上)

-- Step 4: 验证回填完整性
SELECT strategy, COUNT(*) FROM paper_trades WHERE strategy_id IS NULL GROUP BY strategy;
-- 预期:0行(全部回填完成)

3.3 回滚路径

  • 迁移前:git tag v5.3-before-migration 打标签
  • 迁移前:pg_dump arb_engine > backup_before_v54.sql 备份数据库
  • 回滚时:停 V5.4 Strategy Factory → 恢复旧 signal_engine.py(按 git tag 回退)
  • 无需恢复 DB(新字段不影响旧代码读取,兼容)

4. API 接口定义

所有接口需 JWT 认证(Authorization: Bearer <token>)。

4.1 策略管理

POST /api/strategies — 创建策略

Request Body

{
  "display_name": "我的BTC激进策略",
  "symbol": "BTCUSDT",
  "direction": "both",
  "initial_balance": 10000,
  "cvd_fast_window": "30m",
  "cvd_slow_window": "4h",
  "weight_direction": 55,
  "weight_env": 25,
  "weight_aux": 15,
  "weight_momentum": 5,
  "entry_score": 75,
  "gate_obi_enabled": true,
  "obi_threshold": 0.3,
  "gate_whale_enabled": true,
  "whale_cvd_threshold": 0.0,
  "gate_vol_enabled": true,
  "atr_percentile_min": 20,
  "gate_spot_perp_enabled": false,
  "spot_perp_threshold": 0.002,
  "sl_atr_multiplier": 1.5,
  "tp1_ratio": 0.75,
  "tp2_ratio": 1.5,
  "timeout_minutes": 240,
  "flip_threshold": 80,
  "description": "可选描述"
}

校验规则

  • weight_direction + weight_env + weight_aux + weight_momentum == 100,否则返回 400
  • 所有数值字段在允许范围内,否则返回 400 并说明超限字段

Response 200

{
  "strategy_id": "uuid-...",
  "display_name": "我的BTC激进策略",
  "status": "running",
  "created_at": 1741697000000
}

GET /api/strategies — 获取策略列表

Query Params

  • include_deprecated=true|false(默认 false,只返回 running/paused)

Response 200

{
  "strategies": [
    {
      "strategy_id": "uuid-...",
      "display_name": "V5.3 Standard",
      "symbol": "BTCUSDT",
      "status": "running",
      "current_balance": 8500.0,
      "initial_balance": 10000.0,
      "net_usdt": -1500.0,
      "net_r": -7.5,
      "trade_count": 191,
      "win_rate": 46.6,
      "avg_win_r": 0.50,
      "avg_loss_r": -0.78,
      "open_positions": 0,
      "pnl_usdt_24h": -200.0,
      "pnl_r_24h": -1.0,
      "last_trade_at": 1741697000000,
      "last_run_at": 1741697100000
    }
  ]
}

GET /api/strategies/{id} — 获取策略详情(含完整参数)

Response 200:在列表字段基础上额外返回所有配置参数字段(权重、Gate、风控等)。


PATCH /api/strategies/{id} — 更新策略参数

Request Body:只传需要修改的字段(Partial Update)。

约束

  • status = deprecated 的策略不允许修改参数(返回 403)
  • 权重合计校验同创建接口

POST /api/strategies/{id}/pause — 暂停策略

Worker 停止开新仓,不影响现有持仓(继续管理直到平仓)。


POST /api/strategies/{id}/resume — 恢复策略


POST /api/strategies/{id}/deprecate — 废弃策略

Request Body{ "confirm": true }(防止误操作)

废弃后:

  • statusdeprecated
  • deprecated_at → NOW()
  • Worker 停止运行
  • 数据永久保留

POST /api/strategies/{id}/restore — 重新启用废弃策略

恢复至 running 状态,继续原有余额和历史数据。


POST /api/strategies/{id}/add-balance — 追加余额

Request Body{ "amount": 5000.0 }

执行逻辑:

initial_balance += amount
current_balance += amount

4.2 策略广场汇总(已有端点,保留)

  • GET /api/strategy-plaza — 所有活跃策略卡片数据(同 GET /api/strategies
  • GET /api/strategy-plaza/{id}/summary — 单策略汇总

5. Feature Event 结构(Signal Engine → Workers)

Signal Engine 每15秒广播一次,Workers 订阅后消费。

@dataclass
class FeatureEvent:
    # 时间
    ts: int                    # Unix ms
    
    # 基础行情
    symbol: str                # 'BTCUSDT' | 'ETHUSDT' | ...
    price: float               # 实时最新成交价(last_trade_price,非均价)
    atr_value: float           # ATR(14)
    
    # CVD(全部5个窗口,Worker 按需取用)
    cvd_5m: float
    cvd_15m: float
    cvd_30m: float
    cvd_1h: float
    cvd_4h: float
    
    # OBI
    obi: float                 # 订单簿失衡 [-1, 1]
    
    # Whale flow
    whale_cvd: float           # 大单净买入 CVD
    whale_buy_ratio: float     # 大单买入比例 [0, 1]
    
    # 现货/永续溢价
    spot_perp_div: float       # 现货-永续溢价率
    
    # 市场环境
    funding_rate: float        # 资金费率
    open_interest_change: float # OI变化率
    
    # ATR 百分位(用于 gate_vol 判断)
    atr_percentile: int        # 0-100

约束

  • price 必须使用实时点价(last_trade_price),不得使用均价或历史价格
  • Signal Engine 只计算并广播 feature,不做任何评分或开仓决策

6. Worker 配置读取规则

Worker 在每次收到 FeatureEvent 时:

  1. 从 DB 读取最新配置(SELECT * FROM strategies WHERE strategy_id = ? AND status = 'running'
  2. status != 'running',跳过本次评估
  3. 更新 last_run_at = NOW()
  4. 按配置中的 CVD 窗口、权重、Gate 阈值进行评分
  5. 满足入场条件则开仓,开仓记录写入 paper_trades(含 strategy_id + strategy_name_snapshot

7. 参数默认值与边界一览

参数默认值最小值最大值单位
weight_direction551080整数,%
weight_env25560整数,%
weight_aux15040整数,%
weight_momentum5020整数,%
entry_score756095整数,分
obi_threshold0.30.10.9float
whale_cvd_threshold0.0-1.01.0float
atr_percentile_min20580整数,%
spot_perp_threshold0.0020.00050.01float
sl_atr_multiplier1.50.53.0float,倍
tp1_ratio0.750.32.0float,×RD
tp2_ratio1.50.54.0float,×RD
timeout_minutes240301440整数,分钟
flip_threshold806095整数,分
initial_balance1000010001000000USDT

8. 上线步骤(概要)

详细操作 SOP 由小周编写,此处只列关键节点:

  1. 迁移前备份pg_dump arb_engine > backup_before_v54.sql
  2. 打 Git Taggit tag v5.3-before-migration
  3. 执行 Schema 迁移:新增字段、创建 strategies
  4. 执行数据迁移:插入三条旧策略记录,回填 strategy_id + strategy_name_snapshot
  5. 验证回填完整性:确认无 NULL 的 strategy_id
  6. 停旧引擎,启新 Strategy Factory
  7. 验证三策略心跳正常last_run_at 在15秒内更新)
  8. 上线当天限制:不开放"新增策略"功能,只迁移现有三条,观察1-2个交易日

9. Review 检查清单

  • 范总确认数据合约整体方向
  • 小范审阅表结构和 API 逻辑
  • 小周确认迁移步骤可操作性,并编写上线/回滚 SOP
  • 所有人确认后,露露开始编码

On this page