diff --git a/src/main_ml.py b/src/main_ml.py index 5f91d58..c4da28d 100644 --- a/src/main_ml.py +++ b/src/main_ml.py @@ -1,28 +1,31 @@ #!/usr/bin/env python3 -import os, asyncio, aiohttp +import os, asyncio, aiohttp, logging, random from datetime import datetime from binance.client import Client -from dotenv import load_dotenv -import logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) -load_dotenv("/home/marc/bot-deploy/.env") + +# Load env +with open("/home/marc/bot-deploy/.env") as f: + env = {} + for line in f: + k, _, v = line.partition("=") + env[k.strip()] = v.strip() class Bot: def __init__(self): - self.binance = Client(os.getenv("BINANCE_API_KEY_LIVE"), os.getenv("BINANCE_API_SECRET_LIVE")) - self.pairs = ["BTCUSDT","ETHUSDT","SOLUSDT","BNBUSDT","XRPUSDT"] + self.binance = Client(env.get("BINANCE_API_KEY_LIVE"), env.get("BINANCE_API_SECRET_LIVE")) self.current_trades = {} self.completed_trades = [] self.balance = {} self.trades_today = 0 self.daily_pnl = 0.0 - self.wins_today = 0 - self.dashboard_url = "http://localhost:7000/api/update" - logger.info("Bot CLEAN initialized") + self.dashboard = "http://localhost:7000/api/update" + logger.info("🤖 Bot initialized - CLEAN") - async def update_balance(self): + def get_balance(self): + """GET BALANCE FROM BINANCE (SYNC)""" try: acc = self.binance.get_account() self.balance = {} @@ -30,54 +33,82 @@ class Bot: free, locked = float(a["free"]), float(a["locked"]) if free + locked > 0: self.balance[a["asset"]] = {"free": free, "locked": locked, "total": free+locked} + usdt_free = self.balance.get("USDT", {}).get("free", 0) + logger.info(f"💰 Balance updated: USDT ") except Exception as e: logger.error(f"Balance error: {e}") - async def place_buy(self, pair, price): + def place_buy(self, pair): + """PLACE BUY ORDER""" try: - usdt = self.balance.get("USDT", {}).get("free", 0) - qty_usdt = usdt * 0.5 + usdt_free = self.balance.get("USDT", {}).get("free", 0) + qty_usdt = usdt_free * 0.5 + if qty_usdt < 10: return None + + ticker = self.binance.get_symbol_ticker(symbol=pair) + price = float(ticker["price"]) + qty = round(qty_usdt / price, 4) + if qty <= 0: + return None + order = self.binance.order_market_buy(symbol=pair, quantity=qty) - logger.info(f"Buy: {pair} x{qty:.4f} @ ${price:.2f}") + + logger.info(f"🟢 BUY: {pair} x{qty:.4f} @ ") + self.current_trades[pair] = { - "qty": qty, "buy_price": price, "buy_time": datetime.now().isoformat(), "order_id": order["orderId"] + "qty": qty, + "buy_price": price, + "buy_time": datetime.now().isoformat(), + "order_id": order["orderId"] } self.trades_today += 1 return order except Exception as e: - logger.error(f"Buy error {pair}: {e}") + logger.error(f"Buy {pair} error: {e}") return None - async def check_tp(self): + def check_tp(self): + """CHECK +1% TAKE PROFIT""" remove = [] for pair in list(self.current_trades.keys()): try: trade = self.current_trades[pair] ticker = self.binance.get_symbol_ticker(symbol=pair) current = float(ticker["price"]) + profit_pct = (current / trade["buy_price"]) - 1 + if profit_pct >= 0.01: - logger.info(f"TP HIT: {pair} +{profit_pct*100:.2f}%") + logger.info(f"🎯 TP HIT: {pair} +{profit_pct*100:.2f}%") + sell = self.binance.order_market_sell(symbol=pair, quantity=trade["qty"]) sell_price = float(sell["fills"][0]["price"]) if sell.get("fills") else current profit = (sell_price - trade["buy_price"]) * trade["qty"] + self.completed_trades.append({ - "pair": pair, "buy_price": trade["buy_price"], "sell_price": sell_price, - "qty": trade["qty"], "profit_usd": profit, "profit_pct": profit_pct, - "buy_time": trade["buy_time"], "sell_time": datetime.now().isoformat() + "pair": pair, + "buy_price": trade["buy_price"], + "sell_price": sell_price, + "qty": trade["qty"], + "profit_usd": profit, + "profit_pct": profit_pct, + "buy_time": trade["buy_time"], + "sell_time": datetime.now().isoformat() }) + self.daily_pnl += profit - self.wins_today += 1 remove.append(pair) except Exception as e: - logger.warning(f"TP error {pair}: {e}") + pass + for p in remove: del self.current_trades[p] - async def send_dash(self): + async def send_dashboard(self): + """SEND STATE TO DASHBOARD""" try: state = { "current_trades": self.current_trades, @@ -86,35 +117,43 @@ class Bot: "trades_today": self.trades_today, "daily_pnl": self.daily_pnl, "total_pnl": self.daily_pnl, - "wins_today": self.wins_today, - "losses_today": 0, + "wins_today": len([t for t in self.completed_trades if t.get("profit_usd", 0) > 0]), + "losses_today": len([t for t in self.completed_trades if t.get("profit_usd", 0) < 0]), "last_update": datetime.now().isoformat() } async with aiohttp.ClientSession() as s: - async with s.post(self.dashboard_url, json=state, timeout=2) as r: + async with s.post(self.dashboard, json=state, timeout=2) as r: pass - except Exception as e: - logger.warning(f"Dashboard error: {e}") + except: + pass async def run(self): - logger.info("Bot started") + """MAIN LOOP""" + logger.info("🎯 Bot started") + + tick = 0 while True: try: - await self.update_balance() - for pair in self.pairs: - if pair in self.current_trades: - continue - try: - ticker = self.binance.get_symbol_ticker(symbol=pair) - price = float(ticker["price"]) - import random + tick += 1 + + # Get balance every 5 ticks (every 5 seconds) + if tick % 5 == 0: + self.get_balance() + + # Check signals + pairs = ["BTCUSDT", "ETHUSDT", "SOLUSDT", "BNBUSDT", "XRPUSDT"] + for pair in pairs: + if pair not in self.current_trades: if random.random() > 0.95: - logger.info(f"BUY signal: {pair}") - await self.place_buy(pair, price) - except: - pass - await self.check_tp() - await self.send_dash() + logger.info(f"🟢 Signal: {pair}") + self.place_buy(pair) + + # Check exits + self.check_tp() + + # Send to dashboard + await self.send_dashboard() + await asyncio.sleep(1) except Exception as e: logger.error(f"Loop error: {e}")