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:
Tika
2026-03-08 17:38:09 +00:00
commit da30ef19ed
111 changed files with 31723 additions and 0 deletions

798
docs/AI_FRAMEWORK.md Normal file
View File

@@ -0,0 +1,798 @@
# 🤖 Framework IA Adaptative - Trading AI Secure
## 📋 Table des Matières
1. [Vue d'ensemble](#vue-densemble)
2. [Philosophie de l'IA Auto-Optimisante](#philosophie-de-lia-auto-optimisante)
3. [Architecture ML](#architecture-ml)
4. [Optimisation Continue des Paramètres](#optimisation-continue-des-paramètres)
5. [Regime Detection](#regime-detection)
6. [Position Sizing Adaptatif](#position-sizing-adaptatif)
7. [Validation et Anti-Overfitting](#validation-et-anti-overfitting)
8. [Implémentation Technique](#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
```python
# 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** :
```python
# 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é** :
```python
# 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
```python
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
```python
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
```python
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)
```python
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
```python
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
```python
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
```python
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
```python
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
```python
# 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
```python
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.

575
docs/ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,575 @@
# 🏗️ Architecture Détaillée - Trading AI Secure
## 📋 Table des Matières
1. [Vue d'ensemble](#vue-densemble)
2. [Architecture Globale](#architecture-globale)
3. [Modules Core](#modules-core)
4. [Flux de Données](#flux-de-données)
5. [Patterns et Principes](#patterns-et-principes)
6. [Sécurité](#sécurité)
7. [Scalabilité](#scalabilité)
---
## 🎯 Vue d'ensemble
### Principes Architecturaux
1. **Separation of Concerns** : Chaque module a une responsabilité unique
2. **Dependency Injection** : Facilite tests et modularité
3. **Event-Driven** : Communication asynchrone entre composants
4. **Fail-Safe** : Dégradation gracieuse en cas d'erreur
5. **Observable** : Monitoring et logging à tous les niveaux
### Stack Technologique
```yaml
Backend:
Language: Python 3.11+
Framework: FastAPI
Async: asyncio + threading
Data:
Storage: PostgreSQL (positions, trades)
Cache: Redis (market data, signals)
Time-Series: InfluxDB (métriques)
ML/AI:
Core: scikit-learn, XGBoost, LightGBM
Optimization: Optuna
Deep Learning: TensorFlow/PyTorch (optionnel)
Monitoring:
Metrics: Prometheus
Visualization: Grafana
Logging: ELK Stack (Elasticsearch, Logstash, Kibana)
UI:
Dashboard: Streamlit
API Docs: Swagger/OpenAPI
```
---
## 🏛️ Architecture Globale
### Diagramme de Haut Niveau
```
┌─────────────────────────────────────────────────────────────────┐
│ TRADING AI SECURE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ UI LAYER │ │ API LAYER │ │ MONITORING │ │
│ │ │ │ │ │ │ │
│ │ Streamlit │ │ FastAPI │ │ Prometheus │ │
│ │ Dashboard │ │ REST API │ │ Grafana │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └─────────────────┼─────────────────┘ │
│ │ │
│ ┌────────────────────────▼────────────────────────┐ │
│ │ ORCHESTRATION LAYER │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Strategy │ │ Risk │ │ │
│ │ │ Engine │ │ Manager │ │ │
│ │ │ (Singleton) │ │ (Singleton) │ │ │
│ │ └──────┬───────┘ └──────┬───────┘ │ │
│ │ │ │ │ │
│ │ └────────┬────────┘ │ │
│ │ │ │ │
│ └──────────────────┼──────────────────────────────┘ │
│ │ │
│ ┌──────────────────▼──────────────────────────────┐ │
│ │ CORE SERVICES │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Data │ │ ML │ │ Order │ │ │
│ │ │ Service │ │ Engine │ │ Manager │ │ │
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │
│ │ │ │ │ │ │
│ └───────┼─────────────┼─────────────┼─────────────┘ │
│ │ │ │ │
│ ┌───────▼─────────────▼─────────────▼─────────────┐ │
│ │ DATA & INTEGRATION LAYER │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Market │ │ IG │ │ Cache │ │ │
│ │ │ Data │ │ API │ │ (Redis) │ │ │
│ │ │ Sources │ │Connector │ │ │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ PERSISTENCE LAYER │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │PostgreSQL│ │ InfluxDB │ │ File │ │ │
│ │ │(Trades, │ │(Metrics, │ │ System │ │ │
│ │ │Positions)│ │TimeSeries│ │ (Logs) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
---
## 🔧 Modules Core
### 1. Strategy Engine
**Responsabilité** : Orchestration des stratégies de trading
```python
# src/core/strategy_engine.py
class StrategyEngine:
"""
Moteur central de gestion des stratégies
Responsabilités:
- Charger et initialiser stratégies
- Distribuer données marché
- Collecter signaux
- Coordonner exécution
"""
def __init__(self):
self.strategies: Dict[str, BaseStrategy] = {}
self.active_signals: List[Signal] = []
self.risk_manager = RiskManager()
self.order_manager = OrderManager()
async def run(self):
"""Boucle principale"""
while True:
# 1. Récupérer données marché
market_data = await self.fetch_market_data()
# 2. Analyser avec chaque stratégie
signals = await self.analyze_strategies(market_data)
# 3. Filtrer avec risk manager
valid_signals = self.risk_manager.filter_signals(signals)
# 4. Exécuter signaux valides
await self.execute_signals(valid_signals)
# 5. Mettre à jour positions
await self.update_positions()
# 6. Sleep jusqu'à prochaine itération
await asyncio.sleep(self.interval)
```
### 2. Risk Manager (Singleton)
**Responsabilité** : Gestion centralisée du risque
```python
# src/core/risk_manager.py
class RiskManager:
"""
Singleton Risk Manager
Garantit:
- Une seule instance
- État global cohérent
- Thread-safe
"""
_instance = None
_lock = threading.Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not hasattr(self, 'initialized'):
self.initialized = True
self.positions = {}
self.portfolio_value = 0.0
self.peak_value = 0.0
# ... autres attributs
```
### 3. Data Service
**Responsabilité** : Abstraction des sources de données
```python
# src/data/data_service.py
class DataService:
"""
Service unifié d'accès aux données
Features:
- Multi-source avec failover
- Cache intelligent
- Validation données
- Rate limiting
"""
def __init__(self):
self.sources = self._initialize_sources()
self.cache = RedisCache()
self.validator = DataValidator()
async def get_market_data(
self,
symbol: str,
timeframe: str,
start: datetime,
end: datetime
) -> pd.DataFrame:
"""
Récupère données marché avec failover
"""
# 1. Check cache
cached = await self.cache.get(symbol, timeframe, start, end)
if cached:
return cached
# 2. Essayer sources par priorité
for source in self.sources:
try:
data = await source.fetch(symbol, timeframe, start, end)
# 3. Valider
if self.validator.validate(data):
# 4. Cache
await self.cache.set(symbol, timeframe, data)
return data
except Exception as e:
logger.warning(f"Source {source.name} failed: {e}")
continue
raise DataUnavailableError("All sources failed")
```
### 4. ML Engine
**Responsabilité** : Intelligence artificielle adaptative
```python
# src/ml/ml_engine.py
class MLEngine:
"""
Moteur ML adaptatif
Features:
- Ensemble de modèles
- Auto-retraining
- Parameter optimization
- Regime detection
"""
def __init__(self):
self.models = self._initialize_models()
self.optimizer = OptunaOptimizer()
self.regime_detector = RegimeDetector()
async def predict(self, features: pd.DataFrame) -> Dict:
"""
Prédiction avec ensemble
"""
# 1. Détecter régime
regime = self.regime_detector.detect(features)
# 2. Sélectionner modèles selon régime
active_models = self._select_models(regime)
# 3. Prédictions individuelles
predictions = []
for model in active_models:
pred = model.predict(features)
predictions.append(pred)
# 4. Agrégation (stacking)
final_prediction = self._aggregate(predictions)
return {
'prediction': final_prediction,
'confidence': self._calculate_confidence(predictions),
'regime': regime
}
async def optimize_daily(self):
"""
Optimisation quotidienne des paramètres
"""
# 1. Récupérer performance récente
recent_performance = self._get_recent_performance()
# 2. Détecter drift
if self._detect_drift(recent_performance):
# 3. Lancer optimisation Optuna
new_params = await self.optimizer.optimize()
# 4. Valider avec backtesting
if self._validate_params(new_params):
# 5. Appliquer nouveaux paramètres
self._update_parameters(new_params)
```
---
## 🔄 Flux de Données
### Flux Principal (Trading Loop)
```
┌─────────────────────────────────────────────────────────────┐
│ TRADING LOOP (60s) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. FETCH MARKET DATA │
│ ├─ Check cache │
│ ├─ Fetch from sources (failover) │
│ └─ Validate & store │
│ │
│ 2. ANALYZE STRATEGIES │
│ ├─ Calculate indicators │
│ ├─ ML predictions │
│ ├─ Generate signals │
│ └─ Calculate confidence │
│ │
│ 3. RISK VALIDATION │
│ ├─ Check portfolio risk │
│ ├─ Validate position size │
│ ├─ Check correlation │
│ ├─ Verify margin │
│ └─ Circuit breakers │
│ │
│ 4. ORDER EXECUTION │
│ ├─ Place orders (IG API) │
│ ├─ Confirm execution │
│ └─ Update positions │
│ │
│ 5. MONITORING │
│ ├─ Update metrics │
│ ├─ Check alerts │
│ └─ Log events │
│ │
│ 6. SLEEP (until next iteration) │
│ │
└─────────────────────────────────────────────────────────────┘
```
### Flux Optimisation (Daily)
```
┌─────────────────────────────────────────────────────────────┐
│ OPTIMIZATION LOOP (Daily 00:00) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. COLLECT PERFORMANCE DATA │
│ ├─ Last 30 days trades │
│ ├─ Calculate metrics │
│ └─ Detect drift │
│ │
│ 2. PARAMETER OPTIMIZATION (if drift detected) │
│ ├─ Define search space │
│ ├─ Run Optuna (Bayesian) │
│ ├─ Backtest candidates │
│ └─ Select best parameters │
│ │
│ 3. VALIDATION │
│ ├─ Walk-forward analysis │
│ ├─ Monte Carlo simulation │
│ └─ Out-of-sample test │
│ │
│ 4. A/B TESTING │
│ ├─ Deploy variant in paper trading │
│ ├─ Monitor 7 days │
│ └─ Compare vs control │
│ │
│ 5. DEPLOYMENT (if validated) │
│ ├─ Update strategy parameters │
│ ├─ Retrain ML models │
│ └─ Notify operators │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
## 🎨 Patterns et Principes
### Design Patterns Utilisés
#### 1. Singleton (Risk Manager)
```python
class RiskManager:
_instance = None
_lock = threading.Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
```
**Pourquoi** : Garantir une seule instance pour état global cohérent
#### 2. Strategy Pattern (Stratégies de Trading)
```python
class BaseStrategy(ABC):
@abstractmethod
def analyze(self, data):
pass
class ScalpingStrategy(BaseStrategy):
def analyze(self, data):
# Implémentation scalping
pass
class IntradayStrategy(BaseStrategy):
def analyze(self, data):
# Implémentation intraday
pass
```
**Pourquoi** : Facilite ajout de nouvelles stratégies
#### 3. Observer Pattern (Events)
```python
class EventBus:
def __init__(self):
self.subscribers = {}
def subscribe(self, event_type, callback):
if event_type not in self.subscribers:
self.subscribers[event_type] = []
self.subscribers[event_type].append(callback)
def publish(self, event_type, data):
for callback in self.subscribers.get(event_type, []):
callback(data)
# Usage
event_bus.subscribe('trade_executed', log_trade)
event_bus.subscribe('trade_executed', update_metrics)
event_bus.publish('trade_executed', trade_data)
```
**Pourquoi** : Découplage entre composants
#### 4. Factory Pattern (Création Stratégies)
```python
class StrategyFactory:
@staticmethod
def create(strategy_type: str, config: Dict) -> BaseStrategy:
if strategy_type == 'scalping':
return ScalpingStrategy(config)
elif strategy_type == 'intraday':
return IntradayStrategy(config)
elif strategy_type == 'swing':
return SwingStrategy(config)
else:
raise ValueError(f"Unknown strategy: {strategy_type}")
```
**Pourquoi** : Centralise logique de création
### Principes SOLID
- **S**ingle Responsibility : Chaque classe une responsabilité
- **O**pen/Closed : Ouvert extension, fermé modification
- **L**iskov Substitution : Sous-classes substituables
- **I**nterface Segregation : Interfaces spécifiques
- **D**ependency Inversion : Dépendre d'abstractions
---
## 🔒 Sécurité
### Niveaux de Sécurité
```
┌─────────────────────────────────────────────────────────────┐
│ SECURITY LAYERS │
├─────────────────────────────────────────────────────────────┤
│ │
│ LAYER 1: Authentication & Authorization │
│ ├─ API Key management │
│ ├─ OAuth 2.0 (IG Markets) │
│ └─ Role-based access control │
│ │
│ LAYER 2: Data Encryption │
│ ├─ Credentials encrypted at rest │
│ ├─ TLS/SSL for API calls │
│ └─ Database encryption │
│ │
│ LAYER 3: Input Validation │
│ ├─ Pydantic models │
│ ├─ SQL injection prevention │
│ └─ XSS protection │
│ │
│ LAYER 4: Rate Limiting │
│ ├─ API rate limiting │
│ ├─ Brute force protection │
│ └─ DDoS mitigation │
│ │
│ LAYER 5: Audit & Monitoring │
│ ├─ All actions logged │
│ ├─ Anomaly detection │
│ └─ Security alerts │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
## 📈 Scalabilité
### Stratégies de Scaling
#### Horizontal Scaling
```
┌─────────────────────────────────────────────────────────────┐
│ HORIZONTAL SCALING STRATEGY │
├─────────────────────────────────────────────────────────────┤
│ │
│ Load Balancer │
│ │ │
│ ├─── Instance 1 (Scalping) │
│ ├─── Instance 2 (Intraday) │
│ └─── Instance 3 (Swing) │
│ │
│ Shared: │
│ ├─ Redis (Cache) │
│ ├─ PostgreSQL (Positions) │
│ └─ Message Queue (RabbitMQ) │
│ │
└─────────────────────────────────────────────────────────────┘
```
#### Vertical Scaling
- Augmenter RAM pour cache plus large
- Plus de CPU cores pour ML parallèle
- SSD NVMe pour I/O rapide
---
**Architecture complète et évolutive !**

585
docs/BACKTESTING_GUIDE.md Normal file
View File

@@ -0,0 +1,585 @@
# 🧪 Guide de Backtesting - Trading AI Secure
## 📋 Table des Matières
1. [Philosophie Anti-Overfitting](#philosophie-anti-overfitting)
2. [Walk-Forward Analysis](#walk-forward-analysis)
3. [Out-of-Sample Testing](#out-of-sample-testing)
4. [Monte Carlo Simulation](#monte-carlo-simulation)
5. [Paper Trading](#paper-trading)
6. [Métriques de Validation](#métriques-de-validation)
7. [Implémentation](#implémentation)
---
## 🎯 Philosophie Anti-Overfitting
### Principe Fondamental
**"Une stratégie qui performe parfaitement en backtest est probablement sur-optimisée"**
### Les 7 Règles d'Or du Backtesting
1.**Toujours réserver 30% des données pour out-of-sample**
2.**Utiliser walk-forward analysis (pas de look-ahead bias)**
3.**Valider avec Monte Carlo (10,000+ simulations)**
4.**Paper trading obligatoire 30 jours minimum**
5.**Inclure coûts réalistes (slippage, commissions)**
6.**Tester sur multiple marchés/périodes**
7.**Documenter tous les paramètres testés (éviter cherry-picking)**
---
## 🔄 Walk-Forward Analysis
### Concept
La walk-forward analysis simule le trading réel en :
1. Entraînant sur une fenêtre passée
2. Testant sur la fenêtre suivante
3. Glissant les fenêtres progressivement
```
┌────────────────────────────────────────────────────────────┐
│ WALK-FORWARD ANALYSIS │
├────────────────────────────────────────────────────────────┤
│ │
│ Période 1: │
│ [====TRAIN====][TEST] │
│ │
│ Période 2: │
│ [====TRAIN====][TEST] │
│ │
│ Période 3: │
│ [====TRAIN====][TEST] │
│ │
│ Période 4: │
│ [====TRAIN====][TEST] │
│ │
└────────────────────────────────────────────────────────────┘
```
### Implémentation
```python
# src/backtesting/walk_forward.py
from typing import Dict, List, Tuple
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
class WalkForwardAnalyzer:
"""
Walk-Forward Analysis Engine
Paramètres:
- train_window: Taille fenêtre entraînement (ex: 252 jours = 1 an)
- test_window: Taille fenêtre test (ex: 63 jours = 3 mois)
- step_size: Pas de glissement (ex: 21 jours = 1 mois)
"""
def __init__(
self,
train_window: int = 252,
test_window: int = 63,
step_size: int = 21
):
self.train_window = train_window
self.test_window = test_window
self.step_size = step_size
self.results = []
def run(
self,
data: pd.DataFrame,
strategy_class,
optimization_func
) -> Dict:
"""
Exécute walk-forward analysis
Args:
data: Données historiques complètes
strategy_class: Classe de stratégie à tester
optimization_func: Fonction d'optimisation des paramètres
Returns:
Résultats agrégés de tous les walks
"""
total_length = len(data)
current_pos = 0
while current_pos + self.train_window + self.test_window <= total_length:
# Fenêtre entraînement
train_start = current_pos
train_end = current_pos + self.train_window
train_data = data.iloc[train_start:train_end]
# Fenêtre test
test_start = train_end
test_end = train_end + self.test_window
test_data = data.iloc[test_start:test_end]
# Optimiser paramètres sur train
optimal_params = optimization_func(train_data, strategy_class)
# Tester sur test
strategy = strategy_class(optimal_params)
test_results = self._backtest_strategy(strategy, test_data)
# Enregistrer résultats
self.results.append({
'train_period': (train_data.index[0], train_data.index[-1]),
'test_period': (test_data.index[0], test_data.index[-1]),
'optimal_params': optimal_params,
'test_sharpe': test_results['sharpe'],
'test_returns': test_results['total_return'],
'test_max_dd': test_results['max_drawdown'],
'test_win_rate': test_results['win_rate'],
'num_trades': test_results['num_trades']
})
# Glisser fenêtre
current_pos += self.step_size
return self._aggregate_results()
def _backtest_strategy(
self,
strategy,
data: pd.DataFrame
) -> Dict:
"""
Backtest stratégie sur données
"""
trades = []
equity_curve = [10000] # Capital initial
for i in range(len(data)):
current_data = data.iloc[:i+1]
# Générer signal
signal = strategy.analyze(current_data)
if signal:
# Simuler trade
trade_result = self._simulate_trade(
signal,
data.iloc[i:min(i+100, len(data))] # Données futures pour exit
)
trades.append(trade_result)
equity_curve.append(equity_curve[-1] + trade_result['pnl'])
# Calculer métriques
returns = pd.Series(equity_curve).pct_change().dropna()
return {
'total_return': (equity_curve[-1] - equity_curve[0]) / equity_curve[0],
'sharpe': self._calculate_sharpe(returns),
'max_drawdown': self._calculate_max_drawdown(equity_curve),
'win_rate': len([t for t in trades if t['pnl'] > 0]) / len(trades) if trades else 0,
'num_trades': len(trades),
'equity_curve': equity_curve
}
def _simulate_trade(
self,
signal: 'Signal',
future_data: pd.DataFrame
) -> Dict:
"""
Simule exécution d'un trade
"""
entry_price = signal.entry_price
stop_loss = signal.stop_loss
take_profit = signal.take_profit
# Ajouter slippage réaliste
slippage = 0.001 # 0.1%
entry_price *= (1 + slippage if signal.direction == 'LONG' else 1 - slippage)
# Simuler holding jusqu'à exit
for i, row in future_data.iterrows():
# Check stop-loss
if signal.direction == 'LONG':
if row['low'] <= stop_loss:
exit_price = stop_loss * (1 - slippage)
pnl = (exit_price - entry_price) / entry_price
return {'pnl': pnl, 'exit_reason': 'stop_loss', 'holding_bars': i}
# Check take-profit
if row['high'] >= take_profit:
exit_price = take_profit * (1 - slippage)
pnl = (exit_price - entry_price) / entry_price
return {'pnl': pnl, 'exit_reason': 'take_profit', 'holding_bars': i}
else: # SHORT
if row['high'] >= stop_loss:
exit_price = stop_loss * (1 + slippage)
pnl = (entry_price - exit_price) / entry_price
return {'pnl': pnl, 'exit_reason': 'stop_loss', 'holding_bars': i}
if row['low'] <= take_profit:
exit_price = take_profit * (1 + slippage)
pnl = (entry_price - exit_price) / entry_price
return {'pnl': pnl, 'exit_reason': 'take_profit', 'holding_bars': i}
# Timeout (max holding time)
exit_price = future_data.iloc[-1]['close']
if signal.direction == 'LONG':
pnl = (exit_price - entry_price) / entry_price
else:
pnl = (entry_price - exit_price) / entry_price
return {'pnl': pnl, 'exit_reason': 'timeout', 'holding_bars': len(future_data)}
def _aggregate_results(self) -> Dict:
"""
Agrège résultats de tous les walks
"""
if not self.results:
return {}
sharpes = [r['test_sharpe'] for r in self.results]
returns = [r['test_returns'] for r in self.results]
drawdowns = [r['test_max_dd'] for r in self.results]
win_rates = [r['test_win_rate'] for r in self.results]
return {
'num_walks': len(self.results),
'avg_sharpe': np.mean(sharpes),
'std_sharpe': np.std(sharpes),
'min_sharpe': np.min(sharpes),
'max_sharpe': np.max(sharpes),
'avg_return': np.mean(returns),
'avg_max_dd': np.mean(drawdowns),
'worst_max_dd': np.max(drawdowns),
'avg_win_rate': np.mean(win_rates),
'consistency': len([s for s in sharpes if s > 1.0]) / len(sharpes),
'all_walks': self.results
}
def _calculate_sharpe(self, returns: pd.Series, risk_free=0.02) -> float:
"""Calcule Sharpe Ratio"""
excess_returns = returns - risk_free / 252
return np.mean(excess_returns) / np.std(excess_returns) * np.sqrt(252)
def _calculate_max_drawdown(self, equity_curve: List[float]) -> float:
"""Calcule Maximum Drawdown"""
peak = np.maximum.accumulate(equity_curve)
drawdown = (np.array(equity_curve) - peak) / peak
return np.min(drawdown)
```
---
## 📊 Out-of-Sample Testing
### Principe
**Jamais optimiser sur 100% des données !**
```
┌────────────────────────────────────────────────────────────┐
│ SPLIT IN-SAMPLE / OUT-OF-SAMPLE │
├────────────────────────────────────────────────────────────┤
│ │
│ [========== IN-SAMPLE 70% ==========][OUT-SAMPLE 30%] │
│ │
│ Optimisation paramètres Validation finale │
│ Walk-forward analysis Performance réelle │
│ Tuning hyperparamètres JAMAIS touché │
│ │
└────────────────────────────────────────────────────────────┘
```
### Implémentation
```python
class OutOfSampleValidator:
"""
Validation out-of-sample stricte
"""
def __init__(self, oos_ratio=0.30):
self.oos_ratio = oos_ratio
def split_data(
self,
data: pd.DataFrame
) -> Tuple[pd.DataFrame, pd.DataFrame]:
"""
Split données en in-sample / out-of-sample
"""
split_point = int(len(data) * (1 - self.oos_ratio))
in_sample = data.iloc[:split_point]
out_of_sample = data.iloc[split_point:]
return in_sample, out_of_sample
def validate(
self,
strategy,
in_sample_data: pd.DataFrame,
out_of_sample_data: pd.DataFrame
) -> Dict:
"""
Valide stratégie sur out-of-sample
"""
# Performance in-sample
is_results = self._backtest(strategy, in_sample_data)
# Performance out-of-sample (CRITIQUE)
oos_results = self._backtest(strategy, out_of_sample_data)
# Comparer performances
degradation = self._calculate_degradation(is_results, oos_results)
return {
'in_sample': is_results,
'out_of_sample': oos_results,
'degradation': degradation,
'is_valid': self._is_valid_strategy(degradation)
}
def _calculate_degradation(
self,
is_results: Dict,
oos_results: Dict
) -> Dict:
"""
Calcule dégradation performance IS → OOS
"""
return {
'sharpe_degradation': (is_results['sharpe'] - oos_results['sharpe']) / is_results['sharpe'],
'return_degradation': (is_results['total_return'] - oos_results['total_return']) / is_results['total_return'],
'winrate_degradation': (is_results['win_rate'] - oos_results['win_rate']) / is_results['win_rate'],
}
def _is_valid_strategy(self, degradation: Dict) -> bool:
"""
Critères de validation
Stratégie valide si:
- Sharpe OOS > 1.0
- Dégradation Sharpe < 30%
- Dégradation Return < 40%
"""
if degradation['sharpe_degradation'] > 0.30:
return False
if degradation['return_degradation'] > 0.40:
return False
return True
```
---
## 🎲 Monte Carlo Simulation
### Objectif
Tester robustesse en simulant milliers de scénarios aléatoires
```python
class MonteCarloSimulator:
"""
Simulation Monte Carlo pour validation robustesse
"""
def __init__(self, n_simulations=10000):
self.n_simulations = n_simulations
def simulate(
self,
historical_trades: List[Dict]
) -> Dict:
"""
Simule N scénarios en réordonnant trades
Principe:
- Même trades, ordre différent
- Teste sensibilité à la séquence
- Identifie lucky streaks vs. edge réel
"""
results = []
for _ in range(self.n_simulations):
# Réordonner trades aléatoirement
shuffled_trades = np.random.permutation(historical_trades)
# Calculer equity curve
equity = self._calculate_equity_curve(shuffled_trades)
# Métriques
sharpe = self._calculate_sharpe(equity)
max_dd = self._calculate_max_drawdown(equity)
final_return = (equity[-1] - equity[0]) / equity[0]
results.append({
'sharpe': sharpe,
'max_dd': max_dd,
'return': final_return
})
return self._analyze_distribution(results)
def _analyze_distribution(self, results: List[Dict]) -> Dict:
"""
Analyse distribution résultats Monte Carlo
"""
sharpes = [r['sharpe'] for r in results]
returns = [r['return'] for r in results]
drawdowns = [r['max_dd'] for r in results]
return {
# Sharpe
'sharpe_mean': np.mean(sharpes),
'sharpe_median': np.median(sharpes),
'sharpe_5th_percentile': np.percentile(sharpes, 5),
'sharpe_95th_percentile': np.percentile(sharpes, 95),
'prob_sharpe_positive': np.mean(np.array(sharpes) > 0),
'prob_sharpe_above_1': np.mean(np.array(sharpes) > 1.0),
# Returns
'return_mean': np.mean(returns),
'return_5th_percentile': np.percentile(returns, 5),
'return_95th_percentile': np.percentile(returns, 95),
'prob_positive_return': np.mean(np.array(returns) > 0),
# Drawdown
'max_dd_mean': np.mean(drawdowns),
'max_dd_95th_percentile': np.percentile(drawdowns, 95),
'prob_dd_below_10pct': np.mean(np.array(drawdowns) > -0.10),
}
def _calculate_equity_curve(self, trades: List[Dict]) -> List[float]:
"""Calcule equity curve à partir de trades"""
equity = [10000] # Capital initial
for trade in trades:
pnl = trade['pnl'] * equity[-1]
equity.append(equity[-1] + pnl)
return equity
```
---
## 📝 Paper Trading
### Protocole Strict
```python
class PaperTradingEngine:
"""
Paper trading avec conditions réelles
Règles:
- Minimum 30 jours de trading
- Données temps réel (pas historiques)
- Slippage et commissions réalistes
- Latence simulée
- Validation quotidienne
"""
def __init__(self, min_days=30):
self.min_days = min_days
self.start_date = None
self.trades = []
self.daily_metrics = []
def start(self):
"""Démarre paper trading"""
self.start_date = datetime.now()
logger.info(f"Paper trading started. Minimum duration: {self.min_days} days")
def can_go_live(self) -> Tuple[bool, str]:
"""
Vérifie si stratégie peut passer en live
Critères:
- Minimum 30 jours
- Sharpe > 1.5
- Max DD < 10%
- Win rate > 55%
- Minimum 50 trades
"""
if not self.start_date:
return False, "Paper trading not started"
days_elapsed = (datetime.now() - self.start_date).days
if days_elapsed < self.min_days:
return False, f"Only {days_elapsed}/{self.min_days} days completed"
# Calculer métriques
metrics = self._calculate_metrics()
# Vérifier critères
if metrics['sharpe'] < 1.5:
return False, f"Sharpe {metrics['sharpe']:.2f} below 1.5"
if metrics['max_dd'] > 0.10:
return False, f"Max DD {metrics['max_dd']:.2%} above 10%"
if metrics['win_rate'] < 0.55:
return False, f"Win rate {metrics['win_rate']:.2%} below 55%"
if len(self.trades) < 50:
return False, f"Only {len(self.trades)} trades (minimum 50)"
return True, "All criteria met. Ready for live trading."
def _calculate_metrics(self) -> Dict:
"""Calcule métriques paper trading"""
# TODO: Implémenter calculs
pass
```
---
## 📊 Métriques de Validation
### Seuils Minimaux
```yaml
validation_criteria:
# Performance
sharpe_ratio:
in_sample: 1.8
out_of_sample: 1.5
paper_trading: 1.5
# Risk
max_drawdown:
in_sample: 0.08
out_of_sample: 0.10
paper_trading: 0.10
# Consistency
win_rate:
minimum: 0.55
target: 0.60
profit_factor:
minimum: 1.3
target: 1.5
# Robustness
monte_carlo:
prob_positive_sharpe: 0.95
sharpe_5th_percentile: 0.8
# Sample size
minimum_trades:
in_sample: 100
out_of_sample: 30
paper_trading: 50
```
---
**Documentation complète du backtesting terminée !**

615
docs/CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,615 @@
# 🤝 Guide de Contribution - Trading AI Secure
## 📋 Table des Matières
1. [Code of Conduct](#code-of-conduct)
2. [Comment Contribuer](#comment-contribuer)
3. [Standards de Code](#standards-de-code)
4. [Workflow Git](#workflow-git)
5. [Tests](#tests)
6. [Documentation](#documentation)
7. [Review Process](#review-process)
---
## 📜 Code of Conduct
### Nos Valeurs
- **Respect** : Traiter tous les contributeurs avec respect
- **Collaboration** : Travailler ensemble vers un objectif commun
- **Excellence** : Viser la qualité dans tout ce que nous faisons
- **Transparence** : Communication ouverte et honnête
- **Sécurité** : Priorité absolue dans le trading
### Comportements Attendus
✅ Être accueillant et inclusif
✅ Respecter les opinions différentes
✅ Accepter les critiques constructives
✅ Se concentrer sur ce qui est meilleur pour la communauté
✅ Faire preuve d'empathie
### Comportements Inacceptables
❌ Langage ou images inappropriés
❌ Attaques personnelles ou politiques
❌ Harcèlement public ou privé
❌ Publication d'informations privées sans permission
❌ Conduite non professionnelle
---
## 🚀 Comment Contribuer
### Types de Contributions
#### 1. Rapporter des Bugs
**Template Issue Bug** :
```markdown
**Description du Bug**
Description claire et concise du bug.
**Étapes pour Reproduire**
1. Aller à '...'
2. Cliquer sur '...'
3. Voir erreur
**Comportement Attendu**
Ce qui devrait se passer.
**Comportement Actuel**
Ce qui se passe réellement.
**Screenshots**
Si applicable.
**Environnement**
- OS: [e.g. Windows 11]
- Python: [e.g. 3.11.5]
- Version: [e.g. 0.1.0]
**Logs**
```
Coller logs pertinents
```
```
#### 2. Proposer des Features
**Template Issue Feature** :
```markdown
**Problème à Résoudre**
Description du problème que cette feature résout.
**Solution Proposée**
Description de la solution.
**Alternatives Considérées**
Autres approches envisagées.
**Contexte Additionnel**
Informations supplémentaires.
```
#### 3. Améliorer la Documentation
- Corriger typos
- Clarifier explications
- Ajouter exemples
- Traduire documentation
#### 4. Développer du Code
- Nouvelles stratégies
- Améliorations ML
- Optimisations performance
- Nouveaux connecteurs de données
---
## 💻 Standards de Code
### Style Python (PEP 8)
```python
# ✅ BON
def calculate_position_size(
portfolio_value: float,
risk_per_trade: float,
stop_distance: float
) -> float:
"""
Calcule taille position optimale.
Args:
portfolio_value: Valeur totale du portfolio
risk_per_trade: Risque par trade (0.0 à 1.0)
stop_distance: Distance au stop-loss
Returns:
Taille de position en unités
Raises:
ValueError: Si paramètres invalides
"""
if portfolio_value <= 0:
raise ValueError("Portfolio value must be positive")
risk_amount = portfolio_value * risk_per_trade
position_size = risk_amount / stop_distance
return position_size
# ❌ MAUVAIS
def calc_pos(pv,rpt,sd):
return pv*rpt/sd
```
### Type Hints (Obligatoires)
```python
# ✅ BON
from typing import Dict, List, Optional
from datetime import datetime
def analyze_market(
data: pd.DataFrame,
timeframe: str,
indicators: List[str]
) -> Optional[Dict[str, float]]:
pass
# ❌ MAUVAIS
def analyze_market(data, timeframe, indicators):
pass
```
### Docstrings (Google Style)
```python
def backtest_strategy(
strategy: BaseStrategy,
data: pd.DataFrame,
initial_capital: float = 10000.0
) -> Dict[str, float]:
"""
Backtest une stratégie sur données historiques.
Cette fonction exécute un backtest complet incluant:
- Simulation des trades
- Calcul des métriques
- Gestion du risque
Args:
strategy: Instance de stratégie à tester
data: DataFrame avec données OHLCV
initial_capital: Capital initial en USD
Returns:
Dictionnaire avec métriques:
- 'total_return': Return total (%)
- 'sharpe_ratio': Sharpe ratio
- 'max_drawdown': Drawdown maximum (%)
- 'win_rate': Taux de réussite (%)
Raises:
ValueError: Si données insuffisantes
Example:
>>> strategy = ScalpingStrategy(config)
>>> data = load_historical_data('EURUSD', '1h')
>>> results = backtest_strategy(strategy, data)
>>> print(f"Sharpe: {results['sharpe_ratio']:.2f}")
Sharpe: 1.85
"""
pass
```
### Naming Conventions
```python
# Classes: PascalCase
class RiskManager:
pass
# Functions/Methods: snake_case
def calculate_sharpe_ratio():
pass
# Constants: UPPER_SNAKE_CASE
MAX_POSITION_SIZE = 0.05
DEFAULT_RISK_PER_TRADE = 0.02
# Private: _leading_underscore
def _internal_helper():
pass
# Variables: snake_case
portfolio_value = 10000.0
current_drawdown = 0.05
```
### Imports Organization
```python
# 1. Standard library
import os
import sys
from datetime import datetime, timedelta
from typing import Dict, List, Optional
# 2. Third-party
import numpy as np
import pandas as pd
from fastapi import FastAPI, HTTPException
# 3. Local
from src.core.risk_manager import RiskManager
from src.strategies.base_strategy import BaseStrategy
from src.utils.logger import get_logger
```
---
## 🌿 Workflow Git
### Branches
```
main
├── develop
│ ├── feature/add-new-strategy
│ ├── feature/improve-ml-engine
│ ├── bugfix/fix-risk-calculation
│ └── hotfix/critical-security-patch
```
**Conventions de nommage** :
- `feature/description` : Nouvelles fonctionnalités
- `bugfix/description` : Corrections de bugs
- `hotfix/description` : Corrections urgentes
- `docs/description` : Documentation
- `refactor/description` : Refactoring
- `test/description` : Ajout de tests
### Workflow Contribution
#### 1. Fork et Clone
```bash
# Fork sur GitHub
# Puis cloner votre fork
git clone https://github.com/VOTRE-USERNAME/trading-ai-secure.git
cd trading-ai-secure
# Ajouter upstream
git remote add upstream https://github.com/ORIGINAL-OWNER/trading-ai-secure.git
```
#### 2. Créer Branche
```bash
# Mettre à jour develop
git checkout develop
git pull upstream develop
# Créer branche feature
git checkout -b feature/ma-nouvelle-feature
```
#### 3. Développer
```bash
# Faire vos modifications
# ...
# Commiter régulièrement
git add .
git commit -m "feat: add new scalping indicator"
# Suivre conventions de commit (voir ci-dessous)
```
#### 4. Tester
```bash
# Lancer tests
pytest tests/
# Vérifier couverture
pytest --cov=src tests/
# Linter
pylint src/
black src/
isort src/
```
#### 5. Push et Pull Request
```bash
# Push vers votre fork
git push origin feature/ma-nouvelle-feature
# Créer Pull Request sur GitHub
# Remplir template PR
```
### Conventions de Commit
Format : `<type>(<scope>): <description>`
**Types** :
- `feat`: Nouvelle fonctionnalité
- `fix`: Correction de bug
- `docs`: Documentation
- `style`: Formatage (pas de changement de code)
- `refactor`: Refactoring
- `test`: Ajout de tests
- `chore`: Maintenance
**Exemples** :
```bash
feat(strategies): add VWAP indicator to intraday strategy
fix(risk): correct position sizing calculation
docs(readme): update installation instructions
test(backtesting): add Monte Carlo simulation tests
refactor(ml): optimize feature engineering pipeline
```
---
## 🧪 Tests
### Structure Tests
```
tests/
├── unit/
│ ├── test_risk_manager.py
│ ├── test_strategies.py
│ └── test_ml_engine.py
├── integration/
│ ├── test_data_sources.py
│ └── test_ig_api.py
├── e2e/
│ └── test_full_trading_loop.py
└── fixtures/
└── sample_data.py
```
### Écrire Tests
```python
# tests/unit/test_risk_manager.py
import pytest
from src.core.risk_manager import RiskManager
class TestRiskManager:
"""Tests pour RiskManager"""
@pytest.fixture
def risk_manager(self):
"""Fixture RiskManager"""
return RiskManager()
def test_singleton_pattern(self):
"""Vérifie pattern singleton"""
rm1 = RiskManager()
rm2 = RiskManager()
assert rm1 is rm2
def test_validate_trade_success(self, risk_manager):
"""Test validation trade valide"""
is_valid, error = risk_manager.validate_trade(
symbol='EURUSD',
quantity=1000,
price=1.1000,
stop_loss=1.0950,
take_profit=1.1100,
strategy='intraday'
)
assert is_valid is True
assert error is None
def test_validate_trade_no_stop_loss(self, risk_manager):
"""Test rejet si pas de stop-loss"""
is_valid, error = risk_manager.validate_trade(
symbol='EURUSD',
quantity=1000,
price=1.1000,
stop_loss=None, # Pas de stop-loss
take_profit=1.1100,
strategy='intraday'
)
assert is_valid is False
assert "stop-loss" in error.lower()
@pytest.mark.parametrize("position_size,expected", [
(0.01, True), # 1% OK
(0.05, True), # 5% OK
(0.10, False), # 10% trop grand
])
def test_position_size_limits(self, risk_manager, position_size, expected):
"""Test limites taille position"""
# ... test paramétré
```
### Coverage Minimum
- **Global** : 85%
- **Core modules** : 90%
- **Stratégies** : 85%
- **ML** : 80%
- **UI** : 70%
---
## 📚 Documentation
### Documentation Code
Chaque module doit avoir :
1. **Module docstring** : Description du module
2. **Class docstrings** : Description de la classe
3. **Method docstrings** : Description des méthodes
4. **Type hints** : Sur tous les paramètres et retours
### Documentation Utilisateur
Mettre à jour si changements :
- `README.md` : Vue d'ensemble
- `docs/GETTING_STARTED.md` : Guide démarrage
- `docs/ARCHITECTURE.md` : Architecture
- `docs/API.md` : Documentation API
### Exemples
Ajouter exemples d'utilisation :
```python
# examples/strategies/custom_strategy_example.py
"""
Exemple de création d'une stratégie custom.
Cet exemple montre comment:
- Hériter de BaseStrategy
- Implémenter les méthodes requises
- Configurer les paramètres
- Backtester la stratégie
"""
from src.strategies.base_strategy import BaseStrategy
class MyCustomStrategy(BaseStrategy):
"""Ma stratégie personnalisée"""
def analyze(self, data):
# Implémentation
pass
# Usage
if __name__ == "__main__":
strategy = MyCustomStrategy(config)
results = backtest_strategy(strategy, data)
print(results)
```
---
## 👀 Review Process
### Checklist PR
Avant de soumettre PR, vérifier :
- [ ] Code suit standards (PEP 8, type hints, docstrings)
- [ ] Tests ajoutés et passent (coverage > 85%)
- [ ] Documentation mise à jour
- [ ] Pas de secrets/credentials dans le code
- [ ] Commits suivent conventions
- [ ] Branch à jour avec develop
- [ ] Pas de conflits
### Template Pull Request
```markdown
## Description
Description claire des changements.
## Type de Changement
- [ ] Bug fix
- [ ] Nouvelle feature
- [ ] Breaking change
- [ ] Documentation
## Tests
- [ ] Tests unitaires ajoutés
- [ ] Tests d'intégration ajoutés
- [ ] Tous les tests passent
- [ ] Coverage > 85%
## Checklist
- [ ] Code suit standards
- [ ] Documentation mise à jour
- [ ] Pas de secrets dans le code
- [ ] Commits conventionnels
## Screenshots (si applicable)
## Notes Additionnelles
```
### Process de Review
1. **Automated Checks** : CI/CD vérifie tests, linting
2. **Code Review** : Au moins 1 reviewer approuve
3. **Testing** : Reviewer teste localement
4. **Merge** : Squash and merge vers develop
---
## 🎯 Priorités Contributions
### High Priority
- 🔴 Corrections de bugs critiques
- 🔴 Améliorations sécurité
- 🔴 Optimisations performance
### Medium Priority
- 🟡 Nouvelles stratégies
- 🟡 Améliorations ML
- 🟡 Documentation
### Low Priority
- 🟢 Refactoring
- 🟢 Optimisations mineures
- 🟢 Traductions
---
## 💬 Communication
### Channels
- **GitHub Issues** : Bugs, features
- **GitHub Discussions** : Questions, idées
- **Discord** : Chat temps réel
- **Email** : contact@trading-ai-secure.com
### Réponse
- Issues : < 48h
- PRs : < 72h
- Questions : < 24h
---
## 🏆 Reconnaissance
Les contributeurs sont reconnus dans :
- `CONTRIBUTORS.md`
- Release notes
- Documentation
---
**Merci de contribuer à Trading AI Secure ! 🚀**

540
docs/GETTING_STARTED.md Normal file
View File

@@ -0,0 +1,540 @@
# 🚀 Guide de Démarrage - Trading AI Secure
## 📋 Table des Matières
1. [Prérequis](#prérequis)
2. [Installation](#installation)
3. [Configuration](#configuration)
4. [Premier Lancement](#premier-lancement)
5. [Workflow Développement](#workflow-développement)
6. [Tests](#tests)
7. [Troubleshooting](#troubleshooting)
---
## 💻 Prérequis
### Système
- **OS** : Windows 10/11, Linux (Ubuntu 20.04+), macOS 11+
- **Python** : 3.11 ou supérieur
- **RAM** : 8 GB minimum (16 GB recommandé)
- **Disque** : 10 GB espace libre
- **Internet** : Connexion stable pour données temps réel
### Logiciels
```bash
# Python 3.11+
python --version # Doit afficher 3.11.x ou supérieur
# pip (gestionnaire de paquets)
pip --version
# Git
git --version
# (Optionnel) Docker
docker --version
```
### Connaissances Recommandées
- ✅ Python intermédiaire
- ✅ Bases de trading (ordres, stop-loss, etc.)
- ✅ Notions de machine learning (optionnel)
- ✅ Git basique
---
## 📥 Installation
### Étape 1 : Cloner le Repository
```bash
# Cloner le projet
git clone https://github.com/votre-username/trading-ai-secure.git
cd trading-ai-secure
# Vérifier structure
ls -la
```
### Étape 2 : Créer Environnement Virtuel
```bash
# Windows
python -m venv venv
venv\Scripts\activate
# Linux/macOS
python3 -m venv venv
source venv/bin/activate
# Vérifier activation (prompt doit afficher (venv))
```
### Étape 3 : Installer Dépendances
```bash
# Mettre à jour pip
pip install --upgrade pip
# Installer dépendances
pip install -r requirements.txt
# Vérifier installation
pip list
```
### Étape 4 : Installer Dépendances Optionnelles
```bash
# Pour développement
pip install -r requirements-dev.txt
# Pour backtesting avancé
pip install -r requirements-backtest.txt
# Pour production
pip install -r requirements-prod.txt
```
---
## ⚙️ Configuration
### Étape 1 : Copier Fichiers de Configuration
```bash
# Copier templates de configuration
cp config/risk_limits.example.yaml config/risk_limits.yaml
cp config/strategy_params.example.yaml config/strategy_params.yaml
cp config/data_sources.example.yaml config/data_sources.yaml
# NE PAS copier ig_config (contient credentials sensibles)
# Créer manuellement si nécessaire
```
### Étape 2 : Configurer Sources de Données
```yaml
# config/data_sources.yaml
data_sources:
# Yahoo Finance (gratuit, illimité)
yahoo_finance:
enabled: true
priority: 1
# Alpha Vantage (gratuit, 500 calls/jour)
alpha_vantage:
enabled: true
api_key: "YOUR_API_KEY_HERE" # Obtenir sur https://www.alphavantage.co/support/#api-key
priority: 2
rate_limit: 500 # calls per day
# Twelve Data (gratuit, 800 calls/jour)
twelve_data:
enabled: false
api_key: "YOUR_API_KEY_HERE" # Obtenir sur https://twelvedata.com/
priority: 3
rate_limit: 800
```
### Étape 3 : Obtenir Clés API Gratuites
#### Alpha Vantage (Recommandé)
1. Aller sur https://www.alphavantage.co/support/#api-key
2. Entrer email
3. Copier clé API
4. Coller dans `config/data_sources.yaml`
#### Twelve Data (Optionnel)
1. Créer compte sur https://twelvedata.com/
2. Aller dans Dashboard → API
3. Copier clé
4. Coller dans config
### Étape 4 : Configurer Risk Limits
```yaml
# config/risk_limits.yaml
global_limits:
max_portfolio_risk: 0.02 # 2% du capital max
max_position_size: 0.05 # 5% par position max
max_correlation: 0.7 # Corrélation max entre positions
max_drawdown: 0.10 # 10% drawdown max
daily_loss_limit: 0.03 # 3% perte journalière max
strategy_limits:
scalping:
max_trades_per_day: 50
risk_per_trade: 0.005 # 0.5% par trade
max_holding_time: 1800 # 30 minutes
intraday:
max_trades_per_day: 10
risk_per_trade: 0.015 # 1.5% par trade
max_holding_time: 86400 # 1 jour
swing:
max_trades_per_week: 5
risk_per_trade: 0.025 # 2.5% par trade
max_holding_time: 432000 # 5 jours
```
### Étape 5 : Variables d'Environnement
```bash
# Créer fichier .env
touch .env
# Ajouter variables (NE PAS COMMITER)
echo "ENVIRONMENT=development" >> .env
echo "LOG_LEVEL=INFO" >> .env
echo "INITIAL_CAPITAL=10000" >> .env
```
---
## 🎬 Premier Lancement
### Mode 1 : Backtesting (Recommandé pour débuter)
```bash
# Lancer backtesting sur données historiques
python src/main.py --mode backtest --strategy intraday --symbol EURUSD --period 1y
# Avec paramètres personnalisés
python src/main.py \
--mode backtest \
--strategy all \
--symbol EURUSD,GBPUSD,USDJPY \
--period 2y \
--initial-capital 10000
```
**Sortie attendue** :
```
[INFO] Loading historical data for EURUSD...
[INFO] Backtesting intraday strategy...
[INFO] Walk-forward analysis: 12 periods
[INFO] Results:
- Total Return: 15.3%
- Sharpe Ratio: 1.82
- Max Drawdown: 7.2%
- Win Rate: 58.3%
- Total Trades: 127
```
### Mode 2 : Paper Trading
```bash
# Lancer paper trading (simulation temps réel)
python src/main.py --mode paper --strategy intraday
# Avec dashboard
python src/main.py --mode paper --strategy all --dashboard
```
### Mode 3 : Dashboard Uniquement
```bash
# Lancer dashboard Streamlit
streamlit run src/ui/dashboard.py
# Ouvrir navigateur sur http://localhost:8501
```
---
## 🔄 Workflow Développement
### Workflow Quotidien
```bash
# 1. Activer environnement
source venv/bin/activate # Linux/macOS
venv\Scripts\activate # Windows
# 2. Mettre à jour code
git pull origin main
# 3. Installer nouvelles dépendances si nécessaire
pip install -r requirements.txt
# 4. Lancer tests
pytest tests/
# 5. Développer nouvelle feature
# ... éditer code ...
# 6. Tester localement
python src/main.py --mode backtest --strategy your_strategy
# 7. Commit et push
git add .
git commit -m "feat: add new strategy"
git push origin your-branch
```
### Structure Développement
```
Développement d'une nouvelle stratégie:
1. Créer fichier stratégie
src/strategies/your_strategy/your_strategy.py
2. Hériter de BaseStrategy
class YourStrategy(BaseStrategy):
...
3. Implémenter méthodes requises
- calculate_indicators()
- analyze()
- _calculate_confidence()
4. Créer tests
tests/test_your_strategy.py
5. Backtester
python src/main.py --mode backtest --strategy your_strategy
6. Valider métriques
- Sharpe > 1.5
- Max DD < 10%
- Win Rate > 55%
7. Paper trading 30 jours
python src/main.py --mode paper --strategy your_strategy
```
---
## 🧪 Tests
### Lancer Tests Unitaires
```bash
# Tous les tests
pytest
# Tests spécifiques
pytest tests/test_risk_manager.py
pytest tests/test_strategies.py
# Avec couverture
pytest --cov=src tests/
# Avec rapport HTML
pytest --cov=src --cov-report=html tests/
# Ouvrir htmlcov/index.html
```
### Tests d'Intégration
```bash
# Tests intégration données
pytest tests/integration/test_data_sources.py
# Tests intégration IG (nécessite credentials)
pytest tests/integration/test_ig_api.py --ig-demo
```
### Tests de Performance
```bash
# Benchmark stratégies
python tests/benchmark/benchmark_strategies.py
# Profiling
python -m cProfile -o profile.stats src/main.py --mode backtest
python -m pstats profile.stats
```
---
## 🐛 Troubleshooting
### Problème : Installation Dépendances Échoue
```bash
# Erreur: "Could not find a version that satisfies the requirement..."
# Solution 1: Mettre à jour pip
pip install --upgrade pip setuptools wheel
# Solution 2: Installer individuellement
pip install numpy pandas scikit-learn
# Solution 3: Utiliser conda (si disponible)
conda install -c conda-forge numpy pandas scikit-learn
```
### Problème : Erreur Import Module
```bash
# Erreur: "ModuleNotFoundError: No module named 'src'"
# Solution: Ajouter projet au PYTHONPATH
export PYTHONPATH="${PYTHONPATH}:$(pwd)" # Linux/macOS
set PYTHONPATH=%PYTHONPATH%;%CD% # Windows
# Ou installer en mode développement
pip install -e .
```
### Problème : API Rate Limit Dépassé
```bash
# Erreur: "API rate limit exceeded"
# Solution 1: Utiliser cache
# Éditer config/data_sources.yaml
cache:
enabled: true
ttl: 3600 # 1 heure
# Solution 2: Alterner sources
# Activer multiple sources dans config
# Solution 3: Réduire fréquence requêtes
# Augmenter timeframe ou réduire nombre de symboles
```
### Problème : Backtesting Trop Lent
```bash
# Solution 1: Réduire période
python src/main.py --mode backtest --period 6m # 6 mois au lieu de 2 ans
# Solution 2: Utiliser données cached
# Activer cache dans config
# Solution 3: Paralléliser
python src/main.py --mode backtest --parallel --workers 4
```
### Problème : Dashboard Ne Se Lance Pas
```bash
# Erreur: "streamlit: command not found"
# Solution: Réinstaller streamlit
pip install --upgrade streamlit
# Vérifier installation
streamlit --version
# Lancer avec chemin complet
python -m streamlit run src/ui/dashboard.py
```
### Problème : Credentials IG Invalides
```bash
# Erreur: "Authentication failed"
# Vérifications:
# 1. API key correcte
# 2. Username/password corrects
# 3. Compte démo activé
# 4. Pas de caractères spéciaux dans password
# Tester connexion
python tests/test_ig_connection.py
```
---
## 📚 Ressources Supplémentaires
### Documentation
- [Architecture Détaillée](ARCHITECTURE.md)
- [Framework IA](AI_FRAMEWORK.md)
- [Risk Management](RISK_FRAMEWORK.md)
- [Guide Stratégies](STRATEGY_GUIDE.md)
- [Backtesting](BACKTESTING_GUIDE.md)
- [Intégration IG](IG_INTEGRATION.md)
### Tutoriels
```bash
# Tutoriel 1: Créer première stratégie
python tutorials/01_create_strategy.py
# Tutoriel 2: Backtesting avancé
python tutorials/02_advanced_backtesting.py
# Tutoriel 3: Optimisation paramètres
python tutorials/03_parameter_optimization.py
```
### Exemples
```bash
# Exemples de stratégies
ls examples/strategies/
# Exemples de backtests
ls examples/backtests/
# Exemples de configurations
ls examples/configs/
```
---
## 🎯 Prochaines Étapes
### Semaine 1 : Familiarisation
- [ ] Installer et configurer environnement
- [ ] Lancer premier backtest
- [ ] Explorer dashboard
- [ ] Lire documentation
### Semaine 2 : Expérimentation
- [ ] Tester différentes stratégies
- [ ] Ajuster paramètres risk
- [ ] Analyser résultats backtests
- [ ] Comprendre métriques
### Semaine 3 : Développement
- [ ] Créer première stratégie custom
- [ ] Implémenter tests
- [ ] Backtester sur multiple périodes
- [ ] Optimiser paramètres
### Semaine 4 : Validation
- [ ] Walk-forward analysis
- [ ] Monte Carlo simulation
- [ ] Paper trading
- [ ] Documenter résultats
---
## 💬 Support
### Obtenir de l'Aide
1. **Documentation** : Lire docs/ en premier
2. **Issues GitHub** : Créer issue si bug
3. **Discussions** : Forum communauté
4. **Discord** : Chat temps réel
### Contribuer
Voir [CONTRIBUTING.md](CONTRIBUTING.md) pour guidelines.
---
**Bon trading ! 🚀**

719
docs/IG_INTEGRATION.md Normal file
View File

@@ -0,0 +1,719 @@
# 🔌 Guide d'Intégration IG Markets - Trading AI Secure
## 📋 Table des Matières
1. [Vue d'ensemble IG Markets](#vue-densemble-ig-markets)
2. [Configuration Compte](#configuration-compte)
3. [API REST](#api-rest)
4. [Streaming Lightstreamer](#streaming-lightstreamer)
5. [Gestion des Ordres](#gestion-des-ordres)
6. [Risk Management IG](#risk-management-ig)
7. [Migration Progressive](#migration-progressive)
8. [Implémentation](#implémentation)
---
## 🎯 Vue d'ensemble IG Markets
### Pourquoi IG Markets ?
-**API complète** : REST + Streaming temps réel
-**Compte démo gratuit** : Test sans risque
-**Large gamme d'instruments** : Forex, Indices, Actions, Crypto
-**CFD et DMA** : Flexibilité trading
-**Guaranteed stops** : Protection slippage
-**Documentation** : API bien documentée
### Architecture IG
```
┌──────────────────────────────────────────────────────────┐
│ IG MARKETS API │
├──────────────────────────────────────────────────────────┤
│ │
│ REST API STREAMING API │
│ ├─ Authentication ├─ Lightstreamer │
│ ├─ Account Info ├─ Prix temps réel │
│ ├─ Market Data ├─ Positions updates │
│ ├─ Orders (CRUD) └─ Account updates │
│ ├─ Positions │
│ └─ Historical Data │
│ │
└──────────────────────────────────────────────────────────┘
```
---
## 🔐 Configuration Compte
### Étape 1 : Créer Compte Démo
1. **S'inscrire** : https://www.ig.com/uk/demo-account
2. **Activer compte démo** : Capital virtuel £10,000
3. **Accéder API** : Dashboard → API → Generate API Key
### Étape 2 : Obtenir Credentials
```yaml
# config/ig_config.yaml (EXEMPLE - NE PAS COMMITER)
ig_credentials:
# Démo
demo:
api_key: "YOUR_DEMO_API_KEY"
username: "YOUR_DEMO_USERNAME"
password: "YOUR_DEMO_PASSWORD"
account_id: "YOUR_DEMO_ACCOUNT_ID"
api_url: "https://demo-api.ig.com/gateway/deal"
# Live (À ACTIVER APRÈS VALIDATION)
live:
api_key: "YOUR_LIVE_API_KEY"
username: "YOUR_LIVE_USERNAME"
password: "YOUR_LIVE_PASSWORD"
account_id: "YOUR_LIVE_ACCOUNT_ID"
api_url: "https://api.ig.com/gateway/deal"
# Lightstreamer
lightstreamer:
demo_url: "https://demo-apd.marketdatasys.com"
live_url: "https://apd.marketdatasys.com"
```
### Étape 3 : Sécuriser Credentials
```python
# src/core/config_manager.py
import os
from cryptography.fernet import Fernet
import yaml
class SecureConfigManager:
"""
Gestion sécurisée des credentials IG
"""
def __init__(self):
# Générer clé encryption (à stocker en variable d'environnement)
self.key = os.getenv('ENCRYPTION_KEY') or Fernet.generate_key()
self.cipher = Fernet(self.key)
def load_ig_credentials(self, environment='demo'):
"""
Charge credentials IG de manière sécurisée
"""
with open('config/ig_config.yaml', 'r') as f:
config = yaml.safe_load(f)
credentials = config['ig_credentials'][environment]
# Décrypter password si encrypté
if credentials['password'].startswith('encrypted:'):
encrypted_password = credentials['password'].replace('encrypted:', '')
credentials['password'] = self.cipher.decrypt(
encrypted_password.encode()
).decode()
return credentials
def encrypt_password(self, password: str) -> str:
"""Encrypte password"""
return 'encrypted:' + self.cipher.encrypt(password.encode()).decode()
```
---
## 🌐 API REST
### Authentification
```python
# src/data/ig_connector.py
import requests
from typing import Dict, Optional
import logging
logger = logging.getLogger(__name__)
class IGRestAPI:
"""
Connecteur IG REST API
"""
def __init__(self, credentials: Dict):
self.api_key = credentials['api_key']
self.username = credentials['username']
self.password = credentials['password']
self.account_id = credentials['account_id']
self.base_url = credentials['api_url']
self.session = requests.Session()
self.access_token = None
self.cst_token = None
self.security_token = None
def authenticate(self) -> bool:
"""
Authentification IG API
Returns:
True si succès, False sinon
"""
url = f"{self.base_url}/session"
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-IG-API-KEY': self.api_key,
'Version': '2'
}
payload = {
'identifier': self.username,
'password': self.password
}
try:
response = self.session.post(url, json=payload, headers=headers)
response.raise_for_status()
# Extraire tokens
self.cst_token = response.headers.get('CST')
self.security_token = response.headers.get('X-SECURITY-TOKEN')
# Sélectionner compte
self._select_account(self.account_id)
logger.info("IG API authentication successful")
return True
except requests.exceptions.RequestException as e:
logger.error(f"IG API authentication failed: {e}")
return False
def _select_account(self, account_id: str):
"""Sélectionne compte de trading"""
url = f"{self.base_url}/session"
headers = self._get_headers()
headers['Version'] = '1'
headers['_method'] = 'PUT'
payload = {
'accountId': account_id,
'defaultAccount': True
}
response = self.session.put(url, json=payload, headers=headers)
response.raise_for_status()
def _get_headers(self) -> Dict:
"""Headers pour requêtes authentifiées"""
return {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-IG-API-KEY': self.api_key,
'CST': self.cst_token,
'X-SECURITY-TOKEN': self.security_token
}
def get_account_info(self) -> Dict:
"""Récupère informations compte"""
url = f"{self.base_url}/accounts"
response = self.session.get(url, headers=self._get_headers())
response.raise_for_status()
return response.json()
def get_market_details(self, epic: str) -> Dict:
"""
Récupère détails d'un marché
Args:
epic: Identifiant marché IG (ex: 'CS.D.EURUSD.MINI.IP')
"""
url = f"{self.base_url}/markets/{epic}"
headers = self._get_headers()
headers['Version'] = '3'
response = self.session.get(url, headers=headers)
response.raise_for_status()
return response.json()
def get_positions(self) -> Dict:
"""Récupère positions ouvertes"""
url = f"{self.base_url}/positions"
headers = self._get_headers()
headers['Version'] = '2'
response = self.session.get(url, headers=headers)
response.raise_for_status()
return response.json()
def place_order(
self,
epic: str,
direction: str,
size: float,
stop_loss: Optional[float] = None,
take_profit: Optional[float] = None,
guaranteed_stop: bool = True
) -> Dict:
"""
Place ordre de trading
Args:
epic: Identifiant marché
direction: 'BUY' ou 'SELL'
size: Taille position
stop_loss: Niveau stop-loss
take_profit: Niveau take-profit
guaranteed_stop: Utiliser guaranteed stop (recommandé)
"""
url = f"{self.base_url}/positions/otc"
headers = self._get_headers()
headers['Version'] = '2'
payload = {
'epic': epic,
'direction': direction,
'size': size,
'orderType': 'MARKET',
'timeInForce': 'FILL_OR_KILL',
'guaranteedStop': guaranteed_stop,
'currencyCode': 'GBP'
}
# Ajouter stop-loss
if stop_loss:
payload['stopLevel'] = stop_loss
payload['stopDistance'] = None # Calculé automatiquement
# Ajouter take-profit
if take_profit:
payload['limitLevel'] = take_profit
payload['limitDistance'] = None
try:
response = self.session.post(url, json=payload, headers=headers)
response.raise_for_status()
result = response.json()
deal_reference = result.get('dealReference')
# Confirmer ordre
return self._confirm_order(deal_reference)
except requests.exceptions.RequestException as e:
logger.error(f"Order placement failed: {e}")
raise
def _confirm_order(self, deal_reference: str) -> Dict:
"""Confirme exécution ordre"""
url = f"{self.base_url}/confirms/{deal_reference}"
headers = self._get_headers()
headers['Version'] = '1'
response = self.session.get(url, headers=headers)
response.raise_for_status()
return response.json()
def close_position(self, deal_id: str) -> Dict:
"""Ferme position"""
# Récupérer détails position
position = self._get_position_details(deal_id)
url = f"{self.base_url}/positions/otc"
headers = self._get_headers()
headers['Version'] = '1'
headers['_method'] = 'DELETE'
payload = {
'dealId': deal_id,
'direction': 'SELL' if position['direction'] == 'BUY' else 'BUY',
'size': position['size'],
'orderType': 'MARKET'
}
response = self.session.delete(url, json=payload, headers=headers)
response.raise_for_status()
return response.json()
def get_historical_prices(
self,
epic: str,
resolution: str = 'MINUTE',
num_points: int = 100
) -> Dict:
"""
Récupère prix historiques
Args:
epic: Identifiant marché
resolution: 'SECOND', 'MINUTE', 'MINUTE_5', 'HOUR', 'DAY'
num_points: Nombre de points (max 1000)
"""
url = f"{self.base_url}/prices/{epic}"
headers = self._get_headers()
headers['Version'] = '3'
params = {
'resolution': resolution,
'max': min(num_points, 1000)
}
response = self.session.get(url, headers=headers, params=params)
response.raise_for_status()
return response.json()
```
---
## 📡 Streaming Lightstreamer
### Configuration
```python
# src/data/ig_streaming.py
from lightstreamer.client import LightstreamerClient, Subscription
import logging
logger = logging.getLogger(__name__)
class IGStreamingAPI:
"""
Connecteur IG Streaming (Lightstreamer)
Permet de recevoir:
- Prix en temps réel
- Updates positions
- Updates compte
"""
def __init__(self, credentials: Dict, cst_token: str, security_token: str):
self.lightstreamer_url = credentials.get('lightstreamer_url')
self.cst_token = cst_token
self.security_token = security_token
self.account_id = credentials['account_id']
self.client = None
self.subscriptions = {}
def connect(self):
"""Connexion Lightstreamer"""
self.client = LightstreamerClient(self.lightstreamer_url, "DEFAULT")
# Configuration connexion
self.client.connectionDetails.setUser(self.account_id)
self.client.connectionDetails.setPassword(f"CST-{self.cst_token}|XST-{self.security_token}")
# Listeners
self.client.addListener(ConnectionListener())
# Connecter
self.client.connect()
logger.info("Lightstreamer connection established")
def subscribe_market(self, epic: str, callback):
"""
Subscribe à prix temps réel d'un marché
Args:
epic: Identifiant marché
callback: Fonction appelée à chaque update
"""
# Items à subscribe
items = [f"MARKET:{epic}"]
# Fields à recevoir
fields = [
"BID", "OFFER", "HIGH", "LOW",
"MID_OPEN", "CHANGE", "CHANGE_PCT",
"UPDATE_TIME", "MARKET_STATE"
]
# Créer subscription
subscription = Subscription(
mode="MERGE",
items=items,
fields=fields
)
# Ajouter listener
subscription.addListener(MarketDataListener(callback))
# Subscribe
self.client.subscribe(subscription)
self.subscriptions[epic] = subscription
logger.info(f"Subscribed to market: {epic}")
def subscribe_account(self, callback):
"""Subscribe à updates compte"""
items = [f"ACCOUNT:{self.account_id}"]
fields = [
"AVAILABLE_CASH", "PNL", "DEPOSIT",
"USED_MARGIN", "AVAILABLE_TO_DEAL", "EQUITY"
]
subscription = Subscription(
mode="MERGE",
items=items,
fields=fields
)
subscription.addListener(AccountListener(callback))
self.client.subscribe(subscription)
self.subscriptions['account'] = subscription
def unsubscribe(self, key: str):
"""Unsubscribe d'un stream"""
if key in self.subscriptions:
self.client.unsubscribe(self.subscriptions[key])
del self.subscriptions[key]
def disconnect(self):
"""Déconnexion Lightstreamer"""
if self.client:
self.client.disconnect()
logger.info("Lightstreamer disconnected")
class MarketDataListener:
"""Listener pour données marché"""
def __init__(self, callback):
self.callback = callback
def onItemUpdate(self, update):
"""Appelé à chaque update prix"""
data = {
'bid': update.getValue('BID'),
'offer': update.getValue('OFFER'),
'high': update.getValue('HIGH'),
'low': update.getValue('LOW'),
'change': update.getValue('CHANGE'),
'change_pct': update.getValue('CHANGE_PCT'),
'update_time': update.getValue('UPDATE_TIME'),
'market_state': update.getValue('MARKET_STATE')
}
self.callback(data)
class AccountListener:
"""Listener pour updates compte"""
def __init__(self, callback):
self.callback = callback
def onItemUpdate(self, update):
"""Appelé à chaque update compte"""
data = {
'available_cash': update.getValue('AVAILABLE_CASH'),
'pnl': update.getValue('PNL'),
'deposit': update.getValue('DEPOSIT'),
'used_margin': update.getValue('USED_MARGIN'),
'equity': update.getValue('EQUITY')
}
self.callback(data)
class ConnectionListener:
"""Listener pour état connexion"""
def onStatusChange(self, status):
logger.info(f"Lightstreamer status: {status}")
```
---
## 📊 Gestion des Ordres
### Wrapper Unifié
```python
# src/core/order_manager.py
class IGOrderManager:
"""
Gestionnaire d'ordres IG avec validation
"""
def __init__(self, ig_api: IGRestAPI, risk_manager: RiskManager):
self.ig_api = ig_api
self.risk_manager = risk_manager
def execute_signal(self, signal: Signal) -> Optional[str]:
"""
Exécute signal de trading
Returns:
Deal ID si succès, None sinon
"""
# 1. Valider avec risk manager
is_valid, error = self.risk_manager.validate_trade(
symbol=signal.symbol,
quantity=signal.quantity,
price=signal.entry_price,
stop_loss=signal.stop_loss,
take_profit=signal.take_profit,
strategy=signal.strategy
)
if not is_valid:
logger.warning(f"Trade rejected: {error}")
return None
# 2. Convertir symbol en EPIC IG
epic = self._symbol_to_epic(signal.symbol)
# 3. Placer ordre
try:
result = self.ig_api.place_order(
epic=epic,
direction='BUY' if signal.direction == 'LONG' else 'SELL',
size=signal.quantity,
stop_loss=signal.stop_loss,
take_profit=signal.take_profit,
guaranteed_stop=True # Toujours utiliser guaranteed stop
)
deal_id = result.get('dealId')
# 4. Enregistrer position dans risk manager
if deal_id:
self.risk_manager.add_position(Position(
symbol=signal.symbol,
quantity=signal.quantity,
entry_price=signal.entry_price,
current_price=signal.entry_price,
stop_loss=signal.stop_loss,
take_profit=signal.take_profit,
strategy=signal.strategy,
entry_time=datetime.now(),
unrealized_pnl=0.0,
risk_amount=abs(signal.entry_price - signal.stop_loss) * signal.quantity
))
return deal_id
except Exception as e:
logger.error(f"Order execution failed: {e}")
return None
def _symbol_to_epic(self, symbol: str) -> str:
"""
Convertit symbol standard en EPIC IG
Exemples:
- EURUSD → CS.D.EURUSD.MINI.IP
- GBPUSD → CS.D.GBPUSD.MINI.IP
- US500 → IX.D.SPTRD.IFE.IP
"""
# Mapping symbol → EPIC
EPIC_MAP = {
'EURUSD': 'CS.D.EURUSD.MINI.IP',
'GBPUSD': 'CS.D.GBPUSD.MINI.IP',
'USDJPY': 'CS.D.USDJPY.MINI.IP',
'US500': 'IX.D.SPTRD.IFE.IP',
'US30': 'IX.D.DOW.IFE.IP',
'GER40': 'IX.D.DAX.IFE.IP',
}
return EPIC_MAP.get(symbol, symbol)
```
---
## 🛡️ Risk Management IG
### Spécificités IG
```python
class IGRiskCalculator:
"""
Calculs risk spécifiques IG
"""
@staticmethod
def calculate_margin_required(
epic: str,
size: float,
market_details: Dict
) -> float:
"""
Calcule margin requis pour position
IG utilise margin factor variable selon instrument
"""
margin_factor = market_details['dealingRules']['minDealSize']['value']
current_price = market_details['snapshot']['offer']
margin_required = size * current_price * margin_factor
return margin_required
@staticmethod
def calculate_guaranteed_stop_premium(
stop_distance: float,
market_details: Dict
) -> float:
"""
Calcule coût du guaranteed stop
IG facture premium pour guaranteed stops
"""
premium_factor = market_details['dealingRules']['marketOrderPreference']
# Premium généralement 0.3-0.5% du stop distance
premium = stop_distance * 0.003 # 0.3%
return premium
```
---
## 🚀 Migration Progressive
### Plan de Migration
```
┌──────────────────────────────────────────────────────────┐
│ MIGRATION VERS IG MARKETS │
├──────────────────────────────────────────────────────────┤
│ │
│ PHASE 1: Développement (Semaines 1-8) │
│ └─ Sources gratuites (Yahoo, Alpha Vantage) │
│ │
│ PHASE 2: Tests IG Démo (Semaines 9-10) │
│ ├─ Connexion API IG démo │
│ ├─ Paper trading 30 jours │
│ └─ Validation performance │
│ │
│ PHASE 3: Live Progressif (Semaine 11+) │
│ ├─ Capital initial minimal (£500) │
│ ├─ 1 stratégie uniquement │
│ ├─ Monitoring 24/7 │
│ └─ Scale progressif si succès │
│ │
└──────────────────────────────────────────────────────────┘
```
---
**Documentation IG Markets complète !**

429
docs/PROJECT_STATUS.md Normal file
View File

@@ -0,0 +1,429 @@
# 📈 État d'Avancement du Projet - Trading AI Secure
**Dernière mise à jour** : 2024-01-15
**Version** : 0.1.0-alpha
**Statut Global** : 🟡 En Développement Actif
---
## 📊 Vue d'Ensemble Globale
| Phase | Statut | Progression | Début | Fin Prévue | Fin Réelle |
|-------|--------|-------------|-------|------------|------------|
| Phase 1: Architecture | 🟡 En cours | 15% | 2024-01-15 | 2024-01-29 | - |
| Phase 2: IA Adaptative | ⚪ Planifié | 0% | 2024-01-30 | 2024-02-12 | - |
| Phase 3: Stratégies | ⚪ Planifié | 0% | 2024-02-13 | 2024-02-26 | - |
| Phase 4: Interface | ⚪ Planifié | 0% | 2024-02-27 | 2024-03-11 | - |
| Phase 5: Production | ⚪ Planifié | 0% | 2024-03-12 | 2024-03-25 | - |
**Progression Totale** : 3% ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
---
## 🎯 Phase 1 : Architecture Multi-Stratégie (Semaines 1-2)
**Statut** : 🟡 En cours
**Progression** : 15%
**Responsable** : Équipe Core
**Priorité** : 🔴 CRITIQUE
### 1.1 Stack Technologique Sécurisé
#### Backend Core
| Composant | Statut | Progression | Notes |
|-----------|--------|-------------|-------|
| Python 3.11+ setup | ✅ Terminé | 100% | Environnement configuré |
| FastAPI structure | 🟡 En cours | 30% | Routes de base créées |
| Pydantic models | 🟡 En cours | 20% | Modèles risk en cours |
| asyncio/threading | ⚪ À faire | 0% | Planifié semaine 2 |
| Singleton RiskManager | ⚪ À faire | 0% | Dépend de FastAPI |
**Bloqueurs** : Aucun
**Risques** : Complexité threading pour multi-stratégie
#### Risk Management Intégré
| Bibliothèque | Installation | Intégration | Tests | Notes |
|--------------|--------------|-------------|-------|-------|
| quantlib-python | ⚪ À faire | ⚪ À faire | ⚪ À faire | Calculs financiers |
| riskfolio-lib | ⚪ À faire | ⚪ À faire | ⚪ À faire | Optimisation portfolio |
| pypfopt | ⚪ À faire | ⚪ À faire | ⚪ À faire | Modern Portfolio Theory |
**Bloqueurs** : Aucun
**Risques** : Compatibilité versions entre bibliothèques
### 1.2 Sources de Données Gratuites
#### Connecteurs Implémentés
| Source | Statut | Priorité | Limite API | Notes |
|--------|--------|----------|------------|-------|
| Yahoo Finance (yfinance) | ⚪ À faire | 🔴 Haute | Illimité | EOD + intraday limité |
| Alpha Vantage | ⚪ À faire | 🟡 Moyenne | 500/jour | Données temps réel |
| Twelve Data | ⚪ À faire | 🟡 Moyenne | 800/jour | Alternative robuste |
| Polygon.io | ⚪ À faire | 🟢 Basse | 5/min | Données US premium |
| FRED API | ⚪ À faire | 🟢 Basse | Illimité | Données macro |
#### Crypto (Tests)
| Source | Statut | Priorité | Limite API | Notes |
|--------|--------|----------|------------|-------|
| Binance Public API | ⚪ À faire | 🟡 Moyenne | Illimité | Pour tests initiaux |
| CoinGecko API | ⚪ À faire | 🟢 Basse | 50/min | Backup crypto |
**Bloqueurs** : Besoin clés API (gratuites)
**Risques** : Rate limiting, fiabilité données gratuites
### 1.3 Intégration IG Markets Préparée
#### Composants IG
| Composant | Statut | Progression | Notes |
|-----------|--------|-------------|-------|
| ig-trading-api | ⚪ À faire | 0% | Library Python |
| lightstreamer-client | ⚪ À faire | 0% | Streaming temps réel |
| requests-oauthlib | ⚪ À faire | 0% | OAuth authentication |
| Architecture REST | ⚪ À faire | 0% | Ordres, positions |
| Streaming setup | ⚪ À faire | 0% | Prix temps réel |
**Bloqueurs** : Compte IG démo requis (gratuit)
**Risques** : Complexité Lightstreamer, documentation limitée
---
## 🤖 Phase 2 : IA Adaptative avec Risk Management (Semaines 3-4)
**Statut** : ⚪ Planifié
**Progression** : 0%
**Responsable** : Équipe ML
**Priorité** : 🔴 CRITIQUE
### 2.1 IA Risk-Aware
#### Core ML avec Risk Integration
| Composant | Statut | Priorité | Notes |
|-----------|--------|----------|-------|
| scikit-learn pipeline | ⚪ Planifié | 🔴 Haute | Pipeline custom risk-aware |
| Kelly Criterion auto | ⚪ Planifié | 🔴 Haute | Position sizing optimal |
| Value at Risk (VaR) | ⚪ Planifié | 🔴 Haute | Calcul risque portfolio |
| Max Drawdown limiter | ⚪ Planifié | 🔴 Haute | Circuit breaker |
#### Features Risk-Adjusted
| Feature | Statut | Priorité | Notes |
|---------|--------|----------|-------|
| Volatility forecasting (GARCH) | ⚪ Planifié | 🟡 Moyenne | Prédiction volatilité |
| Correlation matrix dynamique | ⚪ Planifié | 🔴 Haute | Diversification |
| Regime detection | ⚪ Planifié | 🔴 Haute | Bull/Bear/Sideways |
| Position sizing adaptatif | ⚪ Planifié | 🔴 Haute | Ajustement dynamique |
#### IA Auto-Optimisante (Nouvelle Exigence)
| Composant | Statut | Priorité | Notes |
|-----------|--------|----------|-------|
| Optimisation bayésienne (Optuna) | ⚪ Planifié | 🔴 Haute | Tuning hyperparamètres |
| A/B testing automatique | ⚪ Planifié | 🟡 Moyenne | Test variantes stratégies |
| Reinforcement Learning | ⚪ Planifié | 🟡 Moyenne | Apprentissage continu |
| Parameter drift detection | ⚪ Planifié | 🔴 Haute | Détection obsolescence |
| Auto-retraining pipeline | ⚪ Planifié | 🔴 Haute | Réentraînement automatique |
**Bloqueurs** : Dépend Phase 1 (données)
**Risques** : Overfitting, complexité optimisation
### 2.2 Module de Sécurité Trading
#### Safety Layer
| Composant | Statut | Priorité | Notes |
|-----------|--------|----------|-------|
| RiskManager class | ⚪ Planifié | 🔴 Haute | Singleton pattern |
| Pre-trade validation | ⚪ Planifié | 🔴 Haute | Checks avant ordre |
| Circuit breakers | ⚪ Planifié | 🔴 Haute | Arrêt automatique |
| Margin verification | ⚪ Planifié | 🔴 Haute | Temps réel |
**Bloqueurs** : Aucun
**Risques** : Faux positifs arrêts intempestifs
---
## 📊 Phase 3 : Système Multi-Stratégie (Semaines 5-6)
**Statut** : ⚪ Planifié
**Progression** : 0%
**Responsable** : Équipe Stratégies
**Priorité** : 🔴 CRITIQUE
### 3.1 Framework Stratégies Modulaire
#### Stratégies à Implémenter
| Stratégie | Statut | Priorité | Complexité | Notes |
|-----------|--------|----------|------------|-------|
| ScalpingStrategy | ⚪ Planifié | 🟡 Moyenne | Haute | 1-5 min, risque 0.5-1% |
| IntradayStrategy | ⚪ Planifié | 🔴 Haute | Moyenne | 15-60 min, risque 1-2% |
| SwingStrategy | ⚪ Planifié | 🟡 Moyenne | Basse | 4H-1D, risque 2-3% |
| BaseStrategy (abstract) | ⚪ Planifié | 🔴 Haute | Moyenne | Classe mère |
#### Paramètres Adaptatifs par Stratégie
| Paramètre | Auto-Ajustement | Fréquence | Notes |
|-----------|-----------------|-----------|-------|
| Timeframe | ✅ Oui | Quotidien | Selon volatilité |
| Risk per trade | ✅ Oui | Quotidien | Selon performance |
| Stop-loss distance | ✅ Oui | Par trade | Selon ATR |
| Take-profit ratio | ✅ Oui | Quotidien | Selon win rate |
| Max positions | ✅ Oui | Hebdomadaire | Selon corrélation |
**Bloqueurs** : Dépend Phase 2 (ML models)
**Risques** : Suroptimisation, instabilité paramètres
### 3.2 Backtesting Avancé Anti-Overfitting
#### Framework de Validation
| Méthode | Statut | Priorité | Notes |
|---------|--------|----------|-------|
| Walk-forward analysis | ⚪ Planifié | 🔴 Haute | Validation temporelle |
| Out-of-sample testing | ⚪ Planifié | 🔴 Haute | 30% données réservées |
| Monte Carlo simulation | ⚪ Planifié | 🟡 Moyenne | 10,000+ scénarios |
| Bootstrap validation | ⚪ Planifié | 🟢 Basse | Validation robustesse |
| Paper trading engine | ⚪ Planifié | 🔴 Haute | 30 jours minimum |
#### Métriques Critiques
| Métrique | Seuil Minimum | Statut Implémentation | Notes |
|----------|---------------|----------------------|-------|
| Sharpe Ratio | > 1.5 | ⚪ À faire | Risk-adjusted return |
| Max Drawdown | < 10% | ⚪ À faire | Perte maximale |
| Win Rate | > 55% | ⚪ À faire | % trades gagnants |
| Profit Factor | > 1.3 | ⚪ À faire | Gains/Pertes |
| Calmar Ratio | > 0.5 | ⚪ À faire | Return/Drawdown |
**Bloqueurs** : Données historiques suffisantes
**Risques** : Biais survivorship, look-ahead bias
---
## 🖥️ Phase 4 : Interface Sécurisée (Semaines 7-8)
**Statut** : ⚪ Planifié
**Progression** : 0%
**Responsable** : Équipe UI/UX
**Priorité** : 🟡 MOYENNE
### 4.1 Dashboard Risk-Centric
#### Composants Interface
| Composant | Statut | Priorité | Notes |
|-----------|--------|----------|-------|
| Streamlit setup | ⚪ Planifié | 🔴 Haute | Framework UI |
| Real-time P&L monitoring | ⚪ Planifié | 🔴 Haute | WebSocket updates |
| Risk metrics dashboard | ⚪ Planifié | 🔴 Haute | VaR, drawdown, etc. |
| Portfolio heat map | ⚪ Planifié | 🟡 Moyenne | Visualisation corrélations |
| Drawdown alerts | ⚪ Planifié | 🔴 Haute | Alertes visuelles |
| Performance attribution | ⚪ Planifié | 🟢 Basse | Par stratégie |
#### Safety Controls UI
| Contrôle | Statut | Priorité | Notes |
|----------|--------|----------|-------|
| Emergency stop button | ⚪ Planifié | 🔴 Haute | Arrêt immédiat |
| Position size calculator | ⚪ Planifié | 🟡 Moyenne | Aide décision |
| Risk budget monitor | ⚪ Planifié | 🔴 Haute | Temps réel |
| Correlation matrix live | ⚪ Planifié | 🟡 Moyenne | Heatmap dynamique |
**Bloqueurs** : Dépend Phase 3 (stratégies)
**Risques** : Performance temps réel, latence
### 4.2 Système d'Alertes Intelligent
#### Canaux de Notification
| Canal | Statut | Priorité | Use Case | Notes |
|-------|--------|----------|----------|-------|
| Telegram bot | ⚪ Planifié | 🔴 Haute | Alertes urgentes | Temps réel |
| Email | ⚪ Planifié | 🟡 Moyenne | Rapports quotidiens | Asynchrone |
| SMS | ⚪ Planifié | 🟢 Basse | Urgences critiques | Coût élevé |
| In-app notifications | ⚪ Planifié | 🟡 Moyenne | Dashboard | Temps réel |
#### Types d'Alertes
| Type | Statut | Priorité | Notes |
|------|--------|----------|-------|
| Risk threshold breaches | ⚪ Planifié | 🔴 Haute | Dépassement limites |
| Unusual market conditions | ⚪ Planifié | 🟡 Moyenne | Volatilité extrême |
| Strategy underperformance | ⚪ Planifié | 🟡 Moyenne | Sharpe < seuil |
| Technical conflicts | ⚪ Planifié | 🟢 Basse | Indicateurs contradictoires |
| News sentiment changes | ⚪ Planifié | 🟢 Basse | Analyse sentiment |
**Bloqueurs** : API Telegram, SMTP config
**Risques** : Spam alertes, faux positifs
---
## 🚀 Phase 5 : Intégration IG et Production (Semaines 9-10)
**Statut** : ⚪ Planifié
**Progression** : 0%
**Responsable** : Équipe DevOps
**Priorité** : 🔴 CRITIQUE
### 5.1 Migration vers IG Markets
#### Étapes d'Intégration
| Étape | Statut | Priorité | Notes |
|-------|--------|----------|-------|
| Compte démo IG | ⚪ Planifié | 🔴 Haute | Gratuit, requis |
| API key generation | ⚪ Planifié | 🔴 Haute | Credentials sécurisés |
| Streaming setup (Lightstreamer) | ⚪ Planifié | 🔴 Haute | Prix temps réel |
| Paper trading validation | ⚪ Planifié | 🔴 Haute | 30 jours minimum |
| Live trading activation | ⚪ Planifié | 🔴 Haute | Après validation |
#### Features IG Spécifiques
| Feature | Statut | Priorité | Notes |
|---------|--------|----------|-------|
| CFD margin calculator | ⚪ Planifié | 🔴 Haute | Calcul margin requis |
| DMA vs CFD selection | ⚪ Planifié | 🟡 Moyenne | Choix instrument |
| Guaranteed stops | ⚪ Planifié | 🔴 Haute | Protection slippage |
| Weekend risk assessment | ⚪ Planifié | 🟡 Moyenne | Gap risk |
**Bloqueurs** : Validation paper trading 30 jours
**Risques** : API changes, downtime IG
### 5.2 Production Safety
#### Deployment Checks
| Check | Statut | Priorité | Notes |
|-------|--------|----------|-------|
| Position limits verification | ⚪ Planifié | 🔴 Haute | Hardcoded limits |
| API rate limiting respect | ⚪ Planifié | 🔴 Haute | Éviter bans |
| Redundant data sources | ⚪ Planifié | 🟡 Moyenne | Failover automatique |
| Automatic failover | ⚪ Planifié | 🔴 Haute | Haute disponibilité |
| Daily reconciliation | ⚪ Planifié | 🔴 Haute | Vérification positions |
#### Monitoring Stack
| Outil | Statut | Priorité | Notes |
|-------|--------|----------|-------|
| Prometheus | ⚪ Planifié | 🟡 Moyenne | Métriques système |
| Grafana | ⚪ Planifié | 🟡 Moyenne | Dashboards |
| Custom trading metrics | ⚪ Planifié | 🔴 Haute | P&L, Sharpe, etc. |
| Health check endpoints | ⚪ Planifié | 🔴 Haute | /health, /ready |
| Error rate monitoring | ⚪ Planifié | 🔴 Haute | Alertes erreurs |
| Latency tracking | ⚪ Planifié | 🟡 Moyenne | Performance API |
**Bloqueurs** : Infrastructure cloud (à définir)
**Risques** : Coûts infrastructure, complexité DevOps
---
## 🎯 Objectifs Hebdomadaires
### Semaine 1 (15-21 Jan 2024) - EN COURS
- [x] Création structure projet
- [x] Documentation complète
- [ ] Setup environnement Python 3.11+
- [ ] Installation dépendances de base
- [ ] Premiers modèles Pydantic
- [ ] Tests unitaires structure
### Semaine 2 (22-28 Jan 2024)
- [ ] RiskManager singleton
- [ ] Connecteur Yahoo Finance
- [ ] Connecteur Alpha Vantage
- [ ] Data validation layer
- [ ] Tests intégration données
### Semaine 3 (29 Jan - 4 Fév 2024)
- [ ] Modèles ML de base (scikit-learn)
- [ ] Regime detection (HMM)
- [ ] Kelly Criterion implementation
- [ ] VaR calculator
### Semaine 4 (5-11 Fév 2024)
- [ ] Optimisation bayésienne (Optuna)
- [ ] Auto-retraining pipeline
- [ ] Parameter drift detection
- [ ] Tests ML complets
---
## 📊 Métriques de Développement
### Couverture de Code
| Module | Couverture | Objectif | Statut |
|--------|------------|----------|--------|
| core/ | 0% | 90% | ⚪ À démarrer |
| strategies/ | 0% | 85% | ⚪ À démarrer |
| ml/ | 0% | 80% | ⚪ À démarrer |
| data/ | 0% | 90% | ⚪ À démarrer |
| backtesting/ | 0% | 95% | ⚪ À démarrer |
| ui/ | 0% | 70% | ⚪ À démarrer |
**Objectif Global** : 85% de couverture
### Qualité Code
| Métrique | Valeur Actuelle | Objectif | Statut |
|----------|-----------------|----------|--------|
| Pylint Score | N/A | > 9.0/10 | ⚪ À mesurer |
| Complexité Cyclomatique | N/A | < 10 | ⚪ À mesurer |
| Duplications | N/A | < 3% | ⚪ À mesurer |
| Documentation | 100% | 100% | ✅ OK |
---
## 🚧 Bloqueurs et Risques Globaux
### Bloqueurs Actuels
| Bloqueur | Impact | Priorité | Solution Proposée | ETA |
|----------|--------|----------|-------------------|-----|
| Aucun actuellement | - | - | - | - |
### Risques Identifiés
| Risque | Probabilité | Impact | Mitigation | Responsable |
|--------|-------------|--------|------------|-------------|
| Overfitting IA | 🟡 Moyenne | 🔴 Haute | Walk-forward, out-of-sample | Équipe ML |
| Rate limiting APIs gratuites | 🟡 Moyenne | 🟡 Moyenne | Multiple sources, cache | Équipe Data |
| Complexité Lightstreamer | 🟡 Moyenne | 🟡 Moyenne | POC early, documentation | Équipe IG |
| Instabilité paramètres auto-optimisés | 🔴 Haute | 🔴 Haute | Contraintes, validation Monte Carlo | Équipe ML |
| Faux positifs circuit breakers | 🟡 Moyenne | 🟡 Moyenne | Tuning seuils, historique | Équipe Risk |
---
## 📅 Prochaines Étapes Immédiates
### Cette Semaine (15-21 Jan)
1. ✅ Finaliser documentation
2. ⏳ Setup environnement développement
3. ⏳ Créer structure fichiers src/
4. ⏳ Premiers tests unitaires
5. ⏳ Configuration CI/CD basique
### Semaine Prochaine (22-28 Jan)
1. Implémenter RiskManager core
2. Connecteur Yahoo Finance fonctionnel
3. Validation données temps réel
4. Tests intégration
5. Première démo interne
---
## 📝 Notes de Version
### v0.1.0-alpha (2024-01-15)
- ✅ Structure projet créée
- ✅ Documentation complète
- ✅ Roadmap détaillée
- ⏳ Développement Phase 1 démarré
---
## 📞 Contacts Équipe
| Rôle | Responsable | Contact |
|------|-------------|---------|
| Chef de Projet | TBD | - |
| Lead Backend | TBD | - |
| Lead ML/IA | TBD | - |
| Lead DevOps | TBD | - |
| QA Lead | TBD | - |
---
**Légende Statuts** :
- ✅ Terminé
- 🟡 En cours
- ⏳ En attente
- ⚪ Planifié
- 🔴 Bloqué
- ❌ Annulé
**Légende Priorités** :
- 🔴 Haute (Critique)
- 🟡 Moyenne (Important)
- 🟢 Basse (Nice to have)

842
docs/RISK_FRAMEWORK.md Normal file
View File

@@ -0,0 +1,842 @@
# ⚠️ Framework de Risk Management - Trading AI Secure
## 📋 Table des Matières
1. [Philosophie du Risk Management](#philosophie-du-risk-management)
2. [Architecture Multi-Niveaux](#architecture-multi-niveaux)
3. [Limites et Contraintes](#limites-et-contraintes)
4. [Risk Manager Core](#risk-manager-core)
5. [Validation Pré-Trade](#validation-pré-trade)
6. [Circuit Breakers](#circuit-breakers)
7. [Métriques de Risque](#métriques-de-risque)
8. [Implémentation Technique](#implémentation-technique)
---
## 🎯 Philosophie du Risk Management
### Principe Fondamental : "Survivre d'abord, Profiter ensuite"
Le risk management est **intégré à tous les niveaux** du système, pas une couche ajoutée après coup.
```
┌─────────────────────────────────────────────────────────┐
│ HIÉRARCHIE DES PRIORITÉS │
├─────────────────────────────────────────────────────────┤
│ │
│ 1. 🛡️ PROTECTION DU CAPITAL (Priorité absolue) │
│ 2. 📉 LIMITATION DES PERTES (Drawdown < 10%) │
│ 3. 🎯 CONSISTANCE (Sharpe > volatilité) │
│ 4. 💰 PROFITABILITÉ (Objectif final) │
│ │
└─────────────────────────────────────────────────────────┘
```
### Règles d'Or
1. **Jamais de trade sans stop-loss**
2. **Jamais plus de 2% du capital en risque total**
3. **Jamais plus de 10% de drawdown**
4. **Toujours vérifier la corrélation**
5. **Toujours valider la liquidité**
---
## 🏗️ Architecture Multi-Niveaux
### 5 Niveaux de Protection
```
┌──────────────────────────────────────────────────────────┐
│ NIVEAU 5: GLOBAL PORTFOLIO RISK │
│ ├─ Max total risk: 2% du capital │
│ ├─ Max drawdown: 10% │
│ └─ Daily loss limit: 3% │
├──────────────────────────────────────────────────────────┤
│ NIVEAU 4: STRATEGY ALLOCATION │
│ ├─ Max per strategy: 33% du capital │
│ ├─ Correlation limit: 0.7 entre stratégies │
│ └─ Min diversification: 3 stratégies actives │
├──────────────────────────────────────────────────────────┤
│ NIVEAU 3: POSITION SIZING │
│ ├─ Kelly Criterion adaptatif │
│ ├─ Max position: 5% du capital │
│ └─ Volatility-adjusted sizing │
├──────────────────────────────────────────────────────────┤
│ NIVEAU 2: TRADE VALIDATION │
│ ├─ Stop-loss obligatoire │
│ ├─ Risk/Reward > 1.5 │
│ ├─ Liquidity check │
│ └─ Margin verification │
├──────────────────────────────────────────────────────────┤
│ NIVEAU 1: CIRCUIT BREAKERS │
│ ├─ Emergency stop │
│ ├─ Volatility spike detection │
│ ├─ Flash crash protection │
│ └─ API failure handling │
└──────────────────────────────────────────────────────────┘
```
---
## 📊 Limites et Contraintes
### Limites Globales (Portfolio)
```yaml
global_limits:
# Capital
max_portfolio_risk: 0.02 # 2% du capital total en risque
max_position_size: 0.05 # 5% max par position
max_total_exposure: 1.0 # 100% du capital (pas de levier)
# Drawdown
max_drawdown: 0.10 # 10% drawdown maximum
max_daily_loss: 0.03 # 3% perte journalière max
max_weekly_loss: 0.07 # 7% perte hebdomadaire max
# Corrélation
max_correlation: 0.7 # Corrélation max entre positions
min_diversification: 3 # Minimum 3 positions non-corrélées
# Liquidité
min_daily_volume: 1000000 # 1M$ volume quotidien minimum
max_position_vs_volume: 0.01 # Max 1% du volume quotidien
# Concentration
max_sector_exposure: 0.30 # 30% max par secteur
max_asset_class_exposure: 0.50 # 50% max par classe d'actif
```
### Limites par Stratégie
```yaml
strategy_limits:
scalping:
max_trades_per_day: 50
risk_per_trade: 0.005 # 0.5% par trade
max_holding_time: 1800 # 30 minutes
max_slippage: 0.001 # 0.1% slippage max
min_profit_target: 0.003 # 0.3% profit minimum
intraday:
max_trades_per_day: 10
risk_per_trade: 0.015 # 1.5% par trade
max_holding_time: 86400 # 1 jour
max_slippage: 0.002 # 0.2% slippage max
min_profit_target: 0.01 # 1% profit minimum
swing:
max_trades_per_week: 5
risk_per_trade: 0.025 # 2.5% par trade
max_holding_time: 432000 # 5 jours
max_slippage: 0.003 # 0.3% slippage max
min_profit_target: 0.03 # 3% profit minimum
```
### Limites Dynamiques (Ajustées selon conditions)
```python
class DynamicLimits:
"""
Limites ajustées selon conditions de marché
"""
def adjust_limits(self, market_conditions: Dict) -> Dict:
"""
Ajuste limites selon volatilité, drawdown, etc.
"""
base_limits = self.get_base_limits()
# Réduire limites si haute volatilité
if market_conditions['volatility'] > 0.03: # > 3% vol quotidienne
base_limits['max_position_size'] *= 0.5
base_limits['max_portfolio_risk'] *= 0.7
# Réduire limites si drawdown élevé
if market_conditions['current_drawdown'] > 0.05: # > 5% DD
reduction_factor = 1 - (market_conditions['current_drawdown'] / 0.10)
base_limits['max_position_size'] *= reduction_factor
# Réduire limites si losing streak
if market_conditions['consecutive_losses'] > 3:
base_limits['max_trades_per_day'] //= 2
base_limits['risk_per_trade'] *= 0.5
return base_limits
```
---
## 🛡️ Risk Manager Core
### Singleton Pattern
```python
# src/core/risk_manager.py
from typing import Dict, List, Optional
from dataclasses import dataclass
from datetime import datetime, timedelta
import threading
import numpy as np
@dataclass
class Position:
"""Représente une position ouverte"""
symbol: str
quantity: float
entry_price: float
current_price: float
stop_loss: float
take_profit: float
strategy: str
entry_time: datetime
unrealized_pnl: float
risk_amount: float
@dataclass
class RiskMetrics:
"""Métriques de risque en temps réel"""
total_risk: float
current_drawdown: float
daily_pnl: float
weekly_pnl: float
portfolio_var: float
portfolio_cvar: float
correlation_matrix: np.ndarray
largest_position: float
num_positions: int
class RiskManager:
"""
Risk Manager Central (Singleton)
Responsabilités:
- Validation pré-trade
- Monitoring positions
- Circuit breakers
- Calcul métriques risque
"""
_instance = None
_lock = threading.Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not hasattr(self, 'initialized'):
self.initialized = True
# Configuration
self.config = self._load_config()
# État
self.positions: Dict[str, Position] = {}
self.daily_trades: List[Dict] = []
self.portfolio_value: float = 100000.0 # Initial capital
self.peak_value: float = 100000.0
# Historique
self.pnl_history: List[float] = []
self.drawdown_history: List[float] = []
# Circuit breakers
self.trading_halted: bool = False
self.halt_reason: Optional[str] = None
def validate_trade(
self,
symbol: str,
quantity: float,
price: float,
stop_loss: float,
take_profit: float,
strategy: str
) -> tuple[bool, Optional[str]]:
"""
Valide un trade avant exécution
Returns:
(is_valid, error_message)
"""
# 1. Vérifier si trading halted
if self.trading_halted:
return False, f"Trading halted: {self.halt_reason}"
# 2. Vérifier stop-loss obligatoire
if stop_loss is None or stop_loss == 0:
return False, "Stop-loss is mandatory"
# 3. Calculer risque du trade
risk_amount = abs(price - stop_loss) * quantity
risk_pct = risk_amount / self.portfolio_value
# 4. Vérifier limites par trade
max_risk_per_trade = self.config['strategy_limits'][strategy]['risk_per_trade']
if risk_pct > max_risk_per_trade:
return False, f"Risk per trade ({risk_pct:.2%}) exceeds limit ({max_risk_per_trade:.2%})"
# 5. Vérifier risque total portfolio
total_risk = self._calculate_total_risk() + risk_amount
max_portfolio_risk = self.config['global_limits']['max_portfolio_risk'] * self.portfolio_value
if total_risk > max_portfolio_risk:
return False, f"Total portfolio risk ({total_risk:.2f}) exceeds limit ({max_portfolio_risk:.2f})"
# 6. Vérifier taille position
position_value = price * quantity
position_pct = position_value / self.portfolio_value
max_position_size = self.config['global_limits']['max_position_size']
if position_pct > max_position_size:
return False, f"Position size ({position_pct:.2%}) exceeds limit ({max_position_size:.2%})"
# 7. Vérifier corrélation
if not self._check_correlation(symbol, strategy):
return False, "Correlation with existing positions too high"
# 8. Vérifier nombre de trades quotidiens
strategy_trades_today = len([t for t in self.daily_trades if t['strategy'] == strategy])
max_trades = self.config['strategy_limits'][strategy]['max_trades_per_day']
if strategy_trades_today >= max_trades:
return False, f"Max daily trades for {strategy} reached ({max_trades})"
# 9. Vérifier Risk/Reward ratio
risk = abs(price - stop_loss)
reward = abs(take_profit - price)
rr_ratio = reward / risk if risk > 0 else 0
if rr_ratio < 1.5:
return False, f"Risk/Reward ratio ({rr_ratio:.2f}) below minimum (1.5)"
# 10. Vérifier drawdown actuel
current_dd = self._calculate_current_drawdown()
max_dd = self.config['global_limits']['max_drawdown']
if current_dd >= max_dd:
return False, f"Max drawdown reached ({current_dd:.2%})"
# Toutes validations passées
return True, None
def add_position(self, position: Position):
"""Ajoute une position au portfolio"""
self.positions[position.symbol] = position
# Enregistrer trade
self.daily_trades.append({
'symbol': position.symbol,
'strategy': position.strategy,
'time': position.entry_time,
'risk': position.risk_amount
})
def update_position(self, symbol: str, current_price: float):
"""Met à jour prix d'une position"""
if symbol in self.positions:
position = self.positions[symbol]
position.current_price = current_price
position.unrealized_pnl = (current_price - position.entry_price) * position.quantity
# Vérifier stop-loss / take-profit
self._check_exit_conditions(position)
def close_position(self, symbol: str, exit_price: float) -> float:
"""Ferme une position et retourne P&L"""
if symbol not in self.positions:
return 0.0
position = self.positions[symbol]
pnl = (exit_price - position.entry_price) * position.quantity
# Mettre à jour portfolio
self.portfolio_value += pnl
self.pnl_history.append(pnl)
# Mettre à jour peak
if self.portfolio_value > self.peak_value:
self.peak_value = self.portfolio_value
# Supprimer position
del self.positions[symbol]
return pnl
def get_risk_metrics(self) -> RiskMetrics:
"""Calcule métriques de risque en temps réel"""
return RiskMetrics(
total_risk=self._calculate_total_risk(),
current_drawdown=self._calculate_current_drawdown(),
daily_pnl=self._calculate_daily_pnl(),
weekly_pnl=self._calculate_weekly_pnl(),
portfolio_var=self._calculate_var(),
portfolio_cvar=self._calculate_cvar(),
correlation_matrix=self._calculate_correlation_matrix(),
largest_position=self._get_largest_position(),
num_positions=len(self.positions)
)
def _calculate_total_risk(self) -> float:
"""Calcule risque total du portfolio"""
return sum(pos.risk_amount for pos in self.positions.values())
def _calculate_current_drawdown(self) -> float:
"""Calcule drawdown actuel"""
if self.peak_value == 0:
return 0.0
return (self.peak_value - self.portfolio_value) / self.peak_value
def _calculate_daily_pnl(self) -> float:
"""Calcule P&L du jour"""
today = datetime.now().date()
daily_pnl = sum(
pnl for pnl, time in zip(self.pnl_history, self.daily_trades)
if time['time'].date() == today
)
# Ajouter unrealized P&L
unrealized = sum(pos.unrealized_pnl for pos in self.positions.values())
return daily_pnl + unrealized
def _calculate_var(self, confidence=0.95) -> float:
"""
Calcule Value at Risk (VaR)
VaR = perte maximale avec X% de confiance
"""
if len(self.pnl_history) < 30:
return 0.0
returns = np.array(self.pnl_history[-30:]) / self.portfolio_value
var = np.percentile(returns, (1 - confidence) * 100)
return abs(var * self.portfolio_value)
def _calculate_cvar(self, confidence=0.95) -> float:
"""
Calcule Conditional Value at Risk (CVaR)
CVaR = perte moyenne au-delà du VaR
"""
if len(self.pnl_history) < 30:
return 0.0
returns = np.array(self.pnl_history[-30:]) / self.portfolio_value
var_threshold = np.percentile(returns, (1 - confidence) * 100)
# Moyenne des pertes au-delà du VaR
tail_losses = returns[returns <= var_threshold]
cvar = np.mean(tail_losses) if len(tail_losses) > 0 else 0
return abs(cvar * self.portfolio_value)
def _check_correlation(self, symbol: str, strategy: str) -> bool:
"""
Vérifie corrélation avec positions existantes
"""
if len(self.positions) == 0:
return True
# Simplification: vérifier si même stratégie
# En production: calculer corrélation réelle des returns
same_strategy_positions = [
pos for pos in self.positions.values()
if pos.strategy == strategy
]
max_correlation = self.config['global_limits']['max_correlation']
# Si trop de positions de même stratégie, corrélation trop haute
if len(same_strategy_positions) >= 3:
return False
return True
def _check_exit_conditions(self, position: Position):
"""Vérifie conditions de sortie (stop-loss / take-profit)"""
# Stop-loss hit
if position.current_price <= position.stop_loss:
self.close_position(position.symbol, position.stop_loss)
logger.warning(f"Stop-loss hit for {position.symbol}")
# Take-profit hit
elif position.current_price >= position.take_profit:
self.close_position(position.symbol, position.take_profit)
logger.info(f"Take-profit hit for {position.symbol}")
def check_circuit_breakers(self):
"""
Vérifie conditions d'arrêt automatique
"""
# 1. Drawdown excessif
current_dd = self._calculate_current_drawdown()
if current_dd >= self.config['global_limits']['max_drawdown']:
self.halt_trading(f"Max drawdown reached: {current_dd:.2%}")
return
# 2. Perte journalière excessive
daily_pnl_pct = self._calculate_daily_pnl() / self.portfolio_value
if daily_pnl_pct <= -self.config['global_limits']['max_daily_loss']:
self.halt_trading(f"Max daily loss reached: {daily_pnl_pct:.2%}")
return
# 3. Volatilité extrême
if self._detect_volatility_spike():
self.halt_trading("Extreme volatility detected")
return
def halt_trading(self, reason: str):
"""Arrête le trading"""
self.trading_halted = True
self.halt_reason = reason
logger.critical(f"TRADING HALTED: {reason}")
# Fermer toutes positions (optionnel)
# self._close_all_positions()
# Envoyer alertes
self._send_emergency_alert(reason)
def resume_trading(self):
"""Reprend le trading (manuel uniquement)"""
self.trading_halted = False
self.halt_reason = None
logger.info("Trading resumed")
def _detect_volatility_spike(self) -> bool:
"""Détecte spike de volatilité anormal"""
if len(self.pnl_history) < 20:
return False
recent_vol = np.std(self.pnl_history[-5:])
baseline_vol = np.std(self.pnl_history[-20:-5])
# Spike si volatilité > 3x baseline
return recent_vol > 3 * baseline_vol
def _send_emergency_alert(self, reason: str):
"""Envoie alerte d'urgence"""
# TODO: Implémenter notifications (Telegram, SMS, Email)
pass
def _load_config(self) -> Dict:
"""Charge configuration depuis YAML"""
import yaml
with open('config/risk_limits.yaml', 'r') as f:
return yaml.safe_load(f)
```
---
## ✅ Validation Pré-Trade
### Checklist Complète
```python
class PreTradeValidator:
"""
Validation exhaustive avant chaque trade
"""
def __init__(self, risk_manager: RiskManager):
self.risk_manager = risk_manager
def validate(self, trade_request: Dict) -> tuple[bool, List[str]]:
"""
Exécute toutes validations
Returns:
(is_valid, list_of_errors)
"""
errors = []
# 1. Validation basique
errors.extend(self._validate_basic(trade_request))
# 2. Validation risque
errors.extend(self._validate_risk(trade_request))
# 3. Validation liquidité
errors.extend(self._validate_liquidity(trade_request))
# 4. Validation margin
errors.extend(self._validate_margin(trade_request))
# 5. Validation technique
errors.extend(self._validate_technical(trade_request))
return len(errors) == 0, errors
def _validate_basic(self, trade: Dict) -> List[str]:
"""Validations basiques"""
errors = []
# Stop-loss obligatoire
if 'stop_loss' not in trade or trade['stop_loss'] is None:
errors.append("Stop-loss is mandatory")
# Take-profit obligatoire
if 'take_profit' not in trade or trade['take_profit'] is None:
errors.append("Take-profit is mandatory")
# Quantité positive
if trade.get('quantity', 0) <= 0:
errors.append("Quantity must be positive")
# Prix valide
if trade.get('price', 0) <= 0:
errors.append("Price must be positive")
return errors
def _validate_risk(self, trade: Dict) -> List[str]:
"""Validations risque"""
errors = []
# Risk/Reward ratio
risk = abs(trade['price'] - trade['stop_loss'])
reward = abs(trade['take_profit'] - trade['price'])
if risk > 0:
rr_ratio = reward / risk
if rr_ratio < 1.5:
errors.append(f"Risk/Reward ratio {rr_ratio:.2f} below minimum 1.5")
# Taille position
position_value = trade['price'] * trade['quantity']
position_pct = position_value / self.risk_manager.portfolio_value
if position_pct > 0.05: # 5% max
errors.append(f"Position size {position_pct:.2%} exceeds 5%")
return errors
def _validate_liquidity(self, trade: Dict) -> List[str]:
"""Validations liquidité"""
errors = []
# TODO: Vérifier volume quotidien
# TODO: Vérifier spread bid/ask
# TODO: Vérifier market depth
return errors
def _validate_margin(self, trade: Dict) -> List[str]:
"""Validations margin"""
errors = []
# TODO: Vérifier margin disponible
# TODO: Calculer margin requis
# TODO: Vérifier margin call risk
return errors
def _validate_technical(self, trade: Dict) -> List[str]:
"""Validations techniques"""
errors = []
# Vérifier que stop-loss est du bon côté
if trade['quantity'] > 0: # Long
if trade['stop_loss'] >= trade['price']:
errors.append("Stop-loss must be below entry price for long")
if trade['take_profit'] <= trade['price']:
errors.append("Take-profit must be above entry price for long")
else: # Short
if trade['stop_loss'] <= trade['price']:
errors.append("Stop-loss must be above entry price for short")
if trade['take_profit'] >= trade['price']:
errors.append("Take-profit must be below entry price for short")
return errors
```
---
## 🚨 Circuit Breakers
### Types de Circuit Breakers
```python
class CircuitBreaker:
"""
Système d'arrêt automatique multi-niveaux
"""
def __init__(self):
self.breakers = {
'drawdown': DrawdownBreaker(),
'daily_loss': DailyLossBreaker(),
'volatility': VolatilityBreaker(),
'flash_crash': FlashCrashBreaker(),
'api_failure': APIFailureBreaker(),
'correlation': CorrelationBreaker(),
}
def check_all(self, market_data: Dict, portfolio_state: Dict) -> Optional[str]:
"""
Vérifie tous circuit breakers
Returns:
Reason for halt, or None if all OK
"""
for name, breaker in self.breakers.items():
if breaker.should_halt(market_data, portfolio_state):
return f"{name}: {breaker.get_reason()}"
return None
class DrawdownBreaker:
"""Arrêt si drawdown excessif"""
def __init__(self, max_drawdown=0.10):
self.max_drawdown = max_drawdown
self.reason = ""
def should_halt(self, market_data: Dict, portfolio: Dict) -> bool:
current_dd = portfolio['current_drawdown']
if current_dd >= self.max_drawdown:
self.reason = f"Drawdown {current_dd:.2%} >= {self.max_drawdown:.2%}"
return True
return False
def get_reason(self) -> str:
return self.reason
class VolatilityBreaker:
"""Arrêt si volatilité extrême"""
def __init__(self, spike_threshold=3.0):
self.spike_threshold = spike_threshold
self.reason = ""
def should_halt(self, market_data: Dict, portfolio: Dict) -> bool:
current_vol = market_data.get('current_volatility', 0)
baseline_vol = market_data.get('baseline_volatility', 0)
if baseline_vol > 0 and current_vol > self.spike_threshold * baseline_vol:
self.reason = f"Volatility spike: {current_vol/baseline_vol:.1f}x baseline"
return True
return False
def get_reason(self) -> str:
return self.reason
class FlashCrashBreaker:
"""Arrêt si mouvement de prix extrême"""
def __init__(self, max_move_pct=0.05):
self.max_move_pct = max_move_pct
self.reason = ""
def should_halt(self, market_data: Dict, portfolio: Dict) -> bool:
price_change = market_data.get('price_change_1min', 0)
if abs(price_change) > self.max_move_pct:
self.reason = f"Flash crash detected: {price_change:.2%} move in 1 minute"
return True
return False
def get_reason(self) -> str:
return self.reason
```
---
## 📊 Métriques de Risque
### Calculs Avancés
```python
class RiskMetricsCalculator:
"""
Calcule métriques de risque avancées
"""
@staticmethod
def calculate_var(returns: np.ndarray, confidence=0.95) -> float:
"""Value at Risk"""
return np.percentile(returns, (1 - confidence) * 100)
@staticmethod
def calculate_cvar(returns: np.ndarray, confidence=0.95) -> float:
"""Conditional Value at Risk (Expected Shortfall)"""
var = RiskMetricsCalculator.calculate_var(returns, confidence)
return returns[returns <= var].mean()
@staticmethod
def calculate_sharpe_ratio(returns: np.ndarray, risk_free_rate=0.02) -> float:
"""Sharpe Ratio"""
excess_returns = returns - risk_free_rate / 252 # Daily
return np.mean(excess_returns) / np.std(excess_returns) * np.sqrt(252)
@staticmethod
def calculate_sortino_ratio(returns: np.ndarray, risk_free_rate=0.02) -> float:
"""Sortino Ratio (downside deviation)"""
excess_returns = returns - risk_free_rate / 252
downside_returns = returns[returns < 0]
downside_std = np.std(downside_returns)
return np.mean(excess_returns) / downside_std * np.sqrt(252)
@staticmethod
def calculate_max_drawdown(equity_curve: np.ndarray) -> float:
"""Maximum Drawdown"""
peak = np.maximum.accumulate(equity_curve)
drawdown = (equity_curve - peak) / peak
return np.min(drawdown)
@staticmethod
def calculate_calmar_ratio(returns: np.ndarray, equity_curve: np.ndarray) -> float:
"""Calmar Ratio (Return / Max Drawdown)"""
annual_return = np.mean(returns) * 252
max_dd = abs(RiskMetricsCalculator.calculate_max_drawdown(equity_curve))
return annual_return / max_dd if max_dd > 0 else 0
```
---
## 🔔 Système d'Alertes
### Configuration Alertes
```yaml
# config/alerts.yaml
alerts:
risk_threshold_breach:
channels: ['telegram', 'email']
priority: high
conditions:
- total_risk > max_portfolio_risk
- current_drawdown > 0.08 # 80% du max
- daily_loss > 0.025 # 83% du max
position_alerts:
channels: ['telegram']
priority: medium
conditions:
- position_size > 0.04 # 80% du max
- correlation > 0.6 # 85% du max
circuit_breaker:
channels: ['telegram', 'sms', 'email']
priority: critical
conditions:
- trading_halted == true
```
---
**Suite dans le prochain fichier...**

849
docs/STRATEGY_GUIDE.md Normal file
View File

@@ -0,0 +1,849 @@
# 📊 Guide des Stratégies - Trading AI Secure
## 📋 Table des Matières
1. [Vue d'ensemble](#vue-densemble)
2. [Architecture Stratégies](#architecture-stratégies)
3. [Scalping Strategy](#scalping-strategy)
4. [Intraday Strategy](#intraday-strategy)
5. [Swing Strategy](#swing-strategy)
6. [Paramètres Adaptatifs](#paramètres-adaptatifs)
7. [Combinaison Multi-Stratégie](#combinaison-multi-stratégie)
8. [Implémentation](#implémentation)
---
## 🎯 Vue d'ensemble
### Philosophie Multi-Stratégie
Le système utilise **3 stratégies complémentaires** qui opèrent sur différents timeframes et profils de risque :
```
┌────────────────────────────────────────────────────────────┐
│ STRATÉGIES COMPLÉMENTAIRES │
├────────────────────────────────────────────────────────────┤
│ │
│ SCALPING (Court Terme) │
│ ├─ Timeframe: 1-5 minutes │
│ ├─ Objectif: Micro-mouvements │
│ ├─ Win Rate: 60-70% │
│ └─ Risk/Trade: 0.5-1% │
│ │
│ INTRADAY (Moyen Terme) │
│ ├─ Timeframe: 15-60 minutes │
│ ├─ Objectif: Tendances journalières │
│ ├─ Win Rate: 55-65% │
│ └─ Risk/Trade: 1-2% │
│ │
│ SWING (Long Terme) │
│ ├─ Timeframe: 4H-1D │
│ ├─ Objectif: Mouvements multi-jours │
│ ├─ Win Rate: 50-60% │
│ └─ Risk/Trade: 2-3% │
│ │
└────────────────────────────────────────────────────────────┘
```
### Avantages Multi-Stratégie
1. **Diversification temporelle** : Réduit corrélation
2. **Opportunités multiples** : Capture différents mouvements
3. **Lissage performance** : Compense pertes d'une stratégie
4. **Adaptabilité** : Ajuste poids selon régime de marché
---
## 🏗️ Architecture Stratégies
### Classe de Base Abstraite
```python
# src/strategies/base_strategy.py
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass
from datetime import datetime
import pandas as pd
import numpy as np
@dataclass
class Signal:
"""Signal de trading"""
symbol: str
direction: str # 'LONG' or 'SHORT'
entry_price: float
stop_loss: float
take_profit: float
confidence: float # 0.0 to 1.0
timestamp: datetime
strategy: str
metadata: Dict
@dataclass
class StrategyConfig:
"""Configuration stratégie"""
name: str
timeframe: str
risk_per_trade: float
max_holding_time: int # seconds
max_trades_per_day: int
min_profit_target: float
max_slippage: float
# Paramètres adaptatifs
adaptive_params: Dict
class BaseStrategy(ABC):
"""
Classe de base pour toutes les stratégies
Toutes stratégies doivent implémenter:
- analyze(): Analyse marché et génère signaux
- calculate_position_size(): Calcule taille position
- update_parameters(): Met à jour paramètres adaptatifs
"""
def __init__(self, config: StrategyConfig):
self.config = config
self.name = config.name
# État
self.active_positions: List[Dict] = []
self.closed_trades: List[Dict] = []
self.parameters = config.adaptive_params.copy()
# Performance
self.win_rate = 0.5
self.avg_win = 0.0
self.avg_loss = 0.0
self.sharpe_ratio = 0.0
@abstractmethod
def analyze(self, market_data: pd.DataFrame) -> Optional[Signal]:
"""
Analyse données marché et génère signal
Args:
market_data: DataFrame avec OHLCV + indicateurs
Returns:
Signal si opportunité détectée, None sinon
"""
pass
@abstractmethod
def calculate_indicators(self, data: pd.DataFrame) -> pd.DataFrame:
"""
Calcule indicateurs techniques nécessaires
Args:
data: DataFrame avec OHLCV
Returns:
DataFrame avec indicateurs ajoutés
"""
pass
def calculate_position_size(
self,
signal: Signal,
portfolio_value: float,
current_volatility: float
) -> float:
"""
Calcule taille position optimale
Utilise:
- Kelly Criterion adaptatif
- Volatility adjustment
- Risk per trade limit
"""
# Kelly de base
kelly = (self.win_rate * (self.avg_win / abs(self.avg_loss)) - (1 - self.win_rate)) / (self.avg_win / abs(self.avg_loss))
# Ajuster selon volatilité
vol_adjustment = 0.02 / max(current_volatility, 0.01) # Target 2% vol
kelly *= vol_adjustment
# Ajuster selon confiance du signal
kelly *= signal.confidence
# Appliquer limite risk per trade
kelly = min(kelly, self.config.risk_per_trade)
# Calculer taille position
risk_amount = portfolio_value * kelly
stop_distance = abs(signal.entry_price - signal.stop_loss)
position_size = risk_amount / stop_distance
return position_size
def update_parameters(self, recent_performance: Dict):
"""
Met à jour paramètres adaptatifs selon performance
Args:
recent_performance: Métriques des 30 derniers jours
"""
# Mettre à jour statistiques
self.win_rate = recent_performance.get('win_rate', self.win_rate)
self.avg_win = recent_performance.get('avg_win', self.avg_win)
self.avg_loss = recent_performance.get('avg_loss', self.avg_loss)
self.sharpe_ratio = recent_performance.get('sharpe', self.sharpe_ratio)
# Ajuster paramètres si sous-performance
if self.sharpe_ratio < 1.0:
self._reduce_aggressiveness()
elif self.sharpe_ratio > 2.0:
self._increase_aggressiveness()
def _reduce_aggressiveness(self):
"""Réduit agressivité si sous-performance"""
# Augmenter seuils de confiance
if 'min_confidence' in self.parameters:
self.parameters['min_confidence'] = min(
self.parameters['min_confidence'] * 1.1,
0.8
)
# Réduire nombre de trades
self.config.max_trades_per_day = max(
int(self.config.max_trades_per_day * 0.8),
1
)
def _increase_aggressiveness(self):
"""Augmente agressivité si sur-performance"""
# Réduire seuils de confiance
if 'min_confidence' in self.parameters:
self.parameters['min_confidence'] = max(
self.parameters['min_confidence'] * 0.9,
0.5
)
# Augmenter nombre de trades
self.config.max_trades_per_day = min(
int(self.config.max_trades_per_day * 1.2),
100
)
def record_trade(self, trade: Dict):
"""Enregistre trade fermé"""
self.closed_trades.append(trade)
# Mettre à jour statistiques
self._update_statistics()
def _update_statistics(self):
"""Met à jour statistiques de performance"""
if len(self.closed_trades) < 10:
return
recent_trades = self.closed_trades[-30:] # 30 derniers trades
wins = [t for t in recent_trades if t['pnl'] > 0]
losses = [t for t in recent_trades if t['pnl'] < 0]
self.win_rate = len(wins) / len(recent_trades)
self.avg_win = np.mean([t['pnl'] for t in wins]) if wins else 0
self.avg_loss = np.mean([t['pnl'] for t in losses]) if losses else 0
# Calculer Sharpe
returns = [t['pnl'] / t['risk'] for t in recent_trades]
self.sharpe_ratio = np.mean(returns) / np.std(returns) if np.std(returns) > 0 else 0
```
---
## ⚡ Scalping Strategy
### Caractéristiques
- **Timeframe** : 1-5 minutes
- **Holding Time** : 5-30 minutes maximum
- **Risk per Trade** : 0.5-1%
- **Win Rate Target** : 60-70%
- **Profit Target** : 0.3-0.5% par trade
### Indicateurs Utilisés
```python
# src/strategies/scalping/scalping_strategy.py
class ScalpingStrategy(BaseStrategy):
"""
Stratégie de scalping basée sur:
- Mean reversion (Bollinger Bands)
- Momentum (RSI, MACD)
- Volume profile
- Order flow imbalance
"""
def __init__(self, config: StrategyConfig):
super().__init__(config)
# Paramètres adaptatifs
self.parameters = {
'bb_period': 20,
'bb_std': 2.0,
'rsi_period': 14,
'rsi_oversold': 30,
'rsi_overbought': 70,
'volume_threshold': 1.5, # 1.5x volume moyen
'min_confidence': 0.65,
}
def calculate_indicators(self, data: pd.DataFrame) -> pd.DataFrame:
"""Calcule indicateurs scalping"""
df = data.copy()
# Bollinger Bands
bb_period = self.parameters['bb_period']
bb_std = self.parameters['bb_std']
df['bb_middle'] = df['close'].rolling(bb_period).mean()
df['bb_std'] = df['close'].rolling(bb_period).std()
df['bb_upper'] = df['bb_middle'] + (bb_std * df['bb_std'])
df['bb_lower'] = df['bb_middle'] - (bb_std * df['bb_std'])
df['bb_position'] = (df['close'] - df['bb_lower']) / (df['bb_upper'] - df['bb_lower'])
# RSI
rsi_period = self.parameters['rsi_period']
delta = df['close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(rsi_period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(rsi_period).mean()
rs = gain / loss
df['rsi'] = 100 - (100 / (1 + rs))
# MACD
df['ema_12'] = df['close'].ewm(span=12).mean()
df['ema_26'] = df['close'].ewm(span=26).mean()
df['macd'] = df['ema_12'] - df['ema_26']
df['macd_signal'] = df['macd'].ewm(span=9).mean()
df['macd_hist'] = df['macd'] - df['macd_signal']
# Volume
df['volume_ma'] = df['volume'].rolling(20).mean()
df['volume_ratio'] = df['volume'] / df['volume_ma']
# ATR pour stop-loss
df['tr'] = np.maximum(
df['high'] - df['low'],
np.maximum(
abs(df['high'] - df['close'].shift(1)),
abs(df['low'] - df['close'].shift(1))
)
)
df['atr'] = df['tr'].rolling(14).mean()
return df
def analyze(self, market_data: pd.DataFrame) -> Optional[Signal]:
"""
Génère signal de scalping
Conditions LONG:
- Prix proche BB lower (oversold)
- RSI < 30 (oversold)
- MACD histogram positif (momentum reversal)
- Volume > 1.5x moyenne
Conditions SHORT:
- Prix proche BB upper (overbought)
- RSI > 70 (overbought)
- MACD histogram négatif
- Volume > 1.5x moyenne
"""
df = self.calculate_indicators(market_data)
if len(df) < 50:
return None
current = df.iloc[-1]
prev = df.iloc[-2]
# Vérifier volume
if current['volume_ratio'] < self.parameters['volume_threshold']:
return None
# Signal LONG
if (current['bb_position'] < 0.2 and # Proche BB lower
current['rsi'] < self.parameters['rsi_oversold'] and
current['macd_hist'] > 0 and prev['macd_hist'] <= 0): # MACD cross
confidence = self._calculate_confidence(df, 'LONG')
if confidence >= self.parameters['min_confidence']:
return Signal(
symbol=market_data.attrs.get('symbol', 'UNKNOWN'),
direction='LONG',
entry_price=current['close'],
stop_loss=current['close'] - (2 * current['atr']),
take_profit=current['close'] + (3 * current['atr']), # R:R 1.5
confidence=confidence,
timestamp=current.name,
strategy='scalping',
metadata={
'rsi': current['rsi'],
'bb_position': current['bb_position'],
'volume_ratio': current['volume_ratio']
}
)
# Signal SHORT
elif (current['bb_position'] > 0.8 and # Proche BB upper
current['rsi'] > self.parameters['rsi_overbought'] and
current['macd_hist'] < 0 and prev['macd_hist'] >= 0):
confidence = self._calculate_confidence(df, 'SHORT')
if confidence >= self.parameters['min_confidence']:
return Signal(
symbol=market_data.attrs.get('symbol', 'UNKNOWN'),
direction='SHORT',
entry_price=current['close'],
stop_loss=current['close'] + (2 * current['atr']),
take_profit=current['close'] - (3 * current['atr']),
confidence=confidence,
timestamp=current.name,
strategy='scalping',
metadata={
'rsi': current['rsi'],
'bb_position': current['bb_position'],
'volume_ratio': current['volume_ratio']
}
)
return None
def _calculate_confidence(self, df: pd.DataFrame, direction: str) -> float:
"""
Calcule confiance du signal (0.0 à 1.0)
Facteurs:
- Force de l'oversold/overbought
- Confirmation volume
- Momentum MACD
- Historique win rate
"""
current = df.iloc[-1]
confidence = 0.5 # Base
if direction == 'LONG':
# RSI oversold strength
rsi_strength = (30 - current['rsi']) / 30
confidence += 0.2 * max(0, rsi_strength)
# BB position
bb_strength = (0.2 - current['bb_position']) / 0.2
confidence += 0.15 * max(0, bb_strength)
else: # SHORT
# RSI overbought strength
rsi_strength = (current['rsi'] - 70) / 30
confidence += 0.2 * max(0, rsi_strength)
# BB position
bb_strength = (current['bb_position'] - 0.8) / 0.2
confidence += 0.15 * max(0, bb_strength)
# Volume confirmation
volume_strength = min((current['volume_ratio'] - 1.5) / 1.5, 1.0)
confidence += 0.15 * volume_strength
# Historical win rate
confidence += 0.1 * (self.win_rate - 0.5)
return np.clip(confidence, 0.0, 1.0)
```
---
## 📈 Intraday Strategy
### Caractéristiques
- **Timeframe** : 15-60 minutes
- **Holding Time** : 2-8 heures
- **Risk per Trade** : 1-2%
- **Win Rate Target** : 55-65%
- **Profit Target** : 1-2% par trade
### Implémentation
```python
# src/strategies/intraday/intraday_strategy.py
class IntradayStrategy(BaseStrategy):
"""
Stratégie intraday basée sur:
- Trend following (EMA crossovers)
- Support/Resistance
- Volume analysis
- Market regime
"""
def __init__(self, config: StrategyConfig):
super().__init__(config)
self.parameters = {
'ema_fast': 9,
'ema_slow': 21,
'ema_trend': 50,
'atr_multiplier': 2.5,
'volume_confirmation': 1.2,
'min_confidence': 0.60,
}
def calculate_indicators(self, data: pd.DataFrame) -> pd.DataFrame:
"""Calcule indicateurs intraday"""
df = data.copy()
# EMAs
df['ema_fast'] = df['close'].ewm(span=self.parameters['ema_fast']).mean()
df['ema_slow'] = df['close'].ewm(span=self.parameters['ema_slow']).mean()
df['ema_trend'] = df['close'].ewm(span=self.parameters['ema_trend']).mean()
# Trend direction
df['trend'] = np.where(df['ema_fast'] > df['ema_slow'], 1, -1)
# ATR
df['tr'] = np.maximum(
df['high'] - df['low'],
np.maximum(
abs(df['high'] - df['close'].shift(1)),
abs(df['low'] - df['close'].shift(1))
)
)
df['atr'] = df['tr'].rolling(14).mean()
# Support/Resistance (pivot points)
df['pivot'] = (df['high'] + df['low'] + df['close']) / 3
df['r1'] = 2 * df['pivot'] - df['low']
df['s1'] = 2 * df['pivot'] - df['high']
# Volume
df['volume_ma'] = df['volume'].rolling(20).mean()
df['volume_ratio'] = df['volume'] / df['volume_ma']
# ADX (trend strength)
df['adx'] = self._calculate_adx(df)
return df
def analyze(self, market_data: pd.DataFrame) -> Optional[Signal]:
"""
Génère signal intraday
Conditions LONG:
- EMA fast cross above EMA slow
- Prix au-dessus EMA trend (uptrend)
- ADX > 25 (strong trend)
- Volume confirmation
Conditions SHORT:
- EMA fast cross below EMA slow
- Prix en-dessous EMA trend (downtrend)
- ADX > 25
- Volume confirmation
"""
df = self.calculate_indicators(market_data)
if len(df) < 100:
return None
current = df.iloc[-1]
prev = df.iloc[-2]
# Vérifier trend strength
if current['adx'] < 25:
return None
# Signal LONG (bullish crossover)
if (current['ema_fast'] > current['ema_slow'] and
prev['ema_fast'] <= prev['ema_slow'] and
current['close'] > current['ema_trend'] and
current['volume_ratio'] > self.parameters['volume_confirmation']):
confidence = self._calculate_confidence(df, 'LONG')
if confidence >= self.parameters['min_confidence']:
atr_mult = self.parameters['atr_multiplier']
return Signal(
symbol=market_data.attrs.get('symbol', 'UNKNOWN'),
direction='LONG',
entry_price=current['close'],
stop_loss=current['close'] - (atr_mult * current['atr']),
take_profit=current['close'] + (atr_mult * 2 * current['atr']),
confidence=confidence,
timestamp=current.name,
strategy='intraday',
metadata={
'adx': current['adx'],
'trend': 'UP',
'volume_ratio': current['volume_ratio']
}
)
# Signal SHORT (bearish crossover)
elif (current['ema_fast'] < current['ema_slow'] and
prev['ema_fast'] >= prev['ema_slow'] and
current['close'] < current['ema_trend'] and
current['volume_ratio'] > self.parameters['volume_confirmation']):
confidence = self._calculate_confidence(df, 'SHORT')
if confidence >= self.parameters['min_confidence']:
atr_mult = self.parameters['atr_multiplier']
return Signal(
symbol=market_data.attrs.get('symbol', 'UNKNOWN'),
direction='SHORT',
entry_price=current['close'],
stop_loss=current['close'] + (atr_mult * current['atr']),
take_profit=current['close'] - (atr_mult * 2 * current['atr']),
confidence=confidence,
timestamp=current.name,
strategy='intraday',
metadata={
'adx': current['adx'],
'trend': 'DOWN',
'volume_ratio': current['volume_ratio']
}
)
return None
def _calculate_adx(self, df: pd.DataFrame, period=14) -> pd.Series:
"""Calcule Average Directional Index"""
# Simplified ADX calculation
high_diff = df['high'].diff()
low_diff = -df['low'].diff()
pos_dm = np.where((high_diff > low_diff) & (high_diff > 0), high_diff, 0)
neg_dm = np.where((low_diff > high_diff) & (low_diff > 0), low_diff, 0)
tr = df['tr']
pos_di = 100 * pd.Series(pos_dm).rolling(period).mean() / tr.rolling(period).mean()
neg_di = 100 * pd.Series(neg_dm).rolling(period).mean() / tr.rolling(period).mean()
dx = 100 * abs(pos_di - neg_di) / (pos_di + neg_di)
adx = dx.rolling(period).mean()
return adx
def _calculate_confidence(self, df: pd.DataFrame, direction: str) -> float:
"""Calcule confiance signal intraday"""
current = df.iloc[-1]
confidence = 0.5
# ADX strength
adx_strength = min((current['adx'] - 25) / 25, 1.0)
confidence += 0.2 * adx_strength
# Volume confirmation
volume_strength = min((current['volume_ratio'] - 1.2) / 1.0, 1.0)
confidence += 0.15 * volume_strength
# Trend alignment
if direction == 'LONG':
trend_alignment = (current['close'] - current['ema_trend']) / current['ema_trend']
else:
trend_alignment = (current['ema_trend'] - current['close']) / current['ema_trend']
confidence += 0.15 * min(trend_alignment * 10, 1.0)
# Historical performance
confidence += 0.1 * (self.win_rate - 0.5)
return np.clip(confidence, 0.0, 1.0)
```
---
## 🌊 Swing Strategy
### Caractéristiques
- **Timeframe** : 4H-1D
- **Holding Time** : 2-5 jours
- **Risk per Trade** : 2-3%
- **Win Rate Target** : 50-60%
- **Profit Target** : 3-5% par trade
### Implémentation
```python
# src/strategies/swing/swing_strategy.py
class SwingStrategy(BaseStrategy):
"""
Stratégie swing basée sur:
- Multi-timeframe analysis
- Chart patterns
- Fibonacci retracements
- Macro trends
"""
def __init__(self, config: StrategyConfig):
super().__init__(config)
self.parameters = {
'sma_short': 20,
'sma_long': 50,
'rsi_period': 14,
'macd_fast': 12,
'macd_slow': 26,
'macd_signal': 9,
'min_confidence': 0.55,
}
def calculate_indicators(self, data: pd.DataFrame) -> pd.DataFrame:
"""Calcule indicateurs swing"""
df = data.copy()
# SMAs
df['sma_short'] = df['close'].rolling(self.parameters['sma_short']).mean()
df['sma_long'] = df['close'].rolling(self.parameters['sma_long']).mean()
# RSI
delta = df['close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(14).mean()
loss = (-delta.where(delta < 0, 0)).rolling(14).mean()
rs = gain / loss
df['rsi'] = 100 - (100 / (1 + rs))
# MACD
df['ema_fast'] = df['close'].ewm(span=self.parameters['macd_fast']).mean()
df['ema_slow'] = df['close'].ewm(span=self.parameters['macd_slow']).mean()
df['macd'] = df['ema_fast'] - df['ema_slow']
df['macd_signal'] = df['macd'].ewm(span=self.parameters['macd_signal']).mean()
df['macd_hist'] = df['macd'] - df['macd_signal']
# ATR
df['tr'] = np.maximum(
df['high'] - df['low'],
np.maximum(
abs(df['high'] - df['close'].shift(1)),
abs(df['low'] - df['close'].shift(1))
)
)
df['atr'] = df['tr'].rolling(14).mean()
# Fibonacci levels (simplified)
df['fib_high'] = df['high'].rolling(50).max()
df['fib_low'] = df['low'].rolling(50).min()
df['fib_range'] = df['fib_high'] - df['fib_low']
df['fib_382'] = df['fib_high'] - 0.382 * df['fib_range']
df['fib_618'] = df['fib_high'] - 0.618 * df['fib_range']
return df
def analyze(self, market_data: pd.DataFrame) -> Optional[Signal]:
"""
Génère signal swing
Conditions LONG:
- SMA short > SMA long (uptrend)
- RSI 40-60 (not overbought)
- MACD bullish
- Prix near Fibonacci support
Conditions SHORT:
- SMA short < SMA long (downtrend)
- RSI 40-60 (not oversold)
- MACD bearish
- Prix near Fibonacci resistance
"""
df = self.calculate_indicators(market_data)
if len(df) < 100:
return None
current = df.iloc[-1]
prev = df.iloc[-2]
# Signal LONG
if (current['sma_short'] > current['sma_long'] and
40 < current['rsi'] < 60 and
current['macd'] > current['macd_signal'] and
abs(current['close'] - current['fib_618']) / current['close'] < 0.01):
confidence = self._calculate_confidence(df, 'LONG')
if confidence >= self.parameters['min_confidence']:
return Signal(
symbol=market_data.attrs.get('symbol', 'UNKNOWN'),
direction='LONG',
entry_price=current['close'],
stop_loss=current['fib_low'],
take_profit=current['fib_high'],
confidence=confidence,
timestamp=current.name,
strategy='swing',
metadata={
'rsi': current['rsi'],
'macd_hist': current['macd_hist'],
'fib_level': 'support_618'
}
)
# Signal SHORT
elif (current['sma_short'] < current['sma_long'] and
40 < current['rsi'] < 60 and
current['macd'] < current['macd_signal'] and
abs(current['close'] - current['fib_382']) / current['close'] < 0.01):
confidence = self._calculate_confidence(df, 'SHORT')
if confidence >= self.parameters['min_confidence']:
return Signal(
symbol=market_data.attrs.get('symbol', 'UNKNOWN'),
direction='SHORT',
entry_price=current['close'],
stop_loss=current['fib_high'],
take_profit=current['fib_low'],
confidence=confidence,
timestamp=current.name,
strategy='swing',
metadata={
'rsi': current['rsi'],
'macd_hist': current['macd_hist'],
'fib_level': 'resistance_382'
}
)
return None
def _calculate_confidence(self, df: pd.DataFrame, direction: str) -> float:
"""Calcule confiance signal swing"""
current = df.iloc[-1]
confidence = 0.5
# Trend strength
sma_distance = abs(current['sma_short'] - current['sma_long']) / current['sma_long']
confidence += 0.2 * min(sma_distance * 20, 1.0)
# MACD strength
macd_strength = abs(current['macd_hist']) / current['close']
confidence += 0.15 * min(macd_strength * 100, 1.0)
# RSI neutral zone (good for swing)
rsi_score = 1 - abs(current['rsi'] - 50) / 50
confidence += 0.15 * rsi_score
# Historical performance
confidence += 0.1 * (self.win_rate - 0.5)
return np.clip(confidence, 0.0, 1.0)
```
---
**Suite dans le prochain fichier...**