From 1fe4509307c2f50735cca303497af41b504d5a12 Mon Sep 17 00:00:00 2001 From: mike Date: Thu, 23 Jul 2026 21:28:37 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20parse=5Fsignal=20=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E3=80=90=E4=BB=93=E4=BD=8D=E3=80=91=E5=AD=97=E6=AE=B5+unit?= =?UTF-8?q?=E8=BF=BD=E8=B8=AA+=E5=87=8F=E5=B9=85=E8=AE=A1=E7=AE=97+?= =?UTF-8?q?=E8=B7=9F=E5=8D=95=E5=BB=BA=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【背景】Jasonleo 9次BTC减仓信号,process_signal.py 的 size regex 只匹配【仓位大小】,不匹配【仓位】。导致推信号显示 size='?',无法算减幅,agent 推减仓建议全错位。 【修复】 1. parse_signal.py:67 - size regex 兼容【仓位(?:大小)?】 2. parse_signal.py:68 - 新增 unit 字段(BTC/USDT/张) 3. parse_signal.py:285 - 推信号时显示 size+unit 4. parse_signal.py:294 - 跟单建议: fetch 真实持仓+算大佬减幅+同比例跟单 5. signal_tracker.py:158 - format_comparison 智能显示整数/小数 + 减幅% 【测试】1450.719 BTC ✅, 49.958(无单位)✅, 10000 USDT ✅ 【验证】format_comparison 减幅 -7.1% 显示正确 --- okx-auto-position/scripts/process_signal.py | 41 +++++++++++++++++++-- okx-auto-position/scripts/signal_tracker.py | 21 ++++++++--- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/okx-auto-position/scripts/process_signal.py b/okx-auto-position/scripts/process_signal.py index 7f03cc8..67c46ee 100644 --- a/okx-auto-position/scripts/process_signal.py +++ b/okx-auto-position/scripts/process_signal.py @@ -30,7 +30,7 @@ DEDUP_DB = Path.home() / ".hermes/trading/signal_dedup.db" # Import signal tracker sys.path.insert(0, str(SKILL_DIR / "scripts")) -from signal_tracker import format_comparison, record_signal as _tracker_record, record_confirmed, format_trader_rating +from signal_tracker import format_comparison, record_signal as _tracker_record, record_confirmed, format_trader_rating, get_last_signal # ─── 解析 ──────────────────────────────────────────────────────────────── @@ -64,7 +64,8 @@ def parse_signal(text): 'symbol': r'【币种】\s*[::]?\s*(\S+)', 'side': r'【方向】\s*[::]?\s*(做多|做空)', 'leverage':r'【杠杆】\s*[::]?\s*(\d+)', - 'size': r'【仓位大小】\s*[::]?\s*([\d,.]+)', + 'size': r'【仓位(?:大小)?】\s*[::]?\s*([\d,.]+)', # 兼容 【仓位】和【仓位大小】 + 'unit': r'【仓位(?:大小)?】\s*[::]?\s*[\d,.]+\s+(BTC|USDT|ETH|SOL|DOGE|张|USD)\b', # 严格匹配已知单位 (必需) 'value': r'【仓位价值】\s*[::]?\s*\$?\s*([\d,.]+)', 'entry': r'【开仓价】\s*[::]?\s*([\d,.]+)', 'current': r'【当前价】\s*[::]?\s*([\d,.]+)', @@ -75,7 +76,7 @@ def parse_signal(text): for key, pattern in extractors.items(): m = re.search(pattern, text) if m: - fields[key] = m.group(1).replace(',', '') + fields[key] = m.group(1).replace(',', '') if key != 'unit' else m.group(1) # 清理symbol if 'symbol' in fields: @@ -253,6 +254,7 @@ def format_message(fields, rec, signal_type): leverage = fields.get('leverage', '10') trader = fields.get('trader', '?') size = fields.get('size', '?') + unit = fields.get('unit', '') # 仓位单位: BTC/USDT/张 value = fields.get('value', '?') entry_price = fields.get('entry', '?') pnl_str = fields.get('pnl', '0') @@ -281,15 +283,45 @@ def format_message(fields, rec, signal_type): type_label = type_labels.get(signal_type, signal_type) # 信号源仓位(只展示,不参与计算) - src_info = f"📊 {trader} {size} {symbol}(价值${value})← 信号源,非你的仓位" + src_info = f"📊 {trader} {size} {unit} {symbol}(价值${value})← 信号源,非你的仓位" # 仓位变化对比 + current_size = 0 try: current_size = float(fields.get('size', '0').replace(',', '')) comparison = format_comparison(trader, symbol, current_size) except: comparison = "" + # 跟单建议: fetch 真实持仓 + 算比例 + our_position = None + our_advice = "" + try: + from okx_position_advisor import get_positions + positions = get_positions(symbol=symbol) + for p in positions: + if p.get('symbol') == f"{symbol}/USDT:USDT" or p.get('symbol') == symbol: + our_position = p + break + if our_position and current_size > 0: + our_contracts = float(our_position.get('contracts', 0)) + # 算大佬减仓比例 + last_signal = get_last_signal(trader, symbol) + last_size = (last_signal or {}).get('trader_size', 0) + if last_size and last_size > 0: + trader_delta_pct = (current_size - last_size) / last_size * 100 + if trader_delta_pct < -0.5: # 大佬减仓 > 0.5% + # 跟同比例 + our_reduce = our_contracts * abs(trader_delta_pct) / 100 + # 取整 (BTC min=0.01张, 其他min=1张) + if symbol == 'BTC': + our_reduce = max(0.01, round(our_reduce, 2)) + else: + our_reduce = max(1, round(our_reduce)) + our_advice = f"\n🎯 跟单建议: 大佬减 {abs(trader_delta_pct):.1f}%, 你跟减 {our_reduce} 张 ({our_contracts} → {our_contracts - our_reduce:.2f})" + except Exception as e: + our_advice = f"\n⚠️ 跟单计算跳过: {e}" + # 交易员评分 try: trader_rating = format_trader_rating(trader) @@ -304,6 +336,7 @@ def format_message(fields, rec, signal_type): 📊 仓位变化 {comparison} +{our_advice} {trader_rating} diff --git a/okx-auto-position/scripts/signal_tracker.py b/okx-auto-position/scripts/signal_tracker.py index ac30179..d4590ec 100644 --- a/okx-auto-position/scripts/signal_tracker.py +++ b/okx-auto-position/scripts/signal_tracker.py @@ -155,17 +155,28 @@ def format_comparison(trader, symbol, current_size): """格式化对比信息""" last_size, desc = compare_position(trader, symbol, current_size) + # 智能显示: 整数直接显示, 小数保留 2-3 位 + def _fmt(n): + if n is None: + return "?" + if n == int(n) and abs(n) >= 10: + return f"{int(n):,}" + return f"{n:,.2f}" + if last_size is None: - return f"• {trader} {symbol}: 首次出现,仓位 {current_size:,.0f}" + return f"• {trader} {symbol}: 首次出现,仓位 {_fmt(current_size)}" if "不变" in desc: - return f"• {trader} {symbol}: 仓位不变 {current_size:,.0f}" + return f"• {trader} {symbol}: 仓位不变 {_fmt(current_size)}" elif "加仓" in desc: - return f"• 📈 {trader} {symbol}: {last_size:,.0f} → {current_size:,.0f}({desc})" + return f"• 📈 {trader} {symbol}: {_fmt(last_size)} → {_fmt(current_size)}({desc})" elif "减仓" in desc: - return f"• 📉 {trader} {symbol}: {last_size:,.0f} → {current_size:,.0f}({desc})" + delta_pct = 0 + if last_size and last_size > 0: + delta_pct = (current_size - last_size) / last_size * 100 + return f"• 📉 {trader} {symbol}: {_fmt(last_size)} → {_fmt(current_size)}(减幅 {delta_pct:+.1f}%)" else: - return f"• {trader} {symbol}: {last_size:,.0f} → {current_size:,.0f}({desc})" + return f"• {trader} {symbol}: {_fmt(last_size)} → {_fmt(current_size)}({desc})" # ─── 交易员统计 ──────────────────────────────────────────────────────────