Files
trader-ml/docs/AI_FRAMEWORK.md
Tika da30ef19ed 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>
2026-03-08 17:38:09 +00:00

26 KiB

🤖 Framework IA Adaptative - Trading AI Secure

📋 Table des Matières

  1. Vue d'ensemble
  2. Philosophie de l'IA Auto-Optimisante
  3. Architecture ML
  4. Optimisation Continue des Paramètres
  5. Regime Detection
  6. Position Sizing Adaptatif
  7. Validation et Anti-Overfitting
  8. Implémentation Technique

🎯 Vue d'ensemble

Le framework IA de Trading AI Secure est conçu pour être auto-adaptatif et en constante remise en question. Contrairement aux systèmes traditionnels avec paramètres fixes, notre IA ajuste continuellement ses décisions en fonction :

  • 📊 Conditions de marché (volatilité, tendance, liquidité)
  • 📈 Performance récente (win rate, Sharpe ratio, drawdown)
  • 🔗 Corrélations inter-stratégies (diversification)
  • ⚠️ Métriques de risque (VaR, CVaR, max drawdown)
  • 🌍 Événements macro-économiques (taux, inflation, sentiment)

🧠 Philosophie de l'IA Auto-Optimisante

Principe Fondamental : "Doute Permanent"

Notre IA opère selon le principe du doute méthodique :

┌─────────────────────────────────────────────────────────┐
│  CYCLE D'AUTO-AMÉLIORATION CONTINUE (24h)               │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  1. COLLECTE    → Données marché + performance          │
│  2. ANALYSE     → Détection dégradation/amélioration    │
│  3. HYPOTHÈSE   → Nouveaux paramètres candidats         │
│  4. TEST        → Backtesting + Monte Carlo             │
│  5. VALIDATION  → A/B testing paper trading             │
│  6. DÉPLOIEMENT → Adoption progressive si validé        │
│  7. MONITORING  → Surveillance performance              │
│                                                         │
│  ↻ RETOUR À L'ÉTAPE 1                                  │
└─────────────────────────────────────────────────────────┘

Questions Permanentes de l'IA

L'IA se pose continuellement ces questions :

  1. Mes paramètres actuels sont-ils toujours optimaux ?

    • Comparaison performance vs. variantes
    • Détection de drift statistique
  2. Le régime de marché a-t-il changé ?

    • Bull → Bear → Sideways
    • Haute volatilité → Basse volatilité
    • Trending → Mean-reverting
  3. Mes prédictions sont-elles calibrées ?

    • Probabilités prédites vs. réalisées
    • Brier score, log-loss
  4. Mon sizing est-il adapté au risque actuel ?

    • Kelly Criterion dynamique
    • Ajustement selon drawdown
  5. Existe-t-il de meilleures combinaisons de features ?

    • Feature importance évolutive
    • Sélection automatique

🏗️ Architecture ML

Stack Technologique

# Core ML
scikit-learn==1.4.0        # Modèles de base
xgboost==2.0.3             # Gradient boosting
lightgbm==4.1.0            # Alternative rapide
catboost==1.2.2            # Categorical features

# Optimisation
optuna==3.5.0              # Bayesian optimization
hyperopt==0.2.7            # Alternative optimization
ray[tune]==2.9.0           # Distributed tuning

# Time Series
statsmodels==0.14.1        # ARIMA, GARCH
arch==6.2.0                # Volatility models
prophet==1.1.5             # Forecasting

# Deep Learning (optionnel)
tensorflow==2.15.0         # Neural networks
pytorch==2.1.2             # Alternative DL
keras-tuner==1.4.6         # Hyperparameter tuning

# Reinforcement Learning
stable-baselines3==2.2.1   # RL algorithms
gym==0.26.2                # RL environment

Pipeline ML Multi-Niveaux

┌──────────────────────────────────────────────────────────────┐
│                    ENSEMBLE ADAPTATIF                        │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │   Modèle 1  │  │   Modèle 2  │  │   Modèle 3  │         │
│  │   XGBoost   │  │  LightGBM   │  │   CatBoost  │         │
│  │  (Trending) │  │(Mean-Rev.)  │  │ (Volatility)│         │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘         │
│         │                │                │                 │
│         └────────────────┼────────────────┘                 │
│                          │                                  │
│                   ┌──────▼──────┐                          │
│                   │   META-     │                          │
│                   │  LEARNER    │                          │
│                   │  (Stacking) │                          │
│                   └──────┬──────┘                          │
│                          │                                  │
│                   ┌──────▼──────┐                          │
│                   │   REGIME    │                          │
│                   │  DETECTOR   │                          │
│                   │  (Weights)  │                          │
│                   └──────┬──────┘                          │
│                          │                                  │
│                   ┌──────▼──────┐                          │
│                   │   FINAL     │                          │
│                   │  DECISION   │                          │
│                   └─────────────┘                          │
└──────────────────────────────────────────────────────────────┘

⚙️ Optimisation Continue des Paramètres

1. Optimisation Bayésienne (Optuna)

Fréquence : Quotidienne (après clôture marché)

Paramètres Optimisés :

# Exemple configuration Optuna
def objective(trial):
    params = {
        # Modèle
        'n_estimators': trial.suggest_int('n_estimators', 100, 1000),
        'max_depth': trial.suggest_int('max_depth', 3, 12),
        'learning_rate': trial.suggest_float('learning_rate', 0.001, 0.3, log=True),
        
        # Features
        'lookback_period': trial.suggest_int('lookback_period', 10, 100),
        'volatility_window': trial.suggest_int('volatility_window', 5, 50),
        
        # Trading
        'stop_loss_atr_mult': trial.suggest_float('stop_loss_atr_mult', 1.0, 5.0),
        'take_profit_ratio': trial.suggest_float('take_profit_ratio', 1.5, 5.0),
        'min_probability': trial.suggest_float('min_probability', 0.5, 0.8),
        
        # Risk
        'kelly_fraction': trial.suggest_float('kelly_fraction', 0.1, 0.5),
        'max_position_size': trial.suggest_float('max_position_size', 0.01, 0.1),
    }
    
    # Backtesting avec paramètres
    sharpe = backtest_strategy(params)
    return sharpe

Contraintes de Sécurité :

# Limites strictes pour éviter paramètres dangereux
PARAMETER_CONSTRAINTS = {
    'max_position_size': {'min': 0.01, 'max': 0.10},  # 1-10% max
    'stop_loss_atr_mult': {'min': 1.0, 'max': 5.0},   # Stop raisonnable
    'kelly_fraction': {'min': 0.1, 'max': 0.5},       # Kelly conservateur
    'min_probability': {'min': 0.5, 'max': 0.9},      # Seuil décision
}

2. A/B Testing Automatique

Principe : Tester simultanément plusieurs variantes de stratégies

class ABTestingEngine:
    """
    Teste 2-3 variantes de paramètres en parallèle
    sur paper trading pendant 7 jours
    """
    
    def __init__(self):
        self.variants = {
            'control': current_params,      # Paramètres actuels
            'variant_a': optimized_params_1, # Optuna suggestion 1
            'variant_b': optimized_params_2, # Optuna suggestion 2
        }
        
    def allocate_capital(self):
        """Allocation capital par variante"""
        return {
            'control': 0.50,    # 50% capital actuel
            'variant_a': 0.25,  # 25% variante A
            'variant_b': 0.25,  # 25% variante B
        }
        
    def evaluate_winner(self, results: Dict):
        """
        Critères de sélection :
        - Sharpe Ratio > control + 10%
        - Max Drawdown < control
        - Win Rate > control
        - Profit Factor > control
        """
        winner = max(results, key=lambda x: results[x]['sharpe'])
        
        if self.is_significantly_better(winner, 'control'):
            return winner
        return 'control'  # Conserver actuel si pas mieux

3. Reinforcement Learning pour Position Sizing

Approche : Agent RL apprend le sizing optimal

import gym
from stable_baselines3 import PPO

class TradingEnvironment(gym.Env):
    """
    Environment RL pour position sizing
    
    State: [portfolio_value, current_drawdown, volatility, 
            win_rate_recent, correlation_portfolio, regime]
    
    Action: position_size (0.0 à max_position_size)
    
    Reward: Sharpe ratio - penalty(drawdown) - penalty(correlation)
    """
    
    def __init__(self):
        self.action_space = gym.spaces.Box(
            low=0.0, high=0.1, shape=(1,)
        )
        self.observation_space = gym.spaces.Box(
            low=-np.inf, high=np.inf, shape=(6,)
        )
        
    def step(self, action):
        position_size = action[0]
        
        # Simuler trade avec ce sizing
        pnl = self.simulate_trade(position_size)
        
        # Calculer reward
        reward = self.calculate_reward(pnl, position_size)
        
        return next_state, reward, done, info
        
    def calculate_reward(self, pnl, position_size):
        """
        Reward = PnL ajusté du risque
        Pénalités :
        - Drawdown excessif
        - Position trop grande
        - Corrélation élevée
        """
        reward = pnl
        
        if self.current_drawdown > 0.05:
            reward -= 10 * self.current_drawdown
            
        if position_size > 0.05:
            reward -= 5 * (position_size - 0.05)
            
        return reward

# Entraînement
env = TradingEnvironment()
model = PPO("MlpPolicy", env, verbose=1)
model.learn(total_timesteps=100000)

4. Parameter Drift Detection

Objectif : Détecter quand paramètres deviennent obsolètes

from scipy import stats

class ParameterDriftDetector:
    """
    Détecte changements statistiques dans performance
    """
    
    def __init__(self, window=30):
        self.window = window
        self.historical_sharpe = []
        
    def detect_drift(self, current_sharpe: float) -> bool:
        """
        Test statistique : performance actuelle vs. historique
        """
        self.historical_sharpe.append(current_sharpe)
        
        if len(self.historical_sharpe) < self.window:
            return False
            
        # Test t de Student
        recent = self.historical_sharpe[-7:]  # 7 derniers jours
        baseline = self.historical_sharpe[-self.window:-7]
        
        t_stat, p_value = stats.ttest_ind(recent, baseline)
        
        # Drift détecté si p < 0.05 et performance dégradée
        if p_value < 0.05 and np.mean(recent) < np.mean(baseline):
            return True
            
        return False
        
    def trigger_reoptimization(self):
        """Lance optimisation Optuna si drift détecté"""
        logger.warning("Parameter drift detected! Triggering reoptimization...")
        run_optuna_optimization()

🎭 Regime Detection

Détection de Régimes de Marché

Objectif : Adapter stratégies selon régime (Bull/Bear/Sideways)

from hmmlearn import hmm
import numpy as np

class MarketRegimeDetector:
    """
    Hidden Markov Model pour détecter régimes
    
    États :
    - 0: Bull Market (trending up, low volatility)
    - 1: Bear Market (trending down, high volatility)
    - 2: Sideways (no trend, medium volatility)
    """
    
    def __init__(self, n_regimes=3):
        self.model = hmm.GaussianHMM(
            n_components=n_regimes,
            covariance_type="full",
            n_iter=1000
        )
        
    def fit(self, returns, volatility):
        """
        Entraîne HMM sur données historiques
        """
        features = np.column_stack([returns, volatility])
        self.model.fit(features)
        
    def predict_regime(self, recent_returns, recent_volatility):
        """
        Prédit régime actuel
        """
        features = np.column_stack([recent_returns, recent_volatility])
        regime = self.model.predict(features)[-1]
        
        regime_names = {0: 'BULL', 1: 'BEAR', 2: 'SIDEWAYS'}
        return regime_names[regime]
        
    def get_regime_probabilities(self, recent_data):
        """
        Probabilités de chaque régime
        """
        return self.model.predict_proba(recent_data)[-1]

Adaptation Stratégies par Régime

REGIME_STRATEGY_WEIGHTS = {
    'BULL': {
        'scalping': 0.2,
        'intraday': 0.5,   # Favoriser intraday en bull
        'swing': 0.3,
    },
    'BEAR': {
        'scalping': 0.4,   # Favoriser scalping en bear
        'intraday': 0.3,
        'swing': 0.1,      # Réduire swing en bear
        'short_bias': 0.2, # Activer short bias
    },
    'SIDEWAYS': {
        'scalping': 0.5,   # Favoriser scalping en sideways
        'intraday': 0.3,
        'swing': 0.2,
    }
}

def adjust_strategy_allocation(regime: str) -> Dict[str, float]:
    """
    Ajuste allocation capital par stratégie selon régime
    """
    return REGIME_STRATEGY_WEIGHTS[regime]

📏 Position Sizing Adaptatif

Kelly Criterion Dynamique

class AdaptiveKellyCriterion:
    """
    Kelly Criterion avec ajustements dynamiques
    
    Kelly% = (p * b - q) / b
    où :
    - p = probabilité de gain (prédite par ML)
    - q = probabilité de perte (1 - p)
    - b = ratio gain/perte moyen
    """
    
    def __init__(self, kelly_fraction=0.25):
        self.kelly_fraction = kelly_fraction  # Fraction conservatrice
        
    def calculate_position_size(
        self,
        win_probability: float,
        avg_win: float,
        avg_loss: float,
        current_drawdown: float,
        portfolio_volatility: float
    ) -> float:
        """
        Calcule taille position optimale
        """
        # Kelly de base
        b = avg_win / abs(avg_loss)
        kelly = (win_probability * b - (1 - win_probability)) / b
        
        # Ajustements dynamiques
        kelly = self._adjust_for_drawdown(kelly, current_drawdown)
        kelly = self._adjust_for_volatility(kelly, portfolio_volatility)
        kelly = self._adjust_for_confidence(kelly, win_probability)
        
        # Appliquer fraction conservatrice
        position_size = kelly * self.kelly_fraction
        
        # Limites strictes
        return np.clip(position_size, 0.01, 0.10)
        
    def _adjust_for_drawdown(self, kelly: float, drawdown: float) -> float:
        """
        Réduire sizing si drawdown élevé
        """
        if drawdown > 0.05:  # > 5% drawdown
            reduction = 1 - (drawdown / 0.10)  # Réduction linéaire
            kelly *= max(reduction, 0.5)  # Min 50% du Kelly
        return kelly
        
    def _adjust_for_volatility(self, kelly: float, volatility: float) -> float:
        """
        Réduire sizing si volatilité élevée
        """
        if volatility > 0.02:  # > 2% volatilité quotidienne
            kelly *= (0.02 / volatility)
        return kelly
        
    def _adjust_for_confidence(self, kelly: float, probability: float) -> float:
        """
        Réduire sizing si faible confiance
        """
        if probability < 0.6:
            kelly *= (probability / 0.6)
        return kelly

Validation et Anti-Overfitting

Walk-Forward Analysis

class WalkForwardValidator:
    """
    Validation temporelle rigoureuse
    
    Principe :
    1. Entraîner sur fenêtre N
    2. Tester sur fenêtre N+1
    3. Glisser fenêtre
    4. Répéter
    """
    
    def __init__(self, train_window=252, test_window=63):
        self.train_window = train_window  # 1 an
        self.test_window = test_window    # 3 mois
        
    def validate(self, data, strategy):
        """
        Effectue walk-forward analysis
        """
        results = []
        
        for i in range(0, len(data) - self.train_window - self.test_window, self.test_window):
            # Fenêtre entraînement
            train_data = data[i:i+self.train_window]
            
            # Fenêtre test
            test_data = data[i+self.train_window:i+self.train_window+self.test_window]
            
            # Entraîner
            strategy.fit(train_data)
            
            # Tester
            performance = strategy.backtest(test_data)
            results.append(performance)
            
        return self._aggregate_results(results)
        
    def _aggregate_results(self, results):
        """
        Agrège résultats walk-forward
        """
        return {
            'mean_sharpe': np.mean([r['sharpe'] for r in results]),
            'std_sharpe': np.std([r['sharpe'] for r in results]),
            'mean_drawdown': np.mean([r['max_drawdown'] for r in results]),
            'worst_period': min(results, key=lambda x: x['sharpe']),
        }

Monte Carlo Simulation

class MonteCarloValidator:
    """
    Simulation Monte Carlo pour robustesse
    """
    
    def __init__(self, n_simulations=10000):
        self.n_simulations = n_simulations
        
    def simulate(self, strategy, historical_trades):
        """
        Simule N scénarios en réordonnant trades
        """
        results = []
        
        for _ in range(self.n_simulations):
            # Réordonner trades aléatoirement
            shuffled_trades = np.random.permutation(historical_trades)
            
            # Calculer métriques
            sharpe = self._calculate_sharpe(shuffled_trades)
            max_dd = self._calculate_max_drawdown(shuffled_trades)
            
            results.append({'sharpe': sharpe, 'max_dd': max_dd})
            
        return self._analyze_distribution(results)
        
    def _analyze_distribution(self, results):
        """
        Analyse distribution résultats
        """
        sharpes = [r['sharpe'] for r in results]
        drawdowns = [r['max_dd'] for r in results]
        
        return {
            'sharpe_mean': np.mean(sharpes),
            'sharpe_5th_percentile': np.percentile(sharpes, 5),
            'sharpe_95th_percentile': np.percentile(sharpes, 95),
            'max_dd_mean': np.mean(drawdowns),
            'max_dd_95th_percentile': np.percentile(drawdowns, 95),
            'probability_positive_sharpe': np.mean(np.array(sharpes) > 0),
        }

💻 Implémentation Technique

Architecture Complète

# src/ml/adaptive_ai_engine.py

from typing import Dict, List, Optional
import optuna
import numpy as np
from dataclasses import dataclass

@dataclass
class AIConfig:
    """Configuration IA adaptative"""
    optimization_frequency: str = 'daily'  # daily, weekly
    ab_test_duration_days: int = 7
    parameter_drift_window: int = 30
    kelly_fraction: float = 0.25
    min_sharpe_improvement: float = 0.1  # 10% amélioration minimum

class AdaptiveAIEngine:
    """
    Moteur IA adaptatif central
    
    Responsabilités :
    - Optimisation continue paramètres
    - Détection régimes
    - Position sizing adaptatif
    - Validation anti-overfitting
    """
    
    def __init__(self, config: AIConfig):
        self.config = config
        
        # Composants
        self.optimizer = OptunaOptimizer()
        self.regime_detector = MarketRegimeDetector()
        self.kelly_calculator = AdaptiveKellyCriterion(config.kelly_fraction)
        self.drift_detector = ParameterDriftDetector()
        self.ab_tester = ABTestingEngine()
        
        # État
        self.current_params = {}
        self.current_regime = 'SIDEWAYS'
        self.performance_history = []
        
    async def daily_optimization_cycle(self):
        """
        Cycle d'optimisation quotidien
        """
        logger.info("Starting daily optimization cycle...")
        
        # 1. Détecter drift
        if self.drift_detector.detect_drift(self.get_recent_sharpe()):
            logger.warning("Parameter drift detected!")
            
            # 2. Optimiser nouveaux paramètres
            new_params = await self.optimizer.optimize()
            
            # 3. Valider avec walk-forward
            if self._validate_params(new_params):
                # 4. Lancer A/B test
                self.ab_tester.add_variant('optimized', new_params)
                
        # 5. Détecter régime
        self.current_regime = self.regime_detector.predict_regime(
            self.get_recent_returns(),
            self.get_recent_volatility()
        )
        
        # 6. Ajuster allocations
        self._adjust_strategy_weights(self.current_regime)
        
        logger.info(f"Optimization cycle complete. Regime: {self.current_regime}")
        
    def calculate_position_size(
        self,
        signal_probability: float,
        current_price: float,
        portfolio_value: float
    ) -> float:
        """
        Calcule taille position optimale
        """
        # Métriques actuelles
        current_dd = self.get_current_drawdown()
        portfolio_vol = self.get_portfolio_volatility()
        
        # Kelly adaptatif
        kelly_size = self.kelly_calculator.calculate_position_size(
            win_probability=signal_probability,
            avg_win=self.get_avg_win(),
            avg_loss=self.get_avg_loss(),
            current_drawdown=current_dd,
            portfolio_volatility=portfolio_vol
        )
        
        # Convertir en nombre d'unités
        position_value = portfolio_value * kelly_size
        units = position_value / current_price
        
        return units
        
    def _validate_params(self, params: Dict) -> bool:
        """
        Valide nouveaux paramètres
        """
        validator = WalkForwardValidator()
        results = validator.validate(self.get_historical_data(), params)
        
        # Critères validation
        if results['mean_sharpe'] < 1.5:
            return False
        if results['mean_drawdown'] > 0.10:
            return False
            
        return True
        
    def get_model_explanation(self, prediction: float) -> Dict:
        """
        Explique décision du modèle (SHAP values)
        """
        import shap
        
        explainer = shap.TreeExplainer(self.model)
        shap_values = explainer.shap_values(self.current_features)
        
        return {
            'prediction': prediction,
            'feature_importance': dict(zip(
                self.feature_names,
                shap_values[0]
            )),
            'base_value': explainer.expected_value
        }

📊 Métriques de Monitoring IA

Dashboard Métriques

AI_METRICS = {
    'optimization': {
        'last_optimization_date': datetime,
        'optimization_frequency': str,
        'parameters_changed': int,
        'improvement_sharpe': float,
    },
    'regime_detection': {
        'current_regime': str,
        'regime_probability': float,
        'regime_changes_last_30d': int,
    },
    'parameter_drift': {
        'drift_detected': bool,
        'drift_magnitude': float,
        'days_since_last_drift': int,
    },
    'ab_testing': {
        'active_tests': int,
        'winning_variant': str,
        'improvement_vs_control': float,
    },
    'model_performance': {
        'sharpe_ratio_7d': float,
        'sharpe_ratio_30d': float,
        'calibration_score': float,  # Brier score
        'feature_stability': float,
    }
}

🚀 Prochaines Étapes

Phase 1 : Implémentation de Base

  • Optimisation Optuna basique
  • Regime detection HMM
  • Kelly Criterion adaptatif
  • Walk-forward validation

Phase 2 : Fonctionnalités Avancées

  • A/B testing automatique
  • Reinforcement Learning sizing
  • Parameter drift detection
  • SHAP explainability

Phase 3 : Production

  • Monitoring temps réel
  • Alertes dégradation
  • Auto-retraining pipeline
  • Audit trail complet

Note : Ce framework garantit que l'IA reste adaptative et auto-critique, ajustant continuellement ses décisions pour maximiser la performance ajustée du risque.