Initial commit — Trading AI Secure project complet
Architecture Docker (8 services), FastAPI, TimescaleDB, Redis, Streamlit. Stratégies : scalping, intraday, swing. MLEngine + RegimeDetector (HMM). BacktestEngine + WalkForwardAnalyzer + Optuna optimizer. Routes API complètes dont /optimize async. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
203
src/db/models.py
Normal file
203
src/db/models.py
Normal file
@@ -0,0 +1,203 @@
|
||||
"""
|
||||
Modèles SQLAlchemy - Trading AI Secure.
|
||||
|
||||
Tables :
|
||||
- Trade : trades exécutés (ouverts + fermés)
|
||||
- OHLCVData : données de marché OHLCV (hypertable TimescaleDB)
|
||||
- BacktestResult : résultats de backtesting
|
||||
- MLModelMeta : métadonnées des modèles ML (date entraînement, métriques)
|
||||
- OptimizationRun : historique des runs Optuna
|
||||
|
||||
TimescaleDB hypertable pour OHLCVData :
|
||||
SELECT create_hypertable('ohlcv', 'timestamp', if_not_exists => TRUE);
|
||||
(Exécuter une seule fois après création de la table)
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import (
|
||||
Boolean, Column, DateTime, Float, Index,
|
||||
Integer, JSON, String, Text, UniqueConstraint,
|
||||
)
|
||||
from sqlalchemy.orm import DeclarativeBase
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TRADING
|
||||
# =============================================================================
|
||||
|
||||
class Trade(Base):
|
||||
"""Trade exécuté (paper ou live)."""
|
||||
__tablename__ = "trades"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
symbol = Column(String(20), nullable=False, index=True)
|
||||
direction = Column(String(5), nullable=False) # LONG | SHORT
|
||||
quantity = Column(Float, nullable=False)
|
||||
entry_price = Column(Float, nullable=False)
|
||||
exit_price = Column(Float, nullable=True)
|
||||
stop_loss = Column(Float, nullable=False)
|
||||
take_profit = Column(Float, nullable=False)
|
||||
strategy = Column(String(50), nullable=False, index=True)
|
||||
mode = Column(String(10), nullable=False, default="paper") # paper | live
|
||||
|
||||
entry_time = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||||
exit_time = Column(DateTime, nullable=True)
|
||||
|
||||
pnl = Column(Float, nullable=True)
|
||||
pnl_pct = Column(Float, nullable=True)
|
||||
risk_amount = Column(Float, nullable=True)
|
||||
|
||||
status = Column(String(10), nullable=False, default="open") # open | closed
|
||||
close_reason = Column(String(30), nullable=True) # stop_loss | take_profit | manual | paper_end
|
||||
|
||||
# Référence broker (IG Markets deal ID)
|
||||
deal_id = Column(String(50), nullable=True, unique=True)
|
||||
|
||||
# Contexte ML
|
||||
ml_confidence = Column(Float, nullable=True)
|
||||
market_regime = Column(String(20), nullable=True) # bull | bear | sideways | volatile
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
__table_args__ = (
|
||||
Index("ix_trades_entry_time", "entry_time"),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Trade {self.direction} {self.symbol} @ {self.entry_price} [{self.status}]>"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# DONNÉES DE MARCHÉ
|
||||
# =============================================================================
|
||||
|
||||
class OHLCVData(Base):
|
||||
"""
|
||||
Données OHLCV (Open/High/Low/Close/Volume).
|
||||
|
||||
Optimisé pour TimescaleDB : créer l'hypertable manuellement après migration :
|
||||
SELECT create_hypertable('ohlcv', 'timestamp', if_not_exists => TRUE);
|
||||
"""
|
||||
__tablename__ = "ohlcv"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
symbol = Column(String(20), nullable=False)
|
||||
timeframe = Column(String(5), nullable=False) # 1m, 5m, 15m, 1h, 1d
|
||||
timestamp = Column(DateTime, nullable=False)
|
||||
|
||||
open = Column(Float, nullable=False)
|
||||
high = Column(Float, nullable=False)
|
||||
low = Column(Float, nullable=False)
|
||||
close = Column(Float, nullable=False)
|
||||
volume = Column(Float, nullable=True)
|
||||
|
||||
source = Column(String(30), nullable=True) # yahoo_finance | alpha_vantage | ig_markets
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint("symbol", "timeframe", "timestamp", name="uq_ohlcv"),
|
||||
Index("ix_ohlcv_symbol_tf_ts", "symbol", "timeframe", "timestamp"),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<OHLCV {self.symbol} {self.timeframe} {self.timestamp} C={self.close}>"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# BACKTESTING
|
||||
# =============================================================================
|
||||
|
||||
class BacktestResult(Base):
|
||||
"""Résultat d'un run de backtesting."""
|
||||
__tablename__ = "backtest_results"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
strategy = Column(String(50), nullable=False)
|
||||
symbol = Column(String(20), nullable=False)
|
||||
period = Column(String(10), nullable=False) # 6m | 1y | 2y
|
||||
initial_capital = Column(Float, nullable=False)
|
||||
final_capital = Column(Float, nullable=False)
|
||||
|
||||
# Métriques de performance
|
||||
total_return = Column(Float, nullable=False)
|
||||
sharpe_ratio = Column(Float, nullable=False)
|
||||
max_drawdown = Column(Float, nullable=False)
|
||||
win_rate = Column(Float, nullable=False)
|
||||
profit_factor = Column(Float, nullable=False)
|
||||
total_trades = Column(Integer, nullable=False)
|
||||
calmar_ratio = Column(Float, nullable=True)
|
||||
sortino_ratio = Column(Float, nullable=True)
|
||||
|
||||
# Validation
|
||||
is_valid = Column(Boolean, default=False) # Sharpe > 1.5, DD < 10%, etc.
|
||||
|
||||
# Paramètres utilisés
|
||||
params = Column(JSON, nullable=True)
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"<BacktestResult {self.strategy}/{self.symbol} "
|
||||
f"Sharpe={self.sharpe_ratio:.2f} DD={self.max_drawdown:.1%}>"
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# MACHINE LEARNING
|
||||
# =============================================================================
|
||||
|
||||
class MLModelMeta(Base):
|
||||
"""Métadonnées d'un modèle ML entraîné."""
|
||||
__tablename__ = "ml_models"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
model_name = Column(String(50), nullable=False) # xgboost | lightgbm | catboost | hmm_regime
|
||||
strategy = Column(String(50), nullable=True)
|
||||
version = Column(Integer, nullable=False, default=1)
|
||||
|
||||
# Métriques d'entraînement
|
||||
train_sharpe = Column(Float, nullable=True)
|
||||
val_sharpe = Column(Float, nullable=True)
|
||||
train_accuracy = Column(Float, nullable=True)
|
||||
val_accuracy = Column(Float, nullable=True)
|
||||
|
||||
# Paramètres
|
||||
hyperparams = Column(JSON, nullable=True)
|
||||
feature_names = Column(JSON, nullable=True) # liste des features utilisées
|
||||
|
||||
# Chemin fichier modèle sérialisé
|
||||
file_path = Column(String(255), nullable=True)
|
||||
|
||||
trained_at = Column(DateTime, default=datetime.utcnow)
|
||||
is_active = Column(Boolean, default=False)
|
||||
|
||||
__table_args__ = (
|
||||
Index("ix_ml_models_name_version", "model_name", "version"),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<MLModelMeta {self.model_name} v{self.version} active={self.is_active}>"
|
||||
|
||||
|
||||
class OptimizationRun(Base):
|
||||
"""Historique des runs d'optimisation Optuna."""
|
||||
__tablename__ = "optimization_runs"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
strategy = Column(String(50), nullable=False)
|
||||
n_trials = Column(Integer, nullable=False)
|
||||
best_sharpe = Column(Float, nullable=True)
|
||||
best_params = Column(JSON, nullable=True)
|
||||
drift_detected = Column(Boolean, default=False)
|
||||
duration_secs = Column(Float, nullable=True)
|
||||
started_at = Column(DateTime, default=datetime.utcnow)
|
||||
completed_at = Column(DateTime, nullable=True)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<OptimizationRun {self.strategy} trials={self.n_trials} sharpe={self.best_sharpe}>"
|
||||
Reference in New Issue
Block a user