TradingAgents/crypto_trading/scripts/run_paper_trading.py

232 lines
6.8 KiB
Python

"""
Paper Trading Runner
Run live paper trading with real-time data
"""
import sys
import os
import time
import signal
# 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
# ============================================================================
# EXAMPLE STRATEGIES
# ============================================================================
class SimpleMovingAverageStrategy:
"""Simple moving average crossover for paper trading."""
def __init__(self, short_window=20, long_window=50):
self.short_window = short_window
self.long_window = long_window
self.price_history = {}
def __call__(self, engine, symbol, current_price):
"""Execute strategy logic."""
# Initialize price history for symbol
if symbol not in self.price_history:
self.price_history[symbol] = []
# Add current price
self.price_history[symbol].append(current_price)
# Keep only needed history
if len(self.price_history[symbol]) > self.long_window:
self.price_history[symbol] = self.price_history[symbol][-self.long_window:]
# Need enough data
if len(self.price_history[symbol]) < self.long_window:
return None
# Calculate moving averages
prices = self.price_history[symbol]
short_ma = sum(prices[-self.short_window:]) / self.short_window
long_ma = sum(prices[-self.long_window:]) / self.long_window
# Golden cross - buy signal
if short_ma > long_ma and symbol not in engine.positions:
return OrderSide.BUY
# Death cross - sell signal
elif short_ma < long_ma and symbol in engine.positions:
return OrderSide.SELL
return None
class MomentumStrategy:
"""Momentum-based strategy."""
def __init__(self, lookback=10, threshold=0.05):
self.lookback = lookback
self.threshold = threshold
self.price_history = {}
def __call__(self, engine, symbol, current_price):
"""Execute strategy logic."""
# Initialize
if symbol not in self.price_history:
self.price_history[symbol] = []
self.price_history[symbol].append(current_price)
if len(self.price_history[symbol]) > self.lookback + 1:
self.price_history[symbol] = self.price_history[symbol][-(self.lookback + 1):]
if len(self.price_history[symbol]) < self.lookback:
return None
# Calculate momentum
momentum = (self.price_history[symbol][-1] - self.price_history[symbol][-self.lookback]) / self.price_history[symbol][-self.lookback]
# Strong momentum - buy
if momentum > self.threshold and symbol not in engine.positions:
return OrderSide.BUY
# Momentum reversal - sell
elif momentum < -self.threshold and symbol in engine.positions:
return OrderSide.SELL
return None
class RSIStrategy:
"""RSI mean reversion strategy."""
def __init__(self, period=14, oversold=30, overbought=70):
self.period = period
self.oversold = oversold
self.overbought = overbought
self.price_history = {}
def calculate_rsi(self, prices):
"""Calculate RSI."""
if len(prices) < self.period + 1:
return 50
gains = []
losses = []
for i in range(1, self.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.period
avg_loss = sum(losses) / self.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 logic."""
if symbol not in self.price_history:
self.price_history[symbol] = []
self.price_history[symbol].append(current_price)
if len(self.price_history[symbol]) > self.period + 10:
self.price_history[symbol] = self.price_history[symbol][-(self.period + 10):]
rsi = self.calculate_rsi(self.price_history[symbol])
# Oversold - buy
if rsi < self.oversold and symbol not in engine.positions:
return OrderSide.BUY
# Overbought - sell
elif rsi > self.overbought and symbol in engine.positions:
return OrderSide.SELL
return None
# ============================================================================
# MAIN
# ============================================================================
def main():
"""Run paper trading."""
print("\n" + "="*80)
print(" CRYPTO PAPER TRADING - LIVE SIMULATION")
print("="*80)
print("\nThis runs live paper trading with real-time market data.")
print("No real money is at risk - this is a simulation.\n")
print("Requirements:")
print(" ✓ CCXT installed (pip install ccxt)")
print(" ✓ Internet connection")
print(" ✓ Press Ctrl+C to stop gracefully\n")
# Configuration
print("Configuration:")
print(" Exchange: Binance")
print(" Symbols: BTC/USDT, ETH/USDT")
print(" Initial Capital: $10,000")
print(" Update Interval: 60 seconds")
print(" Strategy: MA Crossover (20/50)")
print()
input("Press Enter to start paper trading...")
# Create engine
engine = PaperTradingEngine(
exchange_id='binance',
initial_capital=10000,
commission_rate=0.001,
max_position_size=0.20,
max_daily_loss=0.05,
stop_loss_pct=0.15,
take_profit_pct=0.30,
update_interval=60 # 1 minute updates
)
# Set strategy
strategy = SimpleMovingAverageStrategy(short_window=20, long_window=50)
engine.set_strategy(strategy)
# Handle graceful shutdown
def signal_handler(sig, frame):
print("\n\nReceived interrupt signal...")
engine.stop()
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
# Start paper trading
symbols = ['BTC/USDT', 'ETH/USDT']
engine.start(symbols)
# Keep main thread alive
try:
while engine.is_running:
time.sleep(1)
except KeyboardInterrupt:
engine.stop()
print("\nPaper trading stopped.")
print("Data saved to: ./paper_trading_data/\n")
if __name__ == "__main__":
try:
main()
except Exception as e:
print(f"\nError: {e}")
import traceback
traceback.print_exc()