Files
trading_bot_v4/telegram_trade_bot.py
mindesbunister 97ba6a9856 feat: Add /status command to Telegram bot for position monitoring
- Implemented /status command handler in telegram_command_bot.py
- Shows real-time P&L, entry/current prices, TP/SL levels, position info
- Added TRADING_BOT_URL and API_SECRET_KEY environment variables
- Updated docker-compose.telegram-bot.yml with new env vars
- Bot connects to trading-bot-v4:3000 API via internal Docker network
- Added comprehensive documentation and testing guides
- Command displays formatted position info with emojis (profit/loss indicators)
- Shows 'No open positions' message when no trades active
2025-10-27 12:40:10 +01:00

167 lines
5.9 KiB
Python

#!/usr/bin/env python3
"""
Simple Telegram bot that forwards trade commands to n8n webhook
Install: pip3 install python-telegram-bot requests
Run: python3 telegram_trade_bot.py
"""
import os
import requests
from telegram import Update
from telegram.ext import Application, MessageHandler, CommandHandler, filters, ContextTypes
# Configuration - SET THESE!
TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN', 'YOUR_BOT_TOKEN_HERE')
N8N_WEBHOOK_URL = os.getenv('N8N_WEBHOOK_URL', 'https://your-n8n.com/webhook/manual-trade')
TRADING_BOT_URL = os.getenv('TRADING_BOT_URL', 'http://trading-bot-v4:3000')
API_SECRET_KEY = os.getenv('API_SECRET_KEY', '')
ALLOWED_CHAT_ID = int(os.getenv('TELEGRAM_CHAT_ID', '579304651'))
async def handle_status_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle /status command - show current open positions"""
# Only your chat
if update.message.chat_id != ALLOWED_CHAT_ID:
return
print(f"📊 /status command received")
try:
# Fetch positions from trading bot API
response = requests.get(
f"{TRADING_BOT_URL}/api/trading/positions",
headers={'Authorization': f'Bearer {API_SECRET_KEY}'},
timeout=10
)
if not response.ok:
await update.message.reply_text(f"❌ Error fetching positions: {response.status_code}")
return
data = response.json()
if not data.get('success'):
await update.message.reply_text("❌ Failed to fetch positions")
return
# Check if there are active positions
positions = data.get('positions', [])
if not positions:
await update.message.reply_text("📊 *No open positions*\n\nAll clear! Ready for new signals.", parse_mode='Markdown')
return
# Format position information
for pos in positions:
symbol = pos['symbol']
direction = pos['direction'].upper()
entry = pos['entryPrice']
current = pos['currentPrice']
size = pos['currentSize']
leverage = pos['leverage']
# P&L
pnl_pct = pos['profitPercent']
account_pnl = pos['accountPnL']
unrealized_pnl = pos['unrealizedPnL']
# Targets
sl = pos['stopLoss']
tp1 = pos['takeProfit1']
tp2 = pos['takeProfit2']
tp1_hit = pos['tp1Hit']
# Age
age_min = pos['ageMinutes']
# Build status message
emoji = "🟢" if account_pnl > 0 else "🔴" if account_pnl < 0 else ""
direction_emoji = "📈" if direction == "LONG" else "📉"
message = f"{emoji} *{symbol}* {direction_emoji} {direction}\n\n"
message += f"💰 *P&L:* ${unrealized_pnl:.2f} ({account_pnl:+.2f}% account)\n"
message += f"📊 *Price Change:* {pnl_pct:+.2f}%\n\n"
message += f"*Entry:* ${entry:.4f}\n"
message += f"*Current:* ${current:.4f}\n\n"
message += f"*Targets:*\n"
message += f" TP1: ${tp1:.4f} {'' if tp1_hit else ''}\n"
message += f" TP2: ${tp2:.4f}\n"
message += f" SL: ${sl:.4f}\n\n"
message += f"*Position:* ${size:.2f} @ {leverage}x\n"
message += f"*Age:* {age_min} min"
await update.message.reply_text(message, parse_mode='Markdown')
print(f"✅ Status sent: {len(positions)} position(s)")
except Exception as e:
print(f"❌ Error: {e}")
await update.message.reply_text(f"❌ Error: {str(e)}")
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Forward trade commands to n8n"""
# Only your chat
if update.message.chat_id != ALLOWED_CHAT_ID:
return
text = update.message.text.lower().strip()
# Only process trade commands: buy/sell followed by symbol
if not any(text.startswith(cmd) for cmd in ['buy', 'sell', 'long', 'short']):
return
print(f"📨 {text}")
# Forward to n8n
try:
response = requests.post(
N8N_WEBHOOK_URL,
json={'text': text},
timeout=10
)
if response.ok:
print(f"✅ Sent to n8n")
else:
print(f"❌ Error {response.status_code}")
await update.message.reply_text(f"❌ Error: {response.status_code}")
except Exception as e:
print(f"{e}")
await update.message.reply_text(f"❌ Error: {str(e)}")
def main():
"""Start bot"""
if TELEGRAM_BOT_TOKEN == 'YOUR_BOT_TOKEN_HERE':
print("❌ Set TELEGRAM_BOT_TOKEN environment variable")
print("Example: export TELEGRAM_BOT_TOKEN='your_token'")
return
if N8N_WEBHOOK_URL == 'https://your-n8n.com/webhook/manual-trade':
print("❌ Set N8N_WEBHOOK_URL environment variable")
print("Example: export N8N_WEBHOOK_URL='https://n8n.yourdomain.com/webhook/manual-trade'")
return
print(f"🚀 Telegram Trade Bot Starting...")
print(f"📱 Chat ID: {ALLOWED_CHAT_ID}")
print(f"🔗 Webhook: {N8N_WEBHOOK_URL}")
print(f"🤖 Trading Bot: {TRADING_BOT_URL}")
print(f"\n✅ Commands:")
print(f" /status - Show open positions")
print(f"\n✅ Trade messages:")
print(f" buy sol")
print(f" sell btc")
print(f" buy eth")
print(f" sell sol")
app = Application.builder().token(TELEGRAM_BOT_TOKEN).build()
app.add_handler(CommandHandler("status", handle_status_command))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
print(f"\n🤖 Bot ready! Listening for commands...\n")
app.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == '__main__':
main()