From efbea5448c6953f92377e35398c11a2337839242 Mon Sep 17 00:00:00 2001 From: mike Date: Thu, 23 Jul 2026 21:42:49 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BE=A4=E4=BD=93=E6=8A=95=E7=A5=A8?= =?UTF-8?q?=E5=8A=A0=E8=A7=84=E6=A8=A1=E6=9D=83=E9=87=8D=20log10(size+1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【背景】纯按票数算群体方向,1 个巨鲸 1500 BTC long = 1 票 vs Jasonleo 1400 BTC short = 1 票,2:2 误判分歧。 【修复】每票权重 = strength × log10(size+1) — 规模按对数缩放 - 1500 → 3.18 票 - 800 → 2.90 票 - 500 → 2.70 票 - 100 → 2.00 票(避免小账户=0票) 【验证】BTC 现状 4 个 trader: - long: 巨鲸 3.18 + 麻吉 2.90 = 6.08 - short: Jasonleo 3.15 + 狙击手 2.70 = 5.85 - 比例 1.04x < 1.5x 阈值 → 真实分歧,观望 ✅ --- okx-auto-position/scripts/signal_tracker.py | 345 ++++++++++---------- 1 file changed, 171 insertions(+), 174 deletions(-) diff --git a/okx-auto-position/scripts/signal_tracker.py b/okx-auto-position/scripts/signal_tracker.py index c4181ef..b524d28 100644 --- a/okx-auto-position/scripts/signal_tracker.py +++ b/okx-auto-position/scripts/signal_tracker.py @@ -301,6 +301,177 @@ def get_all_traders_summary(): return "\n".join(lines) +# ─── 多交易员群体决策 ───────────────────────────────────────────────────── + +def get_recent_signals_for_symbol(symbol, limit=20): + """获取某币种最近的信号 (含 trader)""" + conn = init_db() + rows = conn.execute(""" + SELECT trader, symbol, side, leverage, trader_size, trader_pnl, timestamp + FROM confirmed_signals + WHERE symbol = ? + ORDER BY timestamp DESC LIMIT ? + """, (symbol, limit)).fetchall() + conn.close() + return [dict(r) for r in rows] + + +def get_trader_strength(trader): + """获取交易员强度评分 (基于历史胜率)""" + stats = get_trader_stats(trader) + if isinstance(stats, list) and stats: + s = stats[0] + return s.get('strength', 1.0) + return 1.0 # 默认中等 + + +def multi_trader_decision(symbol, signals, our_side=None, our_contracts=0): + """ + 多交易员群体决策 + + signals: 最近的信号列表 [{trader, side, size, pnl, ...}] + our_side: 你当前的持仓方向 (long/short/None) + our_contracts: 你的持仓张数 + + 返回: {action, reason, group_side, confidence, urgent_reverse, suggest_amount} + """ + if not signals: + return { + 'action': 'wait', + 'reason': '无信号', + 'group_side': None, + 'confidence': 0, + 'urgent_reverse': False, + 'suggest_amount': 0 + } + + long_weight = 0 + short_weight = 0 + long_size = 0 + short_size = 0 + trader_votes = {} + + for s in signals: + t = s.get('trader') + if t not in trader_votes: + trader_votes[t] = s + + for trader, sig in trader_votes.items(): + strength = get_trader_strength(trader) + size = float(sig.get('trader_size', 0) or 0) + # 权重 = 强度 × log10(规模+1) — 规模按对数缩放, 避免巨鲸一票定 + size_weight = max(1.0, __import__('math').log10(size + 1)) + side = sig.get('side', '') + if side == 'long': + long_weight += strength * size_weight + long_size += size + elif side == 'short': + short_weight += strength * size_weight + short_size += size + + total_weight = long_weight + short_weight + if total_weight == 0: + return { + 'action': 'wait', + 'reason': '无有效信号', + 'group_side': None, + 'confidence': 0, + 'urgent_reverse': False, + 'suggest_amount': 0 + } + + if long_weight > short_weight * 1.5: + group_side = 'long' + confidence = long_weight / total_weight + elif short_weight > long_weight * 1.5: + group_side = 'short' + confidence = short_weight / total_weight + else: + return { + 'action': 'wait', + 'reason': f'群体分歧 long={long_weight:.1f} short={short_weight:.1f}', + 'group_side': None, + 'confidence': 0.5, + 'urgent_reverse': False, + 'suggest_amount': 0 + } + + urgent_reverse = False + reverse_size = 0 + for trader, sig in trader_votes.items(): + if sig.get('side') != group_side: + sz = float(sig.get('trader_size', 0) or 0) + reverse_size += sz + if sz > 1000: + urgent_reverse = True + + if reverse_size > 1000: + urgent_reverse = True + + suggest_amount = 0 + action = 'hold' + reason_parts = [ + f'群体{group_side.upper()} (置信度 {confidence*100:.0f}%)', + f'long票数={int(long_weight)}, short票数={int(short_weight)}', + f'long总规模={long_size:,.0f}, short总规模={short_size:,.0f}', + ] + + if urgent_reverse and our_contracts > 0: + action = 'reduce_50%' + suggest_amount = round(our_contracts * 0.5, 2) + reason_parts.insert(0, f'⚠️ 紧急反向: 反向总规模 {reverse_size:,.0f}') + elif our_side is None: + action = 'open' + suggest_amount = 1 + reason_parts.append('你无持仓,建议开仓') + elif our_side == group_side: + action = 'add' + suggest_amount = round(our_contracts * confidence * 0.1, 2) + if suggest_amount < 0.01: + suggest_amount = 0.01 + reason_parts.append(f'顺势加仓 10% (跟群体置信度 {confidence*100:.0f}%)') + else: + action = 'reduce_50%' + suggest_amount = round(our_contracts * 0.5, 2) + reason_parts.append(f'你{our_side}与群体{group_side}反向, 减仓 50%') + + return { + 'action': action, + 'reason': ' | '.join(reason_parts), + 'group_side': group_side, + 'confidence': confidence, + 'urgent_reverse': urgent_reverse, + 'suggest_amount': suggest_amount, + 'long_weight': long_weight, + 'short_weight': short_weight, + 'long_size': long_size, + 'short_size': short_size, + 'reverse_size': reverse_size, + } + + +def format_multi_decision(result): + """格式化群体决策输出""" + if result['action'] == 'wait': + return f"⏸️ 观望: {result['reason']}" + + emoji = '🟢' if result['group_side'] == 'long' else '🔴' + urgent = '🚨 ' if result['urgent_reverse'] else '' + action_emoji = { + 'open': '🆕 开仓', + 'add': '➕ 加仓', + 'reduce_50%': '📉 减仓50%', + 'hold': '⏸️ 持有', + }.get(result['action'], result['action']) + + msg = f"""{urgent}{emoji} 群体决策: {action_emoji} {result['suggest_amount']} 张 + +📊 群体方向: {result['group_side'].upper()} (置信度 {result['confidence']*100:.0f}%) +💡 {result['reason']}""" + return msg + + + # CLI if __name__ == '__main__': import sys @@ -354,177 +525,3 @@ if __name__ == '__main__': signals = get_recent_signals_for_symbol(symbol, limit=20) result = multi_trader_decision(symbol, signals, our_side, our_contracts) print(format_multi_decision(result)) - - -# ─── 多交易员群体决策 ───────────────────────────────────────────────────── - -def get_recent_signals_for_symbol(symbol, limit=20): - """获取某币种最近的信号 (含 trader)""" - conn = init_db() - rows = conn.execute(""" - SELECT trader, symbol, side, leverage, trader_size, trader_pnl, timestamp - FROM confirmed_signals - WHERE symbol = ? - ORDER BY timestamp DESC LIMIT ? - """, (symbol, limit)).fetchall() - conn.close() - return [dict(r) for r in rows] - - -def get_trader_strength(trader): - """获取交易员强度评分 (基于历史胜率)""" - stats = get_trader_stats(trader) - if isinstance(stats, list) and stats: - s = stats[0] - return s.get('strength', 1.0) - return 1.0 # 默认中等 - - -def multi_trader_decision(symbol, signals, our_side=None, our_contracts=0): - """ - 多交易员群体决策 - - signals: 最近的信号列表 [{trader, side, size, pnl, ...}] - our_side: 你当前的持仓方向 (long/short/None) - our_contracts: 你的持仓张数 - - 返回: {action, reason, group_side, confidence, urgent_reverse, suggest_amount} - """ - if not signals: - return { - 'action': 'wait', - 'reason': '无信号', - 'group_side': None, - 'confidence': 0, - 'urgent_reverse': False, - 'suggest_amount': 0 - } - - # 1. 计算群体方向 + 加权 - long_weight = 0 - short_weight = 0 - long_size = 0 - short_size = 0 - trader_votes = {} # 每个交易员最新一次信号 - - # 只取每个交易员最新一次信号 (避免重复计票) - for s in signals: - t = s.get('trader') - if t not in trader_votes: - trader_votes[t] = s - - for trader, sig in trader_votes.items(): - strength = get_trader_strength(trader) - size = float(sig.get('trader_size', 0) or 0) - side = sig.get('side', '') - if side == 'long': - long_weight += strength - long_size += size - elif side == 'short': - short_weight += strength - short_size += size - - total_weight = long_weight + short_weight - if total_weight == 0: - return { - 'action': 'wait', - 'reason': '无有效信号', - 'group_side': None, - 'confidence': 0, - 'urgent_reverse': False, - 'suggest_amount': 0 - } - - # 2. 判定群体方向 (1.5x 阈值才确认) - if long_weight > short_weight * 1.5: - group_side = 'long' - confidence = long_weight / total_weight - elif short_weight > long_weight * 1.5: - group_side = 'short' - confidence = short_weight / total_weight - else: - return { - 'action': 'wait', - 'reason': f'群体分歧 long={long_weight:.1f} short={short_weight:.1f}', - 'group_side': None, - 'confidence': 0.5, - 'urgent_reverse': False, - 'suggest_amount': 0 - } - - # 3. 紧急反向检测: 大规模反向信号 (>1000 BTC 或总反向 > 1000) - urgent_reverse = False - reverse_size = 0 - for trader, sig in trader_votes.items(): - if sig.get('side') != group_side: - sz = float(sig.get('trader_size', 0) or 0) - reverse_size += sz - if sz > 1000: # 单交易员大规模反向 - urgent_reverse = True - - if reverse_size > 1000: - urgent_reverse = True - - # 4. 决定动作 - suggest_amount = 0 - action = 'hold' - reason_parts = [ - f'群体{group_side.upper()} (置信度 {confidence*100:.0f}%)', - f'long票数={int(long_weight)}, short票数={int(short_weight)}', - f'long总规模={long_size:,.0f}, short总规模={short_size:,.0f}', - ] - - if urgent_reverse and our_contracts > 0: - action = 'reduce_50%' - suggest_amount = round(our_contracts * 0.5, 2) - reason_parts.insert(0, f'⚠️ 紧急反向: 反向总规模 {reverse_size:,.0f}') - elif our_side is None: - action = 'open' - suggest_amount = 1 # 最小开仓 - reason_parts.append('你无持仓,建议开仓') - elif our_side == group_side: - action = 'add' - # 顺势加 10% 仓位 - suggest_amount = round(our_contracts * confidence * 0.1, 2) - if suggest_amount < 0.01: - suggest_amount = 0.01 - reason_parts.append(f'顺势加仓 10% (跟群体置信度 {confidence*100:.0f}%)') - else: # our_side != group_side - action = 'reduce_50%' - suggest_amount = round(our_contracts * 0.5, 2) - reason_parts.append(f'你{our_side}与群体{group_side}反向, 减仓 50%') - - return { - 'action': action, - 'reason': ' | '.join(reason_parts), - 'group_side': group_side, - 'confidence': confidence, - 'urgent_reverse': urgent_reverse, - 'suggest_amount': suggest_amount, - 'long_weight': long_weight, - 'short_weight': short_weight, - 'long_size': long_size, - 'short_size': short_size, - 'reverse_size': reverse_size, - } - - -def format_multi_decision(result): - """格式化群体决策输出""" - if result['action'] == 'wait': - return f"⏸️ 观望: {result['reason']}" - - emoji = '🟢' if result['group_side'] == 'long' else '🔴' - urgent = '🚨 ' if result['urgent_reverse'] else '' - action_emoji = { - 'open': '🆕 开仓', - 'add': '➕ 加仓', - 'reduce_50%': '📉 减仓50%', - 'hold': '⏸️ 持有', - }.get(result['action'], result['action']) - - msg = f"""{urgent}{emoji} 群体决策: {action_emoji} {result['suggest_amount']} 张 - -📊 群体方向: {result['group_side'].upper()} (置信度 {result['confidence']*100:.0f}%) -💡 {result['reason']}""" - return msg