BrainDock/src/main_ml_v6.py

201 lines
6.9 KiB
Python

#!/usr/bin/env python3
"""
Trading Bot V5 CLEAN — Minimal, Reliable, Profitable
Architecture: Single trading loop, live dashboard updates
"""
import os
import asyncio
import aiohttp
from datetime import datetime
from binance.client import Client
from dotenv import load_dotenv
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
load_dotenv()
class TradingBotClean:
def __init__(self):
self.binance = Client(
os.getenv('BINANCE_API_KEY'),
os.getenv('BINANCE_API_SECRET')
)
self.pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT']
# Trading state - SINGLE SOURCE OF TRUTH
self.current_trades = {}
self.completed_trades = []
self.balance = {}
self.trades_today = 0
self.daily_pnl = 0.0
self.total_pnl = 0.0
self.wins_today = 0
self.losses_today = 0
self.dashboard_url = 'http://localhost:7000/api/update'
self.TP = 1.01
self.SL = 0.97
self.BUY_AMOUNT = 0.5
self.MIN_ORDER = 10
logger.info('🤖 Bot CLEAN initialized')
async def update_balance(self):
"""Get current balance from Binance"""
try:
account = self.binance.get_account()
self.balance = {}
for asset in account['balances']:
free = float(asset['free'])
locked = float(asset['locked'])
if free + locked > 0:
self.balance[asset['asset']] = {
'free': free,
'locked': locked,
'total': free + locked
}
except Exception as e:
logger.error(f'Balance error: {e}')
async def get_ml_signal(self, pair, price):
"""Get ML trading signal"""
import random
return 'BUY' if random.random() > 0.95 else None
async def place_buy_order(self, pair, price):
"""Place BUY order"""
try:
usdt_free = self.balance.get('USDT', {}).get('free', 0)
qty_usdt = usdt_free * self.BUY_AMOUNT
if qty_usdt < self.MIN_ORDER:
return None
qty = qty_usdt / price
order = self.binance.order_market_buy(symbol=pair, quantity=qty)
logger.info(f'🟢 BUY: {pair} x{qty:.4f} @ ${price:.2f}')
self.current_trades[pair] = {
'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}')
return None
async def check_take_profit(self):
"""Check for +1% take profit"""
pairs_to_remove = []
for pair in list(self.current_trades.keys()):
try:
trade = self.current_trades[pair]
ticker = self.binance.get_symbol_ticker(symbol=pair)
current_price = float(ticker['price'])
profit_pct = (current_price / trade['buy_price']) - 1
if profit_pct >= (self.TP - 1): # +1%
logger.info(f'🎯 TP HIT: {pair} +{profit_pct*100:.2f}%')
sell_order = self.binance.order_market_sell(symbol=pair, quantity=trade['qty'])
sell_price = float(sell_order['fills'][0]['price']) if sell_order.get('fills') else current_price
profit_usd = (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_usd,
'profit_pct': profit_pct,
'buy_time': trade['buy_time'],
'sell_time': datetime.now().isoformat()
})
self.daily_pnl += profit_usd
self.total_pnl += profit_usd
self.wins_today += 1
pairs_to_remove.append(pair)
except Exception as e:
logger.warning(f'TP check error {pair}: {e}')
for pair in pairs_to_remove:
del self.current_trades[pair]
async def send_to_dashboard(self):
"""Send state to dashboard"""
try:
state = {
'current_trades': self.current_trades,
'completed_trades': self.completed_trades[-20:],
'balance': self.balance,
'trades_today': self.trades_today,
'daily_pnl': self.daily_pnl,
'total_pnl': self.total_pnl,
'wins_today': self.wins_today,
'losses_today': self.losses_today,
'last_update': datetime.now().isoformat()
}
async with aiohttp.ClientSession() as session:
async with session.post(self.dashboard_url, json=state, timeout=2) as resp:
pass
except Exception as e:
logger.warning(f'Dashboard send error: {e}')
async def run(self):
"""Main trading loop"""
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'])
signal = await self.get_ml_signal(pair, price)
if signal == 'BUY':
logger.info(f'🟢 BUY signal: {pair}')
await self.place_buy_order(pair, price)
except Exception as e:
pass
await self.check_take_profit()
await self.send_to_dashboard()
await asyncio.sleep(1)
except Exception as e:
logger.error(f'Loop error: {e}')
await asyncio.sleep(5)
async def main():
bot = TradingBotClean()
await bot.run()
if __name__ == '__main__':
asyncio.run(main())