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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user