#!/usr/bin/env python3 """ bootstrap_eth_xrp_sol_strategies.py 基于 v5.3 Optuna 结果 + v53.json 的 symbol_gates,为策略工厂批量创建 ETH/XRP/SOL 的 54 条单币种策略配置。 约定: - 仍沿用 BTC 工厂当前的 CVD 组合与 TP 档位: * CVD 窗口: (5m,30m), (5m,1h), (15m,1h), (15m,4h), (30m,1h), (30m,4h) * TP 档位: 保守 / 平衡 / 激进(sl=2ATR,TP=0.75/1.0/1.5R 与 1.5/2.0/2.5R) - 每个 symbol 的门控阈值复刻 v53.json 的 symbol_gates: * ETHUSDT: min_vol=0.003, whale_usd=50000, obi=0.35, spd=0.005 * XRPUSDT: min_vol=0.0025, whale_usd=30000, obi=0.40, spd=0.006 * SOLUSDT: min_vol=0.004, whale_usd=20000, obi=0.45, spd=0.008 - 五门开关与 BTC 工厂当前配置保持一致: * 波动率门 / CVD 门 / 巨鲸门 / OBI 门:启用 * 期现门:关闭(仅写入阈值,保留以后启用的空间) - 权重与开仓阈值取自 optuna_results_v3_cn.xlsx 中各 symbol 的 v53/v53_fast Top1: * ETHUSDT (v53): dir=51, env=18, aux=28, mom=3, threshold=75 * XRPUSDT (v53): dir=58, env=8, aux=32, mom=2, threshold=80 * SOLUSDT (v53_fast): dir=38, env=42, aux=8, mom=12, threshold=65 注意: - 如果某个 display_name 已存在于 strategies 表,将跳过,不会重复插入。 - 连接参数走 backend.db.get_sync_conn(),运行脚本时请设置: PG_HOST=127.0.0.1 PG_PORT=9470 PG_DB=arb_engine PG_USER=arb PG_PASS=... 或在服务器上直接使用 Cloud SQL 内网地址。 """ from __future__ import annotations import os import sys from dataclasses import dataclass # 确保可以从 backend 导入 db.get_sync_conn sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "backend")) from db import get_sync_conn # type: ignore @dataclass class SymbolProfile: symbol: str weight_direction: int weight_env: int weight_aux: int weight_momentum: int entry_score: int min_vol: float whale_usd_threshold: float whale_flow_pct: float obi_threshold: float spot_perp_threshold: float # 基于 optuna_results_v3_cn.xlsx Top1 Summary + v53.json symbol_gates SYMBOL_PROFILES: list[SymbolProfile] = [ SymbolProfile( symbol="ETHUSDT", weight_direction=51, weight_env=18, weight_aux=28, weight_momentum=3, entry_score=75, min_vol=0.003, whale_usd_threshold=50_000, whale_flow_pct=0.5, # ALT 分支主要用 whale_usd_threshold,此处保持默认 obi_threshold=0.35, spot_perp_threshold=0.005, ), SymbolProfile( symbol="XRPUSDT", weight_direction=58, weight_env=8, weight_aux=32, weight_momentum=2, entry_score=80, min_vol=0.0025, whale_usd_threshold=30_000, whale_flow_pct=0.5, obi_threshold=0.40, spot_perp_threshold=0.006, ), SymbolProfile( symbol="SOLUSDT", weight_direction=38, weight_env=42, weight_aux=8, weight_momentum=12, entry_score=65, min_vol=0.004, whale_usd_threshold=20_000, whale_flow_pct=0.5, obi_threshold=0.45, spot_perp_threshold=0.008, ), ] # 与 BTC 工厂一致的 CVD 组合 CVD_COMBOS: list[tuple[str, str]] = [ ("5m", "30m"), ("5m", "1h"), ("15m", "1h"), ("15m", "4h"), ("30m", "1h"), ("30m", "4h"), ] # TP 档位:保守 / 平衡 / 激进(统一 sl_multiplier=2.0) TP_PROFILES: dict[str, dict[str, float]] = { "保守": {"sl_atr_multiplier": 2.0, "tp1_ratio": 0.75, "tp2_ratio": 1.5}, "平衡": {"sl_atr_multiplier": 2.0, "tp1_ratio": 1.0, "tp2_ratio": 2.0}, "激进": {"sl_atr_multiplier": 2.0, "tp1_ratio": 1.5, "tp2_ratio": 2.5}, } def build_display_name(symbol: str, fast_win: str, slow_win: str, tp_label: str) -> str: """ 生成与 BTC 工厂一致的 display_name,例如: BTC_CVD5x30m_TP保守 → ETH_CVD5x30m_TP保守 """ base = symbol.replace("USDT", "") fast_label = fast_win.replace("m", "") # "5m" → "5" return f"{base}_CVD{fast_label}x{slow_win}_TP{tp_label}" def main() -> None: created = 0 skipped = 0 with get_sync_conn() as conn: with conn.cursor() as cur: for profile in SYMBOL_PROFILES: sym = profile.symbol for fast_win, slow_win in CVD_COMBOS: for tp_label, tp_cfg in TP_PROFILES.items(): display_name = build_display_name(sym, fast_win, slow_win, tp_label) # 避免重复插入:按 display_name 检查 cur.execute( "SELECT 1 FROM strategies WHERE display_name=%s", (display_name,), ) if cur.fetchone(): skipped += 1 continue cur.execute( """ INSERT INTO strategies ( display_name, symbol, direction, cvd_fast_window, cvd_slow_window, weight_direction, weight_env, weight_aux, weight_momentum, entry_score, gate_vol_enabled, vol_atr_pct_min, gate_cvd_enabled, gate_whale_enabled, whale_usd_threshold, whale_flow_pct, gate_obi_enabled, obi_threshold, gate_spot_perp_enabled, spot_perp_threshold, sl_atr_multiplier, tp1_ratio, tp2_ratio, timeout_minutes, flip_threshold ) VALUES ( %s, -- display_name %s, -- symbol %s, -- direction %s, -- cvd_fast_window %s, -- cvd_slow_window %s, -- weight_direction %s, -- weight_env %s, -- weight_aux %s, -- weight_momentum %s, -- entry_score %s, -- gate_vol_enabled %s, -- vol_atr_pct_min %s, -- gate_cvd_enabled %s, -- gate_whale_enabled %s, -- whale_usd_threshold %s, -- whale_flow_pct %s, -- gate_obi_enabled %s, -- obi_threshold %s, -- gate_spot_perp_enabled %s, -- spot_perp_threshold %s, -- sl_atr_multiplier %s, -- tp1_ratio %s, -- tp2_ratio %s, -- timeout_minutes %s -- flip_threshold ) """, ( display_name, sym, "both", # 方向:多空双向 fast_win, slow_win, profile.weight_direction, profile.weight_env, profile.weight_aux, profile.weight_momentum, profile.entry_score, True, # gate_vol_enabled profile.min_vol, True, # gate_cvd_enabled True, # gate_whale_enabled profile.whale_usd_threshold, profile.whale_flow_pct, True, # gate_obi_enabled profile.obi_threshold, False, # gate_spot_perp_enabled(与当前 BTC 工厂一致,先关闭) profile.spot_perp_threshold, tp_cfg["sl_atr_multiplier"], tp_cfg["tp1_ratio"], tp_cfg["tp2_ratio"], 240, # timeout_minutes,沿用 BTC 工厂 80, # flip_threshold,沿用 v5.4 设计 ), ) created += 1 conn.commit() print(f"[bootstrap] created={created}, skipped={skipped}") if __name__ == "__main__": main()