feat: 多交易员群体决策 multi_trader_decision

【功能】同币种多交易员时,用加权群体决策替代单信号跟随

【算法】
1. 收集币种最近 20 个信号,按 trader 去重
2. 每个交易员按 strength 权重 + size 加权
3. long/short 票数比 > 1.5x 才确认群体方向
4. 反向信号总规模 > 1000 或单交易员 > 1000 触发紧急反向
5. 顺势加 10% / 反向减 50% / 无持仓开仓 1 张

【用法】python3 signal_tracker.py multi <symbol> [our_side] [our_contracts]

【测试】4 场景全过: 顺势加/反向减/无持仓开/分歧观望 
This commit is contained in:
2026-07-23 21:39:22 +08:00
parent 1fe4509307
commit b22905a5f3
+183
View File
@@ -345,3 +345,186 @@ if __name__ == '__main__':
elif cmd == 'summary':
print(get_all_traders_summary())
elif cmd == 'multi' and len(sys.argv) >= 3:
# 群体决策: multi <symbol> [our_side] [our_contracts]
symbol = sys.argv[2]
our_side = sys.argv[3] if len(sys.argv) > 3 else None
our_contracts = float(sys.argv[4]) if len(sys.argv) > 4 else 0
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