feat: extend RT-WS to ETH/XRP/SOL + add per-symbol 4-gate control to v53_alt
This commit is contained in:
parent
57f749c094
commit
1e982c48f9
@ -317,8 +317,8 @@ class SymbolState:
|
||||
self.last_signal_dir: dict[str, str] = {}
|
||||
self.recent_large_trades: deque = deque()
|
||||
# ── Phase 2 实时内存字段(由后台WebSocket协程更新)──────────
|
||||
self.rt_obi: float = 0.0 # 订单簿失衡[-1,1]
|
||||
self.rt_spot_perp_div: float = 0.0 # 期现背离(spot-mark)/mark
|
||||
self.rt_obi: float = 0.0 # 订单簿失衡[-1,1](实时WebSocket,所有symbol)
|
||||
self.rt_spot_perp_div: float = 0.0 # 期现背离(spot-mark)/mark(实时WebSocket,所有symbol)
|
||||
# tiered_cvd_whale:按成交额分档,实时累计(最近15分钟窗口)
|
||||
self._whale_trades: deque = deque() # (time_ms, usd_val, is_sell)
|
||||
self.WHALE_WINDOW_MS: int = 15 * 60 * 1000 # 15分钟
|
||||
@ -753,6 +753,20 @@ class SymbolState:
|
||||
last_signal_ts = self.last_signal_ts.get(strategy_name, 0)
|
||||
in_cooldown = now_ms - last_signal_ts < COOLDOWN_MS
|
||||
|
||||
# ── Per-symbol 四门参数(从 strategy_cfg.symbol_gates 读取)──────────
|
||||
symbol_gates = (strategy_cfg.get("symbol_gates") or {}).get(self.symbol, {})
|
||||
min_vol = float(symbol_gates.get("min_vol_threshold", 0.003))
|
||||
whale_usd = float(symbol_gates.get("whale_threshold_usd", 50000))
|
||||
obi_veto = float(symbol_gates.get("obi_veto_threshold", 0.35))
|
||||
spd_veto = float(symbol_gates.get("spot_perp_divergence_veto", 0.005))
|
||||
|
||||
gate_block = None # 门控否决原因,None = 全部通过
|
||||
|
||||
# 门1:波动率下限
|
||||
atr_pct_price = atr / price if price > 0 else 0
|
||||
if atr_pct_price < min_vol:
|
||||
gate_block = f"low_vol({atr_pct_price:.4f}<{min_vol})"
|
||||
|
||||
# ── Direction Layer(55分)──────────────────────────────────
|
||||
# cvd_resonance(30分):fast+mid同向 = 有效方向
|
||||
if cvd_fast > 0 and cvd_mid > 0:
|
||||
@ -768,6 +782,37 @@ class SymbolState:
|
||||
cvd_resonance = 0
|
||||
no_direction = True # gate: 方向不一致 → 直接不开仓
|
||||
|
||||
# 门2:鲸鱼推力(大单净方向需与信号方向一致)
|
||||
if not gate_block and not no_direction:
|
||||
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
|
||||
)
|
||||
whale_adverse = any(
|
||||
(direction == "LONG" and lt[2] == 1 and lt[1] * price >= whale_usd) or
|
||||
(direction == "SHORT" and lt[2] == 0 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)"
|
||||
|
||||
# 门3:OBI否决(优先实时WebSocket值,fallback DB)
|
||||
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 direction == "LONG" and obi_raw < -obi_veto:
|
||||
gate_block = f"obi_veto({obi_raw:.3f}<-{obi_veto})"
|
||||
elif direction == "SHORT" and obi_raw > obi_veto:
|
||||
gate_block = f"obi_veto({obi_raw:.3f}>{obi_veto})"
|
||||
|
||||
# 门4:期现背离否决(优先实时WebSocket值,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"))
|
||||
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 \
|
||||
(direction == "SHORT" and spot_perp_div > spd_veto):
|
||||
gate_block = f"spd_veto({spot_perp_div:.4f})"
|
||||
|
||||
# p99_flow_alignment(0/10/20分)
|
||||
has_adverse_p99 = any(
|
||||
(direction == "LONG" and lt[2] == 1) or (direction == "SHORT" and lt[2] == 0)
|
||||
@ -833,12 +878,22 @@ class SymbolState:
|
||||
total_score = min(direction_score + crowding_score + environment_score + aux_score, 100)
|
||||
total_score = max(0, round(total_score, 1))
|
||||
|
||||
# 门控否决时归零分、清方向
|
||||
gate_passed = gate_block is None
|
||||
if not gate_passed:
|
||||
total_score = 0
|
||||
|
||||
result.update({
|
||||
"score": total_score,
|
||||
"direction": direction if not no_direction else None,
|
||||
"direction": direction if (not no_direction and gate_passed) else None,
|
||||
"atr_value": atr_value,
|
||||
"factors": {
|
||||
"track": "ALT",
|
||||
"gate_passed": gate_passed,
|
||||
"gate_block": gate_block,
|
||||
"atr_pct_price": round(atr_pct_price, 5),
|
||||
"obi_raw": obi_raw,
|
||||
"spot_perp_div": spot_perp_div,
|
||||
"direction": {
|
||||
"score": direction_score, "max": 55,
|
||||
"cvd_resonance": cvd_resonance, "p99_flow": p99_flow, "accel_bonus": accel_bonus,
|
||||
@ -852,7 +907,7 @@ class SymbolState:
|
||||
},
|
||||
})
|
||||
|
||||
if not no_direction and not in_cooldown:
|
||||
if not no_direction and gate_passed and not in_cooldown:
|
||||
if total_score >= flip_threshold:
|
||||
result["signal"] = direction
|
||||
result["tier"] = "heavy"
|
||||
@ -1314,14 +1369,15 @@ async def _ws_spot_perp_stream(symbol: str, state):
|
||||
await asyncio.gather(read_spot(), read_perp())
|
||||
|
||||
async def _realtime_ws_runner(states: dict):
|
||||
"""统一启动所有实时WebSocket协程,目前只给BTC"""
|
||||
btc_state = states.get("BTCUSDT")
|
||||
if btc_state is None:
|
||||
return
|
||||
await asyncio.gather(
|
||||
_ws_obi_stream("BTCUSDT", btc_state),
|
||||
_ws_spot_perp_stream("BTCUSDT", btc_state),
|
||||
)
|
||||
"""统一启动所有实时WebSocket协程,BTC + ALT (ETH/XRP/SOL)"""
|
||||
coros = []
|
||||
for sym, state in states.items():
|
||||
# OBI流:所有symbol都接(perp depth10)
|
||||
coros.append(_ws_obi_stream(sym, state))
|
||||
# 期现背离流:只有有现货+合约的币种(BTC/ETH/XRP/SOL都有)
|
||||
coros.append(_ws_spot_perp_stream(sym, state))
|
||||
if coros:
|
||||
await asyncio.gather(*coros)
|
||||
|
||||
def start_realtime_ws(states: dict):
|
||||
"""在独立线程里跑asyncio event loop,驱动实时WebSocket采集"""
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"name": "v53_alt",
|
||||
"version": "5.3",
|
||||
"track": "ALT",
|
||||
"description": "V5.3 ALT轨(ETH/XRP/SOL): 55/25/15/5权重,删除确认层(解决CVD双重计分),独立BTC走gate-control",
|
||||
"description": "V5.3 ALT轨(ETH/XRP/SOL): 55/25/15/5权重,删除确认层,per-symbol四门控制",
|
||||
"threshold": 75,
|
||||
"flip_threshold": 85,
|
||||
"weights": {
|
||||
@ -28,5 +28,25 @@
|
||||
"tp_maker": true
|
||||
},
|
||||
"symbols": ["ETHUSDT", "XRPUSDT", "SOLUSDT"],
|
||||
"signals": ["cvd", "p99", "accel", "ls_ratio", "top_trader", "oi", "coinbase_premium"]
|
||||
"signals": ["cvd", "p99", "accel", "ls_ratio", "top_trader", "oi", "coinbase_premium"],
|
||||
"symbol_gates": {
|
||||
"ETHUSDT": {
|
||||
"min_vol_threshold": 0.003,
|
||||
"whale_threshold_usd": 50000,
|
||||
"obi_veto_threshold": 0.35,
|
||||
"spot_perp_divergence_veto": 0.005
|
||||
},
|
||||
"SOLUSDT": {
|
||||
"min_vol_threshold": 0.006,
|
||||
"whale_threshold_usd": 20000,
|
||||
"obi_veto_threshold": 0.45,
|
||||
"spot_perp_divergence_veto": 0.008
|
||||
},
|
||||
"XRPUSDT": {
|
||||
"min_vol_threshold": 0.004,
|
||||
"whale_threshold_usd": 30000,
|
||||
"obi_veto_threshold": 0.40,
|
||||
"spot_perp_divergence_veto": 0.006
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user