237 lines
7.5 KiB
Python
237 lines
7.5 KiB
Python
"""
|
|
24/7 Crypto Trading Bot
|
|
Production deployment for continuous paper trading
|
|
"""
|
|
import sys
|
|
import os
|
|
|
|
# Add project root to path (go up 3 levels: scripts -> crypto_trading -> TradingAgents)
|
|
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
sys.path.insert(0, project_root)
|
|
|
|
from crypto_trading.src.paper_trading.paper_trading_engine import PaperTradingEngine, OrderSide
|
|
from crypto_trading.src.paper_trading.dashboard import PaperTradingDashboard
|
|
from crypto_trading.src.paper_trading.bot_manager import BotManager
|
|
|
|
|
|
# ============================================================================
|
|
# PRODUCTION STRATEGY
|
|
# ============================================================================
|
|
|
|
class MultiIndicatorStrategy:
|
|
"""
|
|
Production-grade multi-indicator strategy.
|
|
|
|
Combines:
|
|
- Moving average crossover
|
|
- RSI oversold/overbought
|
|
- Volume confirmation
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
short_window: int = 20,
|
|
long_window: int = 50,
|
|
rsi_period: int = 14,
|
|
rsi_oversold: int = 30,
|
|
rsi_overbought: int = 70
|
|
):
|
|
self.short_window = short_window
|
|
self.long_window = long_window
|
|
self.rsi_period = rsi_period
|
|
self.rsi_oversold = rsi_oversold
|
|
self.rsi_overbought = rsi_overbought
|
|
|
|
# Price history
|
|
self.price_history = {}
|
|
|
|
def calculate_rsi(self, prices):
|
|
"""Calculate RSI."""
|
|
if len(prices) < self.rsi_period + 1:
|
|
return 50
|
|
|
|
gains = []
|
|
losses = []
|
|
|
|
for i in range(1, self.rsi_period + 1):
|
|
change = prices[-i] - prices[-i-1]
|
|
if change > 0:
|
|
gains.append(change)
|
|
losses.append(0)
|
|
else:
|
|
gains.append(0)
|
|
losses.append(abs(change))
|
|
|
|
avg_gain = sum(gains) / self.rsi_period
|
|
avg_loss = sum(losses) / self.rsi_period
|
|
|
|
if avg_loss == 0:
|
|
return 100
|
|
|
|
rs = avg_gain / avg_loss
|
|
rsi = 100 - (100 / (1 + rs))
|
|
|
|
return rsi
|
|
|
|
def __call__(self, engine, symbol, current_price):
|
|
"""Execute strategy."""
|
|
# Initialize history
|
|
if symbol not in self.price_history:
|
|
self.price_history[symbol] = []
|
|
|
|
self.price_history[symbol].append(current_price)
|
|
|
|
# Keep needed history
|
|
if len(self.price_history[symbol]) > self.long_window + 10:
|
|
self.price_history[symbol] = self.price_history[symbol][-(self.long_window + 10):]
|
|
|
|
# Need enough data
|
|
if len(self.price_history[symbol]) < self.long_window:
|
|
return None
|
|
|
|
prices = self.price_history[symbol]
|
|
|
|
# Calculate indicators
|
|
short_ma = sum(prices[-self.short_window:]) / self.short_window
|
|
long_ma = sum(prices[-self.long_window:]) / self.long_window
|
|
rsi = self.calculate_rsi(prices)
|
|
|
|
# BUY CONDITIONS
|
|
# 1. Golden cross (short MA > long MA)
|
|
# 2. RSI oversold
|
|
# 3. No existing position
|
|
if (short_ma > long_ma and
|
|
rsi < self.rsi_oversold and
|
|
symbol not in engine.positions):
|
|
return OrderSide.BUY
|
|
|
|
# SELL CONDITIONS
|
|
# 1. Death cross (short MA < long MA) OR
|
|
# 2. RSI overbought
|
|
# 3. Have existing position
|
|
if symbol in engine.positions:
|
|
if short_ma < long_ma or rsi > self.rsi_overbought:
|
|
return OrderSide.SELL
|
|
|
|
return None
|
|
|
|
|
|
# ============================================================================
|
|
# CONFIGURATION
|
|
# ============================================================================
|
|
|
|
BOT_CONFIG = {
|
|
# Engine settings
|
|
'exchange_id': 'binance',
|
|
'initial_capital': 10000,
|
|
'commission_rate': 0.001,
|
|
'max_position_size': 0.15, # 15% per position
|
|
'max_daily_loss': 0.05, # 5% daily loss limit
|
|
'stop_loss_pct': 0.10, # 10% stop loss
|
|
'take_profit_pct': 0.25, # 25% take profit
|
|
'update_interval': 60, # 60 second updates
|
|
|
|
# Bot manager settings
|
|
'max_retries': 10,
|
|
'retry_delay': 300, # 5 minutes
|
|
'health_check_interval': 300, # 5 minutes
|
|
'daily_report_time': '00:00', # Midnight UTC
|
|
|
|
# Trading symbols
|
|
'symbols': ['BTC/USDT', 'ETH/USDT', 'BNB/USDT'],
|
|
|
|
# Strategy settings
|
|
'strategy': {
|
|
'short_window': 20,
|
|
'long_window': 50,
|
|
'rsi_period': 14,
|
|
'rsi_oversold': 30,
|
|
'rsi_overbought': 70,
|
|
}
|
|
}
|
|
|
|
|
|
# ============================================================================
|
|
# MAIN
|
|
# ============================================================================
|
|
|
|
def main():
|
|
"""Run 24/7 crypto trading bot."""
|
|
print("\n" + "="*80)
|
|
print(" 24/7 CRYPTO PAPER TRADING BOT")
|
|
print("="*80)
|
|
print("\nProduction-grade paper trading bot for continuous operation.")
|
|
print("\nConfiguration:")
|
|
print(f" Exchange: {BOT_CONFIG['exchange_id']}")
|
|
print(f" Symbols: {', '.join(BOT_CONFIG['symbols'])}")
|
|
print(f" Initial Capital: ${BOT_CONFIG['initial_capital']:,.2f}")
|
|
print(f" Update Interval: {BOT_CONFIG['update_interval']}s")
|
|
print(f" Max Position Size: {BOT_CONFIG['max_position_size']:.1%}")
|
|
print(f" Stop Loss: {BOT_CONFIG['stop_loss_pct']:.1%}")
|
|
print(f" Take Profit: {BOT_CONFIG['take_profit_pct']:.1%}")
|
|
print(f" Daily Loss Limit: {BOT_CONFIG['max_daily_loss']:.1%}")
|
|
print("\nStrategy:")
|
|
print(f" Type: Multi-Indicator (MA + RSI)")
|
|
print(f" MA Short/Long: {BOT_CONFIG['strategy']['short_window']}/{BOT_CONFIG['strategy']['long_window']}")
|
|
print(f" RSI Period: {BOT_CONFIG['strategy']['rsi_period']}")
|
|
print("\nFeatures:")
|
|
print(" ✓ 24/7 operation")
|
|
print(" ✓ Automatic error recovery")
|
|
print(" ✓ Health monitoring")
|
|
print(" ✓ Daily reports")
|
|
print(" ✓ Graceful shutdown (Ctrl+C)")
|
|
print("\nData:")
|
|
print(" Logs: ./logs/")
|
|
print(" Trading Data: ./paper_trading_data/")
|
|
print()
|
|
|
|
input("Press Enter to start bot...")
|
|
|
|
# Create engine
|
|
engine = PaperTradingEngine(
|
|
exchange_id=BOT_CONFIG['exchange_id'],
|
|
initial_capital=BOT_CONFIG['initial_capital'],
|
|
commission_rate=BOT_CONFIG['commission_rate'],
|
|
max_position_size=BOT_CONFIG['max_position_size'],
|
|
max_daily_loss=BOT_CONFIG['max_daily_loss'],
|
|
stop_loss_pct=BOT_CONFIG['stop_loss_pct'],
|
|
take_profit_pct=BOT_CONFIG['take_profit_pct'],
|
|
update_interval=BOT_CONFIG['update_interval'],
|
|
data_dir="./paper_trading_data"
|
|
)
|
|
|
|
# Create dashboard
|
|
dashboard = PaperTradingDashboard(engine)
|
|
|
|
# Create strategy
|
|
strategy = MultiIndicatorStrategy(**BOT_CONFIG['strategy'])
|
|
engine.set_strategy(strategy)
|
|
|
|
# Create bot manager
|
|
bot_manager = BotManager(
|
|
engine=engine,
|
|
dashboard=dashboard,
|
|
max_retries=BOT_CONFIG['max_retries'],
|
|
retry_delay=BOT_CONFIG['retry_delay'],
|
|
health_check_interval=BOT_CONFIG['health_check_interval'],
|
|
daily_report_time=BOT_CONFIG['daily_report_time'],
|
|
log_dir="./logs"
|
|
)
|
|
|
|
# Start bot
|
|
print("\n🚀 Starting bot...\n")
|
|
bot_manager.start(BOT_CONFIG['symbols'])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except KeyboardInterrupt:
|
|
print("\n\nShutdown requested by user...")
|
|
sys.exit(0)
|
|
except Exception as e:
|
|
print(f"\n🚨 Fatal error: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|