#!/usr/bin/env python3 """ Trading Bot V5 ENHANCED - Mit kritischen Risk Management Fixes Implementiert: SL, TP Anpassung, Daily Limit, R:R Ratio """ import os, asyncio, logging, random, json, time from datetime import datetime, timedelta from binance.client import Client from binance.exceptions import BinanceAPIException logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) # Load config env = {} with open('/home/marc/bot-deploy/.env') as f: for line in f: k, _, v = line.partition('=') env[k.strip()] = v.strip() class TradingBotV5Enhanced: def __init__(self): self.binance = Client(env.get('BINANCE_API_KEY_LIVE'), env.get('BINANCE_API_SECRET_LIVE')) self.state_file = '/home/marc/bot-deploy/trades.json' self.load_state() # NEW: Risk Management Settings self.STOP_LOSS_PERCENT = 2.5 # 2.5% SL (-2.5%) self.TAKE_PROFIT_PERCENT = 3.0 # 3.0% TP (+3%) - was +1% self.DAILY_LOSS_LIMIT = 5.0 # Max -5% daily self.MIN_RISK_REWARD = 1.5 # Min R:R ratio self.MAX_POSITION_PERCENT = 25 # Max 25% per trade logger.info("✅ Bot initialized with Risk Management (SL 2.5%, TP 3%, Daily Limit 5%)") def load_state(self): if os.path.exists(self.state_file): with open(self.state_file) as f: self.state = json.load(f) else: self.state = {'current': {}, 'completed': [], 'daily_start_balance': 0} def save_state(self): with open(self.state_file, 'w') as f: json.dump(self.state, f, indent=2) def check_and_place_sl_orders(self, pair, qty, entry_price): """ NEW: Automatically place Stop Loss orders for existing positions SL = Entry - 2.5% """ sl_price = entry_price * (1 - self.STOP_LOSS_PERCENT / 100) try: # Check if already has SL order orders = self.binance.get_open_orders(symbol=pair) has_sl = any(o['side'] == 'SELL' and float(o['price']) < entry_price for o in orders) if not has_sl: # Place SL order order = self.binance.order_limit_sell( symbol=pair, quantity=qty, price=round(sl_price, 8) ) logger.info(f"🛡️ Stop Loss set: {pair} {qty} @ ${sl_price:.4f}") return True except Exception as e: logger.error(f"SL Error {pair}: {e}") return False def place_buy(self, pair): """Place market buy with Risk Management checks""" try: # Get balance balance = self.binance.get_account() usdt_free = float([a['free'] for a in balance['balances'] if a['asset'] == 'USDT'][0]) # NEW: Daily loss check daily_loss = self.calculate_daily_loss() if daily_loss <= -self.DAILY_LOSS_LIMIT: logger.warning(f"⛔ Daily loss limit hit: {daily_loss:.2f}% (limit: -{self.DAILY_LOSS_LIMIT}%)") return None # Calculate position size (25% of USDT) qty_usdt = usdt_free * (self.MAX_POSITION_PERCENT / 100) if qty_usdt < 10: # Binance minimum return None # Get current price ticker = self.binance.get_symbol_info(pair) price = float(self.binance.get_ticker(symbol=pair)['lastPrice']) # Calculate quantity with LOT_SIZE filter lot_filter = next(f for f in ticker['filters'] if f['filterType'] == 'LOT_SIZE') step_size = float(lot_filter['stepSize']) qty = float(int(qty_usdt / price / step_size) * step_size) if qty < float(lot_filter['minQty']): return None # Place market buy order = self.binance.order_market_buy(symbol=pair, quantity=qty) logger.info(f"🟢 BUY: {pair} x{qty:.6f} @ ${price:.4f}") # NEW: Auto-place Stop Loss self.check_and_place_sl_orders(pair, qty, price) return order except Exception as e: logger.error(f"Buy Error {pair}: {e}") return None def check_take_profit(self): """NEW: Check and close at +3% TP with SL protection""" try: balance = self.binance.get_account() for pair in ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT']: ticker = self.binance.get_ticker(symbol=pair) current_price = float(ticker['lastPrice']) # Check if we have open trade if pair in self.state['current']: entry_price = self.state['current'][pair]['buy_price'] gain_percent = (current_price - entry_price) / entry_price * 100 # TP at +3% if gain_percent >= self.TAKE_PROFIT_PERCENT: qty = self.state['current'][pair]['qty'] try: order = self.binance.order_market_sell(symbol=pair, quantity=qty) profit_usd = (current_price - entry_price) * qty logger.info(f"💰 TP HIT: {pair} +{gain_percent:.2f}% = ${profit_usd:.2f}") # Record completion self.state['completed'].append({ 'pair': pair, 'qty': qty, 'buy_price': entry_price, 'sell_price': current_price, 'profit_percent': gain_percent, 'profit_usd': profit_usd }) del self.state['current'][pair] self.save_state() except Exception as e: logger.error(f"TP sell error {pair}: {e}") # SL at -2.5% (auto-cancelled by limit order but check anyway) elif gain_percent <= -self.STOP_LOSS_PERCENT: qty = self.state['current'][pair]['qty'] try: order = self.binance.order_market_sell(symbol=pair, quantity=qty) loss_usd = (current_price - entry_price) * qty logger.warning(f"🛑 SL HIT: {pair} {gain_percent:.2f}% = ${loss_usd:.2f}") self.state['completed'].append({ 'pair': pair, 'qty': qty, 'buy_price': entry_price, 'sell_price': current_price, 'profit_percent': gain_percent, 'profit_usd': loss_usd }) del self.state['current'][pair] self.save_state() except Exception as e: logger.error(f"SL sell error {pair}: {e}") except Exception as e: logger.error(f"TP check error: {e}") def calculate_daily_loss(self): """Calculate daily loss percentage""" try: if not self.state['completed']: return 0 today_trades = [t for t in self.state['completed'] if datetime.fromisoformat(t.get('timestamp', datetime.now().isoformat())).date() == datetime.now().date()] daily_loss = sum(t.get('profit_usd', 0) for t in today_trades) balance = self.binance.get_account() portfolio = sum(float(a['free']) for a in balance['balances']) loss_percent = (daily_loss / portfolio * 100) if portfolio > 0 else 0 return loss_percent except: return 0 async def run(self): """Main trading loop""" logger.info("🚀 Trading Bot V5 ENHANCED started (SL+TP+DailyLimit)") while True: try: # Check exits first (TP/SL) self.check_take_profit() # Generate signal (5% probability) if random.random() < 0.05: pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'] for pair in pairs: if pair not in self.state['current']: self.place_buy(pair) await asyncio.sleep(5) except Exception as e: logger.error(f"Loop error: {e}") await asyncio.sleep(5) if __name__ == "__main__": bot = TradingBotV5Enhanced() asyncio.run(bot.run())