fix: parse_signal 兼容【仓位】字段+unit追踪+减幅计算+跟单建议
【背景】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% 显示正确
This commit is contained in:
@@ -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}
|
||||
|
||||
|
||||
@@ -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})"
|
||||
|
||||
# ─── 交易员统计 ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user