Bot auto-update: src/main_ml.py
This commit is contained in:
parent
524c52ccf6
commit
c856478c1a
133
src/main_ml.py
133
src/main_ml.py
|
|
@ -1,28 +1,31 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os, asyncio, aiohttp
|
import os, asyncio, aiohttp, logging, random
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from binance.client import Client
|
from binance.client import Client
|
||||||
from dotenv import load_dotenv
|
|
||||||
import logging
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
logger = logging.getLogger(__name__)
|
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:
|
class Bot:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.binance = Client(os.getenv("BINANCE_API_KEY_LIVE"), os.getenv("BINANCE_API_SECRET_LIVE"))
|
self.binance = Client(env.get("BINANCE_API_KEY_LIVE"), env.get("BINANCE_API_SECRET_LIVE"))
|
||||||
self.pairs = ["BTCUSDT","ETHUSDT","SOLUSDT","BNBUSDT","XRPUSDT"]
|
|
||||||
self.current_trades = {}
|
self.current_trades = {}
|
||||||
self.completed_trades = []
|
self.completed_trades = []
|
||||||
self.balance = {}
|
self.balance = {}
|
||||||
self.trades_today = 0
|
self.trades_today = 0
|
||||||
self.daily_pnl = 0.0
|
self.daily_pnl = 0.0
|
||||||
self.wins_today = 0
|
self.dashboard = "http://localhost:7000/api/update"
|
||||||
self.dashboard_url = "http://localhost:7000/api/update"
|
logger.info("🤖 Bot initialized - CLEAN")
|
||||||
logger.info("Bot CLEAN initialized")
|
|
||||||
|
|
||||||
async def update_balance(self):
|
def get_balance(self):
|
||||||
|
"""GET BALANCE FROM BINANCE (SYNC)"""
|
||||||
try:
|
try:
|
||||||
acc = self.binance.get_account()
|
acc = self.binance.get_account()
|
||||||
self.balance = {}
|
self.balance = {}
|
||||||
|
|
@ -30,54 +33,82 @@ class Bot:
|
||||||
free, locked = float(a["free"]), float(a["locked"])
|
free, locked = float(a["free"]), float(a["locked"])
|
||||||
if free + locked > 0:
|
if free + locked > 0:
|
||||||
self.balance[a["asset"]] = {"free": free, "locked": locked, "total": free+locked}
|
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:
|
except Exception as e:
|
||||||
logger.error(f"Balance error: {e}")
|
logger.error(f"Balance error: {e}")
|
||||||
|
|
||||||
async def place_buy(self, pair, price):
|
def place_buy(self, pair):
|
||||||
|
"""PLACE BUY ORDER"""
|
||||||
try:
|
try:
|
||||||
usdt = self.balance.get("USDT", {}).get("free", 0)
|
usdt_free = self.balance.get("USDT", {}).get("free", 0)
|
||||||
qty_usdt = usdt * 0.5
|
qty_usdt = usdt_free * 0.5
|
||||||
|
|
||||||
if qty_usdt < 10:
|
if qty_usdt < 10:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
ticker = self.binance.get_symbol_ticker(symbol=pair)
|
||||||
|
price = float(ticker["price"])
|
||||||
|
|
||||||
qty = round(qty_usdt / price, 4)
|
qty = round(qty_usdt / price, 4)
|
||||||
|
if qty <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
order = self.binance.order_market_buy(symbol=pair, quantity=qty)
|
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] = {
|
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
|
self.trades_today += 1
|
||||||
return order
|
return order
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Buy error {pair}: {e}")
|
logger.error(f"Buy {pair} error: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def check_tp(self):
|
def check_tp(self):
|
||||||
|
"""CHECK +1% TAKE PROFIT"""
|
||||||
remove = []
|
remove = []
|
||||||
for pair in list(self.current_trades.keys()):
|
for pair in list(self.current_trades.keys()):
|
||||||
try:
|
try:
|
||||||
trade = self.current_trades[pair]
|
trade = self.current_trades[pair]
|
||||||
ticker = self.binance.get_symbol_ticker(symbol=pair)
|
ticker = self.binance.get_symbol_ticker(symbol=pair)
|
||||||
current = float(ticker["price"])
|
current = float(ticker["price"])
|
||||||
|
|
||||||
profit_pct = (current / trade["buy_price"]) - 1
|
profit_pct = (current / trade["buy_price"]) - 1
|
||||||
|
|
||||||
if profit_pct >= 0.01:
|
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 = self.binance.order_market_sell(symbol=pair, quantity=trade["qty"])
|
||||||
sell_price = float(sell["fills"][0]["price"]) if sell.get("fills") else current
|
sell_price = float(sell["fills"][0]["price"]) if sell.get("fills") else current
|
||||||
profit = (sell_price - trade["buy_price"]) * trade["qty"]
|
profit = (sell_price - trade["buy_price"]) * trade["qty"]
|
||||||
|
|
||||||
self.completed_trades.append({
|
self.completed_trades.append({
|
||||||
"pair": pair, "buy_price": trade["buy_price"], "sell_price": sell_price,
|
"pair": pair,
|
||||||
"qty": trade["qty"], "profit_usd": profit, "profit_pct": profit_pct,
|
"buy_price": trade["buy_price"],
|
||||||
"buy_time": trade["buy_time"], "sell_time": datetime.now().isoformat()
|
"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.daily_pnl += profit
|
||||||
self.wins_today += 1
|
|
||||||
remove.append(pair)
|
remove.append(pair)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"TP error {pair}: {e}")
|
pass
|
||||||
|
|
||||||
for p in remove:
|
for p in remove:
|
||||||
del self.current_trades[p]
|
del self.current_trades[p]
|
||||||
|
|
||||||
async def send_dash(self):
|
async def send_dashboard(self):
|
||||||
|
"""SEND STATE TO DASHBOARD"""
|
||||||
try:
|
try:
|
||||||
state = {
|
state = {
|
||||||
"current_trades": self.current_trades,
|
"current_trades": self.current_trades,
|
||||||
|
|
@ -86,35 +117,43 @@ class Bot:
|
||||||
"trades_today": self.trades_today,
|
"trades_today": self.trades_today,
|
||||||
"daily_pnl": self.daily_pnl,
|
"daily_pnl": self.daily_pnl,
|
||||||
"total_pnl": self.daily_pnl,
|
"total_pnl": self.daily_pnl,
|
||||||
"wins_today": self.wins_today,
|
"wins_today": len([t for t in self.completed_trades if t.get("profit_usd", 0) > 0]),
|
||||||
"losses_today": 0,
|
"losses_today": len([t for t in self.completed_trades if t.get("profit_usd", 0) < 0]),
|
||||||
"last_update": datetime.now().isoformat()
|
"last_update": datetime.now().isoformat()
|
||||||
}
|
}
|
||||||
async with aiohttp.ClientSession() as s:
|
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
|
pass
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Dashboard error: {e}")
|
|
||||||
|
|
||||||
async def run(self):
|
|
||||||
logger.info("Bot started")
|
|
||||||
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
|
|
||||||
if random.random() > 0.95:
|
|
||||||
logger.info(f"BUY signal: {pair}")
|
|
||||||
await self.place_buy(pair, price)
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
await self.check_tp()
|
|
||||||
await self.send_dash()
|
async def run(self):
|
||||||
|
"""MAIN LOOP"""
|
||||||
|
logger.info("🎯 Bot started")
|
||||||
|
|
||||||
|
tick = 0
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
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"🟢 Signal: {pair}")
|
||||||
|
self.place_buy(pair)
|
||||||
|
|
||||||
|
# Check exits
|
||||||
|
self.check_tp()
|
||||||
|
|
||||||
|
# Send to dashboard
|
||||||
|
await self.send_dashboard()
|
||||||
|
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Loop error: {e}")
|
logger.error(f"Loop error: {e}")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue