feat: merge v53_alt+v53_btc into unified v53 strategy (all 4 symbols, per-symbol gates)

This commit is contained in:
root 2026-03-03 15:59:27 +00:00
parent 546fae39d0
commit 42cb230337
4 changed files with 87 additions and 223 deletions

View File

@ -1,6 +1,6 @@
{ {
"enabled": true, "enabled": true,
"enabled_strategies": ["v51_baseline", "v52_8signals", "v53_alt", "v53_btc"], "enabled_strategies": ["v51_baseline", "v52_8signals", "v53"],
"initial_balance": 10000, "initial_balance": 10000,
"risk_per_trade": 0.02, "risk_per_trade": 0.02,
"max_positions": 4, "max_positions": 4,

View File

@ -42,7 +42,7 @@ logger = logging.getLogger("signal-engine")
SYMBOLS = ["BTCUSDT", "ETHUSDT", "XRPUSDT", "SOLUSDT"] SYMBOLS = ["BTCUSDT", "ETHUSDT", "XRPUSDT", "SOLUSDT"]
LOOP_INTERVAL = 15 # 秒从5改15CPU降60%,信号质量无影响) LOOP_INTERVAL = 15 # 秒从5改15CPU降60%,信号质量无影响)
STRATEGY_DIR = os.path.join(os.path.dirname(__file__), "strategies") STRATEGY_DIR = os.path.join(os.path.dirname(__file__), "strategies")
DEFAULT_STRATEGY_FILES = ["v51_baseline.json", "v52_8signals.json", "v53_alt.json", "v53_btc.json"] DEFAULT_STRATEGY_FILES = ["v51_baseline.json", "v52_8signals.json", "v53.json"]
def load_strategy_configs() -> list[dict]: def load_strategy_configs() -> list[dict]:
@ -453,23 +453,15 @@ class SymbolState:
track = strategy_cfg.get("track", "ALT") track = strategy_cfg.get("track", "ALT")
# ─── Track Router ─────────────────────────────────────────── # ─── Track Router ───────────────────────────────────────────
# V5.3策略按track路由到专属评分逻辑 # v53 → 统一评分BTC/ETH/XRP/SOL
# v53_alt → ALT轨ETH/XRP/SOL55/25/15/5删确认层 # v53_alt / v53_btc → 兼容旧策略名,转发到 _evaluate_v53()
# v53_btc → BTC轨gate-control逻辑
# v51/v52 → 原有代码路径(兼容,不修改) # v51/v52 → 原有代码路径(兼容,不修改)
if track == "ALT" and strategy_name.startswith("v53"): if strategy_name.startswith("v53"):
# 检查symbol限制v53_alt只跑ALT不跑BTC
allowed_symbols = strategy_cfg.get("symbols", []) allowed_symbols = strategy_cfg.get("symbols", [])
if allowed_symbols and self.symbol not in allowed_symbols: if allowed_symbols and self.symbol not in allowed_symbols:
snap = snapshot or self.build_evaluation_snapshot(now_ms) snap = snapshot or self.build_evaluation_snapshot(now_ms)
return self._empty_result(strategy_name, snap) return self._empty_result(strategy_name, snap)
return self._evaluate_v53_alt(now_ms, strategy_cfg, snapshot) return self._evaluate_v53(now_ms, strategy_cfg, snapshot)
if track == "BTC" and strategy_name.startswith("v53"):
# v53_btc只跑BTC
if self.symbol != "BTCUSDT":
snap = snapshot or self.build_evaluation_snapshot(now_ms)
return self._empty_result(strategy_name, snap)
return self._evaluate_v53_btc(now_ms, strategy_cfg, snapshot)
# ─── 原有V5.1/V5.2评分逻辑(保持不变)──────────────────────── # ─── 原有V5.1/V5.2评分逻辑(保持不变)────────────────────────
strategy_cfg = strategy_cfg or {} strategy_cfg = strategy_cfg or {}
strategy_name = strategy_cfg.get("name", "v51_baseline") strategy_name = strategy_cfg.get("name", "v51_baseline")
@ -725,13 +717,17 @@ class SymbolState:
"signal": None, "direction": None, "score": 0, "tier": None, "factors": {}, "signal": None, "direction": None, "score": 0, "tier": None, "factors": {},
} }
def _evaluate_v53_alt(self, now_ms: int, strategy_cfg: dict, snapshot: Optional[dict] = None) -> dict: def _evaluate_v53(self, now_ms: int, strategy_cfg: dict, snapshot: Optional[dict] = None) -> dict:
""" """
V5.3 ALT轨评分ETH/XRP/SOL V5.3 统一评分BTC/ETH/XRP/SOL
权重Direction 55 | Crowding 25 | Environment 15 | Auxiliary 5 架构四层评分 55/25/15/5 + per-symbol 四门控制
删除独立确认层解决CVD双重计分问题 - 门1波动率下限atr/price
- 门2CVD共振fast+mid同向
- 门3OBI否决实时WebSocketfallback DB
- 门4期现背离否决实时WebSocketfallback DB
BTC额外whale_cvd_ratio>$100k巨鲸CVD
""" """
strategy_name = strategy_cfg.get("name", "v53_alt") strategy_name = strategy_cfg.get("name", "v53")
strategy_threshold = int(strategy_cfg.get("threshold", 75)) strategy_threshold = int(strategy_cfg.get("threshold", 75))
flip_threshold = int(strategy_cfg.get("flip_threshold", 85)) flip_threshold = int(strategy_cfg.get("flip_threshold", 85))
@ -741,34 +737,31 @@ class SymbolState:
price = snap["price"] price = snap["price"]
atr = snap["atr"] atr = snap["atr"]
atr_value = snap.get("atr_value", atr) atr_value = snap.get("atr_value", atr)
atr_pct = snap["atr_pct"]
cvd_fast_accel = snap["cvd_fast_accel"] cvd_fast_accel = snap["cvd_fast_accel"]
environment_score_raw = snap["environment_score"] environment_score_raw = snap["environment_score"]
result = self._empty_result(strategy_name, snap) result = self._empty_result(strategy_name, snap)
if self.warmup or price == 0 or atr == 0: if self.warmup or price == 0 or atr == 0:
return result return result
last_signal_ts = self.last_signal_ts.get(strategy_name, 0) last_signal_ts = self.last_signal_ts.get(strategy_name, 0)
in_cooldown = now_ms - last_signal_ts < COOLDOWN_MS in_cooldown = now_ms - last_signal_ts < COOLDOWN_MS
# ── Per-symbol 四门参数(从 strategy_cfg.symbol_gates 读取)────────── # ── Per-symbol 四门参数 ────────────────────────────────────
symbol_gates = (strategy_cfg.get("symbol_gates") or {}).get(self.symbol, {}) symbol_gates = (strategy_cfg.get("symbol_gates") or {}).get(self.symbol, {})
min_vol = float(symbol_gates.get("min_vol_threshold", 0.003)) min_vol = float(symbol_gates.get("min_vol_threshold", 0.002))
whale_usd = float(symbol_gates.get("whale_threshold_usd", 50000)) whale_usd = float(symbol_gates.get("whale_threshold_usd", 50000))
obi_veto = float(symbol_gates.get("obi_veto_threshold", 0.35)) obi_veto = float(symbol_gates.get("obi_veto_threshold", 0.35))
spd_veto = float(symbol_gates.get("spot_perp_divergence_veto", 0.005)) spd_veto = float(symbol_gates.get("spot_perp_divergence_veto", 0.005))
gate_block = None # 门控否决原因None = 全部通过 gate_block = None
# 门1波动率下限 # 门1波动率下限
atr_pct_price = atr / price if price > 0 else 0 atr_pct_price = atr / price if price > 0 else 0
if atr_pct_price < min_vol: if atr_pct_price < min_vol:
gate_block = f"low_vol({atr_pct_price:.4f}<{min_vol})" gate_block = f"low_vol({atr_pct_price:.4f}<{min_vol})"
# ── Direction Layer55分────────────────────────────────── # 门2CVD共振方向门
# cvd_resonance30分fast+mid同向 = 有效方向
if cvd_fast > 0 and cvd_mid > 0: if cvd_fast > 0 and cvd_mid > 0:
direction = "LONG" direction = "LONG"
cvd_resonance = 30 cvd_resonance = 30
@ -780,25 +773,35 @@ class SymbolState:
else: else:
direction = "LONG" if cvd_fast > 0 else "SHORT" direction = "LONG" if cvd_fast > 0 else "SHORT"
cvd_resonance = 0 cvd_resonance = 0
no_direction = True # gate: 方向不一致 → 直接不开仓 no_direction = True
if not gate_block:
gate_block = "no_direction_consensus"
# 门2鲸鱼推力大单净方向需与信号方向一致 # 门3鲸鱼否决BTC用whale_cvd_ratioALT用大单对立
if not gate_block and not no_direction: if not gate_block and not no_direction:
whale_aligned = any( if self.symbol == "BTCUSDT":
(direction == "LONG" and lt[2] == 0 and lt[1] * price >= whale_usd) or # BTC巨鲸CVD净方向与信号方向冲突时否决
(direction == "SHORT" and lt[2] == 1 and lt[1] * price >= whale_usd) whale_cvd = self.whale_cvd_ratio if self._whale_trades else to_float(self.market_indicators.get("tiered_cvd_whale")) or 0.0
for lt in self.recent_large_trades whale_threshold_pct = float(symbol_gates.get("whale_flow_threshold_pct", 0.5)) / 100
) if (direction == "LONG" and whale_cvd < -whale_threshold_pct) or \
whale_adverse = any( (direction == "SHORT" and whale_cvd > whale_threshold_pct):
(direction == "LONG" and lt[2] == 1 and lt[1] * price >= whale_usd) or gate_block = f"whale_cvd_veto({whale_cvd:.3f})"
(direction == "SHORT" and lt[2] == 0 and lt[1] * price >= whale_usd) else:
for lt in self.recent_large_trades # ALTrecent_large_trades 里有对立大单则否决
) whale_adverse = any(
# 有明确对立大单时否决(没有大单时不否决,给机会) (direction == "LONG" and lt[2] == 1 and lt[1] * price >= whale_usd) or
if whale_adverse and not whale_aligned: (direction == "SHORT" and lt[2] == 0 and lt[1] * price >= whale_usd)
gate_block = f"whale_adverse(>${whale_usd/1000:.0f}k)" for lt in self.recent_large_trades
)
whale_aligned = any(
(direction == "LONG" and lt[2] == 0 and lt[1] * price >= whale_usd) or
(direction == "SHORT" and lt[2] == 1 and lt[1] * price >= whale_usd)
for lt in self.recent_large_trades
)
if whale_adverse and not whale_aligned:
gate_block = f"whale_adverse(>${whale_usd/1000:.0f}k)"
# 门3OBI否决优先实时WebSocket值fallback DB # 门4OBI否决实时WS优先fallback DB
obi_raw = self.rt_obi if self.rt_obi != 0.0 else to_float(self.market_indicators.get("obi_depth_10")) obi_raw = self.rt_obi if self.rt_obi != 0.0 else to_float(self.market_indicators.get("obi_depth_10"))
if not gate_block and not no_direction and obi_raw is not None: if not gate_block and not no_direction and obi_raw is not None:
if direction == "LONG" and obi_raw < -obi_veto: if direction == "LONG" and obi_raw < -obi_veto:
@ -806,14 +809,16 @@ class SymbolState:
elif direction == "SHORT" and obi_raw > obi_veto: elif direction == "SHORT" and obi_raw > obi_veto:
gate_block = f"obi_veto({obi_raw:.3f}>{obi_veto})" gate_block = f"obi_veto({obi_raw:.3f}>{obi_veto})"
# 门4期现背离否决优先实时WebSocket值fallback DB # 门5期现背离否决实时WS优先fallback DB
spot_perp_div = self.rt_spot_perp_div if self.rt_spot_perp_div != 0.0 else to_float(self.market_indicators.get("spot_perp_divergence")) spot_perp_div = self.rt_spot_perp_div if self.rt_spot_perp_div != 0.0 else to_float(self.market_indicators.get("spot_perp_divergence"))
if not gate_block and not no_direction and spot_perp_div is not None: if not gate_block and not no_direction and spot_perp_div is not None:
if (direction == "LONG" and spot_perp_div < -spd_veto) or \ if (direction == "LONG" and spot_perp_div < -spd_veto) or \
(direction == "SHORT" and spot_perp_div > spd_veto): (direction == "SHORT" and spot_perp_div > spd_veto):
gate_block = f"spd_veto({spot_perp_div:.4f})" gate_block = f"spd_veto({spot_perp_div:.4f})"
# p99_flow_alignment0/10/20分 gate_passed = gate_block is None
# ── Direction Layer55分─────────────────────────────────
has_adverse_p99 = any( has_adverse_p99 = any(
(direction == "LONG" and lt[2] == 1) or (direction == "SHORT" and lt[2] == 0) (direction == "LONG" and lt[2] == 1) or (direction == "SHORT" and lt[2] == 0)
for lt in self.recent_large_trades for lt in self.recent_large_trades
@ -822,25 +827,17 @@ class SymbolState:
(direction == "LONG" and lt[2] == 0) or (direction == "SHORT" and lt[2] == 1) (direction == "LONG" and lt[2] == 0) or (direction == "SHORT" and lt[2] == 1)
for lt in self.recent_large_trades for lt in self.recent_large_trades
) )
if has_aligned_p99: p99_flow = 20 if has_aligned_p99 else (10 if not has_adverse_p99 else 0)
p99_flow = 20
elif not has_adverse_p99:
p99_flow = 10
else:
p99_flow = 0
# cvd_accel_bonus0/5分
accel_bonus = 5 if ( accel_bonus = 5 if (
(direction == "LONG" and cvd_fast_accel > 0) or (direction == "LONG" and cvd_fast_accel > 0) or
(direction == "SHORT" and cvd_fast_accel < 0) (direction == "SHORT" and cvd_fast_accel < 0)
) else 0 ) else 0
direction_score = min(cvd_resonance + p99_flow + accel_bonus, 55) direction_score = min(cvd_resonance + p99_flow + accel_bonus, 55)
# ── Crowding Layer25分───────────────────────────────── # ── Crowding Layer25分─────────────────────────────────
long_short_ratio = to_float(self.market_indicators.get("long_short_ratio")) long_short_ratio = to_float(self.market_indicators.get("long_short_ratio"))
if long_short_ratio is None: if long_short_ratio is None:
ls_score = 7 # 缺失给中间分 ls_score = 7
elif (direction == "SHORT" and long_short_ratio > 2.0) or (direction == "LONG" and long_short_ratio < 0.5): elif (direction == "SHORT" and long_short_ratio > 2.0) or (direction == "LONG" and long_short_ratio < 0.5):
ls_score = 15 ls_score = 15
elif (direction == "SHORT" and long_short_ratio > 1.5) or (direction == "LONG" and long_short_ratio < 0.7): elif (direction == "SHORT" and long_short_ratio > 1.5) or (direction == "LONG" and long_short_ratio < 0.7):
@ -858,13 +855,12 @@ class SymbolState:
top_trader_score = 10 if top_trader_position >= 0.55 else (0 if top_trader_position <= 0.45 else 5) top_trader_score = 10 if top_trader_position >= 0.55 else (0 if top_trader_position <= 0.45 else 5)
else: else:
top_trader_score = 10 if top_trader_position <= 0.45 else (0 if top_trader_position >= 0.55 else 5) top_trader_score = 10 if top_trader_position <= 0.45 else (0 if top_trader_position >= 0.55 else 5)
crowding_score = min(ls_score + top_trader_score, 25) crowding_score = min(ls_score + top_trader_score, 25)
# ── Environment Layer15分──────────────────────────────── # ── Environment Layer15分──────────────────────────────
environment_score = round(environment_score_raw / 15 * 15) # 已是0~15 environment_score = round(environment_score_raw / 15 * 15)
# ── Auxiliary Layer5分────────────────────────────────── # ── Auxiliary Layer5分────────────────────────────────
coinbase_premium = to_float(self.market_indicators.get("coinbase_premium")) coinbase_premium = to_float(self.market_indicators.get("coinbase_premium"))
if coinbase_premium is None: if coinbase_premium is None:
aux_score = 2 aux_score = 2
@ -877,23 +873,24 @@ class SymbolState:
total_score = min(direction_score + crowding_score + environment_score + aux_score, 100) total_score = min(direction_score + crowding_score + environment_score + aux_score, 100)
total_score = max(0, round(total_score, 1)) total_score = max(0, round(total_score, 1))
# 门控否决时归零分、清方向
gate_passed = gate_block is None
if not gate_passed: if not gate_passed:
total_score = 0 total_score = 0
# whale_cvd for BTC display
whale_cvd_display = (self.whale_cvd_ratio if self._whale_trades else to_float(self.market_indicators.get("tiered_cvd_whale"))) if self.symbol == "BTCUSDT" else None
result.update({ result.update({
"score": total_score, "score": total_score,
"direction": direction if (not no_direction and gate_passed) else None, "direction": direction if (not no_direction and gate_passed) else None,
"atr_value": atr_value, "atr_value": atr_value,
"factors": { "factors": {
"track": "ALT", "track": "BTC" if self.symbol == "BTCUSDT" else "ALT",
"gate_passed": gate_passed, "gate_passed": gate_passed,
"gate_block": gate_block, "gate_block": gate_block,
"atr_pct_price": round(atr_pct_price, 5), "atr_pct_price": round(atr_pct_price, 5),
"obi_raw": obi_raw, "obi_raw": obi_raw,
"spot_perp_div": spot_perp_div, "spot_perp_div": spot_perp_div,
"whale_cvd_ratio": whale_cvd_display,
"direction": { "direction": {
"score": direction_score, "max": 55, "score": direction_score, "max": 55,
"cvd_resonance": cvd_resonance, "p99_flow": p99_flow, "accel_bonus": accel_bonus, "cvd_resonance": cvd_resonance, "p99_flow": p99_flow, "accel_bonus": accel_bonus,
@ -920,114 +917,16 @@ class SymbolState:
self.last_signal_dir[strategy_name] = direction self.last_signal_dir[strategy_name] = direction
return result return result
def _evaluate_v53_alt(self, now_ms: int, strategy_cfg: dict, snapshot: Optional[dict] = None) -> dict:
"""已废弃,由 _evaluate_v53() 统一处理,保留供兼容"""
return self._evaluate_v53(now_ms, strategy_cfg, snapshot)
def _evaluate_v53_btc(self, now_ms: int, strategy_cfg: dict, snapshot: Optional[dict] = None) -> dict: def _evaluate_v53_btc(self, now_ms: int, strategy_cfg: dict, snapshot: Optional[dict] = None) -> dict:
""" """已废弃,由 _evaluate_v53() 统一处理,保留供兼容"""
V5.3 BTC轨评分gate-control逻辑 return self._evaluate_v53(now_ms, strategy_cfg, snapshot)
不用线性总分用条件门控+否决条件决定是否开仓
新特征Phase 2采集后启用tiered_cvd_whale, obi_depth_10, spot_perp_divergence
当前Phase1版本用已有特征填充为数据接入预留扩展点
"""
strategy_name = strategy_cfg.get("name", "v53_btc")
btc_gate = strategy_cfg.get("btc_gate", {})
min_vol = btc_gate.get("min_vol_threshold", 0.002)
obi_veto = btc_gate.get("obi_veto_threshold", 0.30)
spot_perp_veto = btc_gate.get("spot_perp_divergence_veto", 0.003)
snap = snapshot or self.build_evaluation_snapshot(now_ms)
cvd_fast = snap["cvd_fast"]
cvd_mid = snap["cvd_mid"]
price = snap["price"]
atr = snap["atr"]
atr_value = snap.get("atr_value", atr)
atr_pct = snap["atr_pct"]
result = self._empty_result(strategy_name, snap)
if self.warmup or price == 0 or atr == 0:
return result
last_signal_ts = self.last_signal_ts.get(strategy_name, 0)
in_cooldown = now_ms - last_signal_ts < COOLDOWN_MS
block_reason = None
# Gate 1: 波动率门控atr_percent_1h = atr/price
atr_pct_price = atr / price if price > 0 else 0
if atr_pct_price < min_vol:
block_reason = f"low_vol_regime({atr_pct_price:.4f}<{min_vol})"
# Gate 2: 方向门控CVD共振BTC需要更严格
if not block_reason:
if cvd_fast > 0 and cvd_mid > 0:
direction = "LONG"
elif cvd_fast < 0 and cvd_mid < 0:
direction = "SHORT"
else:
block_reason = "no_direction_consensus"
direction = "LONG" if cvd_fast > 0 else "SHORT"
else:
direction = "LONG" if cvd_fast > 0 else "SHORT"
# Gate 3: OBI否决 — 优先用实时WebSocket值回退DB值
obi_raw = self.rt_obi if self.rt_obi != 0.0 else to_float(self.market_indicators.get("obi_depth_10"))
if not block_reason and obi_raw is not None:
# obi_raw: 正值=买单占优,负值=卖单占优,[-1,1]
if direction == "LONG" and obi_raw < -obi_veto:
block_reason = f"obi_imbalance_veto(obi={obi_raw:.3f})"
elif direction == "SHORT" and obi_raw > obi_veto:
block_reason = f"obi_imbalance_veto(obi={obi_raw:.3f})"
# Gate 4: 期现背离否决 — 优先用实时WebSocket值回退DB值
spot_perp_div = self.rt_spot_perp_div if self.rt_spot_perp_div != 0.0 else to_float(self.market_indicators.get("spot_perp_divergence"))
if not block_reason and spot_perp_div is not None:
# spot_perp_div: 绝对背离率如0.005=0.5%
if abs(spot_perp_div) > spot_perp_veto:
# 背离方向与信号方向相反时否决
if (direction == "LONG" and spot_perp_div < -spot_perp_veto) or \
(direction == "SHORT" and spot_perp_div > spot_perp_veto):
block_reason = f"spot_perp_divergence_veto({spot_perp_div:.4f})"
# 所有门控通过后用ALT评分作为BTC综合评分暂用待Phase2换专属特征
gate_passed = block_reason is None
# 复用ALT评分作为参考分不影响门控决策仅供记录
# whale_cvd_ratio 优先用实时计算值
whale_cvd = self.whale_cvd_ratio if self._whale_trades else to_float(self.market_indicators.get("tiered_cvd_whale"))
alt_result = self._evaluate_v53_alt(now_ms, strategy_cfg, snap)
total_score = alt_result["score"] if gate_passed else 0
result.update({
"score": total_score,
"direction": direction if gate_passed else None,
"atr_value": atr_value,
"factors": {
"track": "BTC",
"gate_passed": gate_passed,
"block_reason": block_reason,
"atr_pct_price": round(atr_pct_price, 5),
"obi_raw": obi_raw,
"spot_perp_div": spot_perp_div,
"whale_cvd_ratio": whale_cvd,
"alt_score_ref": alt_result["score"],
# 透传ALT层分数供前端展示
"direction": (alt_result.get("factors") or {}).get("direction"),
"crowding": (alt_result.get("factors") or {}).get("crowding"),
"environment": (alt_result.get("factors") or {}).get("environment"),
"auxiliary": (alt_result.get("factors") or {}).get("auxiliary"),
},
})
strategy_threshold = int(strategy_cfg.get("threshold", 75))
if gate_passed and not in_cooldown and total_score >= strategy_threshold:
result["signal"] = direction
result["tier"] = "standard"
if result["signal"]:
self.last_signal_ts[strategy_name] = now_ms
self.last_signal_dir[strategy_name] = direction
return result
# ─── PG DB操作 ─────────────────────────────────────────────────── # ─── PG DB操作 ───────────────────────────────────────────────────
# ─── PG DB操作 ───────────────────────────────────────────────────
def load_historical(state: SymbolState, window_ms: int): def load_historical(state: SymbolState, window_ms: int):
now_ms = int(time.time() * 1000) now_ms = int(time.time() * 1000)
@ -1088,18 +987,17 @@ def save_feature_event(ts: int, symbol: str, result: dict, strategy: str):
V5.3 专用每次评分后把 raw features + score 层写入 signal_feature_events V5.3 专用每次评分后把 raw features + score 层写入 signal_feature_events
只对 v53_alt / v53_btc 调用其他策略跳过 只对 v53_alt / v53_btc 调用其他策略跳过
""" """
if strategy not in ("v53_alt", "v53_btc"): if not strategy.startswith("v53"):
return return
f = result.get("factors") or {} f = result.get("factors") or {}
track = f.get("track", "ALT") track = f.get("track", "ALT")
side = result.get("direction") or ("LONG" if result.get("score", 0) >= 0 else "SHORT") side = result.get("direction") or ("LONG" if result.get("score", 0) >= 0 else "SHORT")
# ALT层分 score_direction = (f.get("direction") or {}).get("score", 0) if track == "ALT" else (f.get("direction") or {}).get("score", 0)
score_direction = (f.get("direction") or {}).get("score", 0) if track == "ALT" else None score_crowding = (f.get("crowding") or {}).get("score", 0)
score_crowding = (f.get("crowding") or {}).get("score", 0) if track == "ALT" else None score_env = (f.get("environment") or {}).get("score", 0)
score_env = (f.get("environment") or {}).get("score", 0) if track == "ALT" else None score_aux = (f.get("auxiliary") or {}).get("score", 0)
score_aux = (f.get("auxiliary") or {}).get("score", 0) if track == "ALT" else None gate_passed = f.get("gate_passed", True)
gate_passed = f.get("gate_passed") if track == "BTC" else True # ALT轨无gate概念视为通过 block_reason = f.get("gate_block") or f.get("block_reason")
block_reason = f.get("block_reason") if track == "BTC" else None
with get_sync_conn() as conn: with get_sync_conn() as conn:
with conn.cursor() as cur: with conn.cursor() as cur:

View File

@ -1,8 +1,7 @@
{ {
"name": "v53_alt", "name": "v53",
"version": "5.3", "version": "5.3",
"track": "ALT", "description": "V5.3 统一策略BTC/ETH/XRP/SOL: 四层评分 55/25/15/5 + per-symbol 四门控制",
"description": "V5.3 ALT轨ETH/XRP/SOL: 55/25/15/5权重删除确认层per-symbol四门控制",
"threshold": 75, "threshold": 75,
"flip_threshold": 85, "flip_threshold": 85,
"weights": { "weights": {
@ -11,25 +10,21 @@
"environment": 15, "environment": 15,
"auxiliary": 5 "auxiliary": 5
}, },
"direction_sub": {
"cvd_resonance": 30,
"p99_flow_alignment": 20,
"cvd_accel_bonus": 5
},
"crowding_sub": {
"lsr_contrarian": 15,
"top_trader_position": 10
},
"accel_bonus": 5,
"tp_sl": { "tp_sl": {
"sl_multiplier": 2.0, "sl_multiplier": 2.0,
"tp1_multiplier": 1.5, "tp1_multiplier": 1.5,
"tp2_multiplier": 3.0, "tp2_multiplier": 3.0,
"tp_maker": true "tp_maker": true
}, },
"symbols": ["ETHUSDT", "XRPUSDT", "SOLUSDT"], "symbols": ["BTCUSDT", "ETHUSDT", "XRPUSDT", "SOLUSDT"],
"signals": ["cvd", "p99", "accel", "ls_ratio", "top_trader", "oi", "coinbase_premium"],
"symbol_gates": { "symbol_gates": {
"BTCUSDT": {
"min_vol_threshold": 0.002,
"whale_threshold_usd": 100000,
"whale_flow_threshold_pct": 0.5,
"obi_veto_threshold": 0.30,
"spot_perp_divergence_veto": 0.003
},
"ETHUSDT": { "ETHUSDT": {
"min_vol_threshold": 0.003, "min_vol_threshold": 0.003,
"whale_threshold_usd": 50000, "whale_threshold_usd": 50000,

View File

@ -1,29 +0,0 @@
{
"name": "v53_btc",
"version": "5.3",
"track": "BTC",
"description": "V5.3 BTC轨: gate-control逻辑不用线性加分核心特征=tiered_cvd_whale+obi_depth_10+spot_perp_divergence+atr_percent_1h",
"threshold": 75,
"flip_threshold": 85,
"btc_gate": {
"min_vol_threshold": 0.002,
"obi_veto_threshold": 0.30,
"whale_flow_threshold_pct": 0.5,
"spot_perp_divergence_veto": 0.003
},
"weights": {
"direction": 55,
"crowding": 25,
"environment": 15,
"auxiliary": 5
},
"accel_bonus": 5,
"tp_sl": {
"sl_multiplier": 2.0,
"tp1_multiplier": 1.5,
"tp2_multiplier": 3.0,
"tp_maker": true
},
"symbols": ["BTCUSDT"],
"signals": ["cvd", "p99", "accel", "ls_ratio", "top_trader", "oi", "coinbase_premium"]
}