- Trading skills (OKX, dividend, lottery, quantitative) - Creative skills (ASCII art, diagrams, video) - Development skills (GitHub, debugging, TDD) - Research skills (arXiv, blog monitoring) - Productivity skills (email, documents, notes) - MCP integration skills - Custom user skills
171 lines
5.6 KiB
Python
171 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
修正跟单方案金额。
|
||
用法: echo "原始信号文本" | python3 fix_recommendation.py
|
||
或: python3 fix_recommendation.py "原始信号文本"
|
||
|
||
从信号文本提取币种/方向/杠杆,调advisor脚本获取正确金额,替换原消息中的跟单方案部分。
|
||
"""
|
||
import sys
|
||
import re
|
||
import json
|
||
import subprocess
|
||
from pathlib import Path
|
||
|
||
ADVISOR = Path.home() / ".hermes/skills/trading/okx-auto-position/scripts/okx_position_advisor.py"
|
||
|
||
def extract_from_signal(text):
|
||
"""从信号文本提取关键字段"""
|
||
fields = {}
|
||
|
||
# 币种
|
||
m = re.search(r'跟单建议\s*\|\s*(\w+)', text)
|
||
if m:
|
||
fields['symbol'] = m.group(1)
|
||
|
||
# 方向
|
||
if '做多' in text:
|
||
fields['side'] = 'long'
|
||
elif '做空' in text:
|
||
fields['side'] = 'short'
|
||
|
||
# 杠杆
|
||
m = re.search(r'(\d+)x', text)
|
||
if m:
|
||
fields['leverage'] = m.group(1)
|
||
|
||
# 交易员
|
||
m = re.search(r'📊\s*(\S+)', text)
|
||
if m:
|
||
fields['trader'] = m.group(1)
|
||
|
||
# 交易员仓位
|
||
m = re.search(r'📊\s*\S+\s+([\d,.]+\s*\w+)', text)
|
||
if m:
|
||
fields['trader_pos'] = m.group(1)
|
||
|
||
# 交易员价值
|
||
m = re.search(r'(价值\$?([\d,.]+))', text)
|
||
if m:
|
||
fields['trader_value'] = m.group(1)
|
||
|
||
# 入场价
|
||
m = re.search(r'入场:\s*\$?([\d,.]+)', text)
|
||
if m:
|
||
fields['entry'] = m.group(1).replace(',', '')
|
||
|
||
# 浮盈
|
||
m = re.search(r'浮[盈亏]:\s*([+-]?\$?[\d,.]+)', text)
|
||
if m:
|
||
fields['pnl'] = m.group(1).replace('$', '').replace(',', '')
|
||
|
||
return fields
|
||
|
||
def run_advisor(symbol, side, leverage):
|
||
"""调advisor脚本获取正确数据"""
|
||
# Don't add /USDT - advisor handles symbol format internally
|
||
cmd = ['python3', str(ADVISOR), '--symbol', symbol, '--side', side, '--leverage', str(leverage), '--json']
|
||
|
||
try:
|
||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30, cwd=str(ADVISOR.parent))
|
||
if result.returncode == 0:
|
||
return json.loads(result.stdout)
|
||
except Exception as e:
|
||
return {'error': str(e)}
|
||
return {'error': 'advisor failed'}
|
||
|
||
def rebuild_message(original, fields, rec):
|
||
"""用正确数据重建消息"""
|
||
if 'error' in rec:
|
||
return f"⚠️ advisor错误: {rec['error']}\n\n{original}"
|
||
|
||
symbol = fields.get('symbol', '?')
|
||
side_cn = '做多' if fields.get('side') == 'long' else '做空'
|
||
emoji = '🟩' if fields.get('side') == 'long' else '🟥'
|
||
leverage = fields.get('leverage', '10')
|
||
trader = fields.get('trader', '?')
|
||
trader_pos = fields.get('trader_pos', '?')
|
||
trader_value = fields.get('trader_value', '?')
|
||
entry = fields.get('entry', '?')
|
||
pnl = fields.get('pnl', '0')
|
||
|
||
# 性价比
|
||
cc = rec.get('cost_check', {})
|
||
rr = cc.get('rr_ratio', rec.get('rr', 0))
|
||
profit = cc.get('profit_amount', rec.get('tp_pnl', 0))
|
||
fee = cc.get('fee_cost', 0)
|
||
fee_pct = cc.get('fee_pct', 0)
|
||
net = cc.get('net_profit', 0)
|
||
rating_emoji = cc.get('rating_emoji', '⚠️')
|
||
rating_text = cc.get('rating_text', '未知')
|
||
|
||
pnl_float = float(pnl) if pnl else 0
|
||
pnl_emoji = '🔥' if pnl_float > 0 else '🔴'
|
||
pnl_sign = '+' if pnl_float > 0 else ''
|
||
|
||
# 提取原始消息的趋势分析和ATR部分
|
||
trend_match = re.search(r'(📈 趋势分析.*?)(?=🛡️)', original, re.DOTALL)
|
||
trend_block = trend_match.group(1).strip() if trend_match else "📈 趋势分析\n• 数据加载中"
|
||
|
||
atr_match = re.search(r'(🛡️ ATR检查.*?)(?=📐|🎯|回复)', original, re.DOTALL)
|
||
atr_block = atr_match.group(1).strip() if atr_match else "🛡️ ATR检查\n• 数据加载中"
|
||
|
||
msg = f"""⚡ 跟单建议 | {symbol} {side_cn} {emoji} {leverage}x
|
||
|
||
📊 {trader} {trader_pos}(价值${trader_value})← 信号源,非你的仓位
|
||
入场: ${entry} | 当前: ${rec['price']}
|
||
浮盈: {pnl_sign}{pnl_float:.0f} {pnl_emoji} | 强平距: ${rec.get('liq_price', '?')}
|
||
|
||
{trend_block}
|
||
|
||
{atr_block}
|
||
|
||
📐 性价比检查(基于你的推荐仓位)
|
||
• 你的仓位: {rec['contracts']}张(保证金{rec['margin']:.2f} USDT)
|
||
• 盈亏比: {rr}:1 {'✅' if rr >= 2 else '⚠️' if rr >= 1.5 else '❌'}
|
||
• 盈利额: +{profit:.2f} USDT {'✅' if profit >= 10 else '❌ <10U保底'}
|
||
• 手续费: {fee:.2f} USDT ({fee_pct:.1f}%) {'✅' if fee_pct < 5 else '❌'}
|
||
• 净盈利: {net:.2f} USDT {'✅' if net >= 10 else '❌'}
|
||
• 评级: {rating_emoji} {rating_text}
|
||
|
||
🎯 跟单方案(基于你的账户数据)
|
||
• 入场: ${rec['price']}(市价)
|
||
• 止损: ${rec['sl_price']}(-{rec['sl_pct']:.1f}%,-{rec['sl_pnl']:.2f} USDT)
|
||
• 止盈: ${rec['tp_price']}(+{rec['tp_pct']:.1f}%,+{rec['tp_pnl']:.2f} USDT)
|
||
• 仓位: {rec['contracts']}张(保证金{rec['margin']:.2f} USDT)
|
||
• 强平: ${rec.get('liq_price', '?')}
|
||
|
||
回复 Y 确认跟单 / N 取消"""
|
||
|
||
return msg
|
||
|
||
def main():
|
||
# Get input
|
||
if len(sys.argv) > 1:
|
||
text = ' '.join(sys.argv[1:])
|
||
else:
|
||
text = sys.stdin.read()
|
||
|
||
if not text.strip():
|
||
print("用法: python3 fix_recommendation.py '信号文本'")
|
||
return
|
||
|
||
# Extract fields
|
||
fields = extract_from_signal(text)
|
||
|
||
if not fields.get('symbol') or not fields.get('side'):
|
||
print("⚠️ 无法解析信号文本")
|
||
print(text)
|
||
return
|
||
|
||
# Run advisor
|
||
leverage = fields.get('leverage', '10')
|
||
rec = run_advisor(fields['symbol'], fields['side'], leverage)
|
||
|
||
# Rebuild message
|
||
result = rebuild_message(text, fields, rec)
|
||
print(result)
|
||
|
||
if __name__ == '__main__':
|
||
main()
|