feat: trading bot MVP — ICT Order Block + Liquidity Sweep strategy

Full-stack trading bot with:
- FastAPI backend with ICT strategy (Order Block + Liquidity Sweep detection)
- Backtester engine with rolling window, spread simulation, and performance metrics
- Hybrid market data service (yfinance + TwelveData with rate limiting + SQLite cache)
- Simulated exchange for paper trading
- React/TypeScript frontend with TradingView lightweight-charts v5
- Live dashboard with candlestick chart, OHLC legend, trade markers
- Backtest page with configurable parameters, equity curve, and trade table
- WebSocket support for real-time updates
- Bot runner with asyncio loop for automated trading

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 23:25:51 +01:00
commit 4df8d53b1a
58 changed files with 7484 additions and 0 deletions

90
backend/app/main.py Normal file
View File

@@ -0,0 +1,90 @@
import logging
from fastapi import FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware
from app.api.routes import backtest, bot, candles, trades
from app.api.routes.bot import set_bot_runner
from app.api.websocket import manager, websocket_endpoint
from app.core.bot import BotRunner
from app.core.config import settings
from app.core.database import AsyncSessionLocal, init_db
from app.core.exchange.simulated import SimulatedExchange
from app.core.strategy.order_block_sweep import OrderBlockSweepStrategy
from app.services.market_data import MarketDataService
from app.services.trade_manager import TradeManager
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI(
title="Trader Bot API",
description="Bot de trading ICT — Order Block + Liquidity Sweep",
version="0.1.0",
)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173", "http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(candles.router, prefix="/api")
app.include_router(trades.router, prefix="/api")
app.include_router(backtest.router, prefix="/api")
app.include_router(bot.router, prefix="/api")
@app.websocket("/ws/live")
async def ws_live(websocket: WebSocket):
await websocket_endpoint(websocket)
@app.on_event("startup")
async def startup():
await init_db()
logger.info("Base de données initialisée")
# Initialiser le bot avec l'exchange simulé (paper trading local)
async with AsyncSessionLocal() as db:
market_data = MarketDataService(db)
exchange = SimulatedExchange(
market_data_service=market_data,
initial_balance=settings.bot_initial_balance,
)
strategy = OrderBlockSweepStrategy()
trade_mgr = TradeManager(exchange)
runner = BotRunner(
exchange=exchange,
strategy=strategy,
trade_manager=trade_mgr,
)
async def broadcast_event(event: dict):
await manager.broadcast(event)
runner.set_event_callback(broadcast_event)
set_bot_runner(runner)
td_status = "✓ configurée" if settings.twelvedata_api_key else "✗ manquante (historique limité)"
logger.info(
"Bot initialisé — SimulatedExchange | balance=%.0f$ | TwelveData=%s",
settings.bot_initial_balance,
td_status,
)
@app.get("/")
async def root():
return {
"name": "Trader Bot API",
"version": "0.1.0",
"docs": "/docs",
"data_sources": {
"primary": "yfinance",
"fallback_historical": "TwelveData",
"twelvedata_configured": bool(settings.twelvedata_api_key),
},
}