32 KiB
32 KiB
📊 Guide des Stratégies - Trading AI Secure
📋 Table des Matières
- Vue d'ensemble
- Architecture Stratégies
- Scalping Strategy
- Intraday Strategy
- Swing Strategy
- Paramètres Adaptatifs
- Combinaison Multi-Stratégie
- 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
- Diversification temporelle : Réduit corrélation
- Opportunités multiples : Capture différents mouvements
- Lissage performance : Compense pertes d'une stratégie
- Adaptabilité : Ajuste poids selon régime de marché
🏗️ Architecture Stratégies
Classe de Base Abstraite
# 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
# 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'] + (4 * current['atr']), # R:R 2:1 (breakeven ~34%)
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'] - (4 * current['atr']), # R:R 2:1 (breakeven ~34%)
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
# 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
# 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)
ML-Driven Strategy (Phase 4b — 2026-03-08)
Concept
Contrairement aux stratégies règle-based (scalping/intraday/swing), la MLDrivenStrategy remplace les conditions codées en dur par un modèle XGBoost/LightGBM entraîné sur des données historiques.
Le modèle apprend quelles combinaisons d'indicateurs classiques sont réellement prédictives, reproduisant l'intuition d'un trader expérimenté.
Fichiers
| Fichier | Rôle |
|---|---|
src/strategies/ml_driven/ml_strategy.py |
Stratégie (interface BaseStrategy) |
src/ml/ml_strategy_model.py |
Entraînement + prédiction |
src/ml/features/technical_features.py |
~50 features TA |
src/ml/features/label_generator.py |
Labels LONG/SHORT/NEUTRAL |
Documentation complète : docs/ML_STRATEGY_GUIDE.md
Features utilisées
- RSI : valeur, zones survente/surachat, divergences haussières/baissières
- MACD : crossovers, histogramme, pente du momentum
- Bollinger Bands : position relative, squeeze, cassures et rebonds
- Supports/Résistances : distance aux niveaux pivots locaux (50 barres)
- Points Pivots : classiques (R1/R2/S1/S2) + Fibonacci (38.2%, 61.8%, 100%)
- ATR : volatilité normalisée, ratio vs moyenne
- Chandeliers : marteau, étoile filante, engulfing haussier/baissier, doji
- EMAs : alignement 8/21/50/200, distance % du prix, pente
- Volume : ratio vs moyenne, pics, OBV
- Sessions : Londres (8h-16h), NY (13h-21h), chevauchement (13h-16h)
Labels (supervision)
Pour chaque barre i, simulation forward sur N barres :
- LONG (1) : HIGH atteint
entry + tp_atr × ATRavant que LOW descende sousentry - sl_atr × ATR - SHORT (-1) : l'inverse
- NEUTRAL (0) : ni TP ni SL dans l'horizon
Usage via API
# Entraîner
curl -X POST http://localhost:8100/trading/train \
-H "Content-Type: application/json" \
-d '{"symbol":"EURUSD","timeframe":"1h","period":"2y","model_type":"xgboost","tp_atr_mult":2.0,"sl_atr_mult":1.0}'
# Suivre l'entraînement
curl http://localhost:8100/trading/train/{job_id}
# Lister les modèles disponibles
curl http://localhost:8100/trading/ml-models
# Feature importance
curl http://localhost:8100/trading/ml-models/EURUSD/1h/importance
Paramètres de configuration
config = {
'name': 'ml_driven',
'symbol': 'EURUSD',
'timeframe': '1h',
'risk_per_trade': 0.01,
'model_type': 'xgboost', # xgboost | lightgbm | random_forest
'min_confidence': 0.55, # Seuil de confiance minimum
'tp_atr_mult': 2.0, # TP = entry ± 2×ATR → R:R = 2:1
'sl_atr_mult': 1.0, # SL = entry ∓ 1×ATR
'auto_load': True, # Charge le modèle existant au démarrage
}
Validation
Walk-forward cross-validation (3 folds temporels) — protège contre l'overfitting.
Métriques cibles :
wf_accuracy > 0.55wf_precision > 0.50sur signaux directionnels- Distribution LONG/SHORT équilibrée
Modèles sauvegardés
models/ml_strategy/
├── EURUSD_1h_xgboost.joblib
└── EURUSD_1h_xgboost_meta.json
Chargement automatique au démarrage si auto_load=True.