Classification ML avec QuantBook - Notebook de Recherche

Companion notebook pour QC-Py-19-ML-Supervised-Classification Duree: 45 minutes | Niveau: Intermediaire | Python + QuantConnect


Objectifs d’apprentissage

A la fin de ce notebook, vous saurez :

  1. Utiliser QuantBook pour charger et explorer les données financieres
  2. Créer des features techniques pour le Machine Learning (RSI, EMA, MACD)
  3. Construire une variable cible pour la prediction de direction
  4. Entrainer un RandomForestClassifier avec validation temporelle
  5. Evaluer les performances avec metriques de classification
  6. Persister le modèle via ObjectStore pour l’utiliser dans un algorithme

Prerequis

  • Notebook QC-Py-04 (Research Workflow) recommande
  • Connaissance de base sklearn (fit, predict, classification_report)
  • Compte QuantConnect avec acces Research

Duree estimee : 45 minutes



IMPORTANT - Mode d’emploi de ce notebook

Ce notebook est concu pour etre execute dans QuantConnect Research Environment (QuantBook). Il utilise l’API synchrone de QuantBook pour explorer les données et entrainer un modèle ML.

Workflow de développement ML sur QuantConnect : 1. Recherche (ce notebook) : Explorer, entrainer, evaluer en QuantBook 2. Persistance : Sauvegarder le modèle dans ObjectStore 3. Production : Charger le modèle dans main.py pour le trading

Voir le notebook QC-Py-19 pour la théorie complete sur la classification ML.


1. Setup QuantBook (5 min)

Imports et Configuration

Commencons par importer les modules necessaires et configurer l’environnement.

# Imports QuantConnect
from QuantConnect import *
from QuantConnect.Data import *
from QuantConnect.Research import QuantBook

# Imports pour analyse et ML
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split, TimeSeriesSplit
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
import matplotlib.pyplot as plt

# Configuration matplotlib (compatible QuantBook - pas de magic commands)
plt.rcParams['figure.figsize'] = (12, 6)
plt.rcParams['axes.grid'] = True
plt.rcParams['axes.facecolor'] = '#f8f8f8'
plt.rcParams['font.size'] = 10

print("Imports reussis")
Imports reussis

Creation de l’Instance QuantBook

QuantBook est l’API de recherche synchrone de QuantConnect. Contrairement a QCAlgorithm qui est event-driven, QuantBook permet d’executer du code cellule par cellule dans un notebook Jupyter.

# Creer instance QuantBook
qb = QuantBook()

print("QuantBook initialise")
print(f"Type: {type(qb)}")
QuantBook initialise
Type: <class 'QuantConnect.Research.QuantBook'>

2. Data Loading with QuantBook (10 min)

Ajouter des Securities

Ajoutons SPY et QQQ pour notre analyse. Ces deux ETF sont representatifs du marche US.

# Ajouter securities
spy = qb.AddEquity("SPY", Resolution.Daily)
qqq = qb.AddEquity("QQQ", Resolution.Daily)

print("Securities ajoutees:")
print(f"  SPY: {spy.Symbol}")
print(f"  QQQ: {qqq.Symbol}")
print(f"\nTotal securities: {len(qb.Securities)}")
Securities ajoutees:
  SPY: SPY
  QQQ: QQQ

Total securities: 2

Recuperer les Données Historiques

Point cle : qb.History() retourne directement un DataFrame pandas avec MultiIndex (symbol, time), contrairement a self.History() dans QCAlgorithm qui retourne un objet Slice.

Cette API synchrone est ideale pour la recherche et le prototypage ML.

# Recuperer 2 ans de donnees (504 jours de trading)
history = qb.History(qb.Securities.Keys, 504, Resolution.Daily)

print(f"Type de history: {type(history)}")
print(f"Shape: {history.shape}")
print(f"\nPremieres lignes:")
history.head()
Type de history: <class 'pandas.core.frame.DataFrame'>
Shape: (1008, 5)

Premieres lignes:
close high low open volume
symbol time
SPY 2024-06-05 16:00:00 521.967684 521.967684 516.188328 518.150575 40587259.0
2024-06-06 16:00:00 521.957922 522.690104 520.024961 522.260557 27382947.0
2024-06-07 16:00:00 521.323364 524.134943 519.898050 521.020729 35375224.0
2024-06-10 16:00:00 522.934165 523.256325 519.927337 520.571657 32232296.0
2024-06-11 16:00:00 524.193518 524.252092 519.409929 521.401464 31617845.0

Extraire les Données SPY

Pour simplifier l’analyse, concentrons-nous sur SPY dans un premier temps.

# Extraire donnees SPY uniquement
df = history.loc["SPY"].copy()

print(f"SPY DataFrame shape: {df.shape}")
print(f"\nColonnes: {df.columns.tolist()}")
print(f"\nPeriode: {df.index.min()} a {df.index.max()}")
print(f"\nPremieres lignes:")
df.head()
SPY DataFrame shape: (504, 5)

Colonnes: ['close', 'high', 'low', 'open', 'volume']

Periode: 2024-06-05 16:00:00 a 2026-06-09 16:00:00

Premieres lignes:
close high low open volume
time
2024-06-05 16:00:00 521.967684 521.967684 516.188328 518.150575 40587259.0
2024-06-06 16:00:00 521.957922 522.690104 520.024961 522.260557 27382947.0
2024-06-07 16:00:00 521.323364 524.134943 519.898050 521.020729 35375224.0
2024-06-10 16:00:00 522.934165 523.256325 519.927337 520.571657 32232296.0
2024-06-11 16:00:00 524.193518 524.252092 519.409929 521.401464 31617845.0

Interpretation : Structure des Données

Aspect Valeur Signification
Colonnes open, high, low, close, volume Données OHLCV standard
Index DatetimeIndex Timestamps quotidiens
Shape ~504 lignes 2 ans de données quotidiennes

Note technique : QuantBook synchronise automatiquement les données. Pas besoin de gerer les splits/dividendes manuellement.


3. Feature Engineering (15 min)

Créer des Features Techniques

Pour notre modèle de classification, nous allons créer plusieurs indicateurs techniques comme features : - RSI (Relative Strength Index) : Momentum oscillator - EMA (Exponential Moving Average) : Tendance - MACD : Momentum et tendance combines - Returns : Rendements passes

# Fonction pour calculer le RSI
def calculate_rsi(series, period=14):
    """Calculer le RSI (Relative Strength Index)."""
    delta = series.diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
    rs = gain / loss
    rsi = 100 - (100 / (1 + rs))
    return rsi

# Fonction pour calculer l'EMA
def calculate_ema(series, span):
    """Calculer l'Exponential Moving Average."""
    return series.ewm(span=span, adjust=False).mean()

# Fonction pour calculer le MACD
def calculate_macd(series, fast=12, slow=26, signal=9):
    """Calculer le MACD (Moving Average Convergence Divergence)."""
    ema_fast = series.ewm(span=fast, adjust=False).mean()
    ema_slow = series.ewm(span=slow, adjust=False).mean()
    macd_line = ema_fast - ema_slow
    signal_line = macd_line.ewm(span=signal, adjust=False).mean()
    histogram = macd_line - signal_line
    return macd_line, signal_line, histogram

print("Fonctions d'indicateurs definies")
Fonctions d'indicateurs definies

Application des Indicateurs

Appliquons les indicateurs sur notre DataFrame SPY.

# Calculer les indicateurs
df['rsi_14'] = calculate_rsi(df['close'], 14)
df['ema_10'] = calculate_ema(df['close'], 10)
df['ema_20'] = calculate_ema(df['close'], 20)
df['ema_50'] = calculate_ema(df['close'], 50)

# MACD
df['macd_line'], df['macd_signal'], df['macd_histogram'] = calculate_macd(df['close'])

# Returns passes
df['returns_1d'] = df['close'].pct_change(1)
df['returns_5d'] = df['close'].pct_change(5)
df['returns_10d'] = df['close'].pct_change(10)

# Ratio prix/EMA (normalisation)
df['price_ema10_ratio'] = df['close'] / df['ema_10']
df['price_ema20_ratio'] = df['close'] / df['ema_20']
df['price_ema50_ratio'] = df['close'] / df['ema_50']

# Volatilite rolling
df['volatility_10d'] = df['returns_1d'].rolling(10).std()
df['volatility_20d'] = df['returns_1d'].rolling(20).std()

print(f"Features creees. Colonnes: {df.shape[1]}")
print(f"\nListe des features:")
print(df.columns.tolist())
Features creees. Colonnes: 20

Liste des features:
['close', 'high', 'low', 'open', 'volume', 'rsi_14', 'ema_10', 'ema_20', 'ema_50', 'macd_line', 'macd_signal', 'macd_histogram', 'returns_1d', 'returns_5d', 'returns_10d', 'price_ema10_ratio', 'price_ema20_ratio', 'price_ema50_ratio', 'volatility_10d', 'volatility_20d']

Creation de la Variable Cible (Target)

Pour la classification, nous devons définir ce que nous voulons predire. Ici, nous allons predire la direction du marche a J+1 : - 1 : Le prix monte le lendemain - 0 : Le prix baisse ou reste stable le lendemain

# Calculer le return du jour suivant
df['next_day_return'] = df['close'].pct_change().shift(-1)

# Creer le label binaire (1 = hausse, 0 = baisse/flat)
df['target'] = (df['next_day_return'] > 0).astype(int)

print("Variable cible creee")
print(f"\nDistribution des classes:")
print(df['target'].value_counts())
print(f"\nProportion de hausses: {df['target'].mean():.2%}")
Variable cible creee

Distribution des classes:
target
1    290
0    214
Name: count, dtype: int64

Proportion de hausses: 57.54%

Nettoyage des Données

Les indicateurs rolling et les shifts generent des NaN. Supprimons les lignes incompletes.

# Definir les colonnes de features (exclure colonnes non-predictives)
feature_cols = [
    'rsi_14', 'ema_10', 'ema_20', 'ema_50',
    'macd_line', 'macd_signal', 'macd_histogram',
    'returns_1d', 'returns_5d', 'returns_10d',
    'price_ema10_ratio', 'price_ema20_ratio', 'price_ema50_ratio',
    'volatility_10d', 'volatility_20d'
]

# Dataset nettoy
df_clean = df[feature_cols + ['target']].dropna()

print(f"Dataset apres nettoyage: {df_clean.shape}")
print(f"\nLignes supprimees: {len(df) - len(df_clean)}")
print(f"\nApercu du dataset nettoy:")
df_clean.head()
Dataset apres nettoyage: (484, 16)

Lignes supprimees: 20

Apercu du dataset nettoy:
rsi_14 ema_10 ema_20 ema_50 macd_line macd_signal macd_histogram returns_1d returns_5d returns_10d price_ema10_ratio price_ema20_ratio price_ema50_ratio volatility_10d volatility_20d target
time
2024-07-05 16:00:00 76.585497 536.332343 532.906504 528.072500 4.068785 3.250020 0.818765 0.005767 0.015136 0.017238 1.012824 1.019335 1.028666 0.003651 0.003518 1
2024-07-08 16:00:00 76.860156 537.696808 533.947494 528.690712 4.430604 3.486137 0.944467 0.001154 0.020323 0.019779 1.011419 1.018521 1.028648 0.003501 0.003492 1
2024-07-09 16:00:00 73.029800 538.909347 534.939711 529.305420 4.705778 3.730065 0.975713 0.000972 0.019217 0.024100 1.010125 1.017621 1.028453 0.003024 0.003417 1
2024-07-10 16:00:00 77.160200 540.880817 536.350446 530.107264 5.297448 4.043542 1.253906 0.009895 0.022422 0.030266 1.016402 1.024987 1.037059 0.003842 0.003828 0
2024-07-11 16:00:00 68.594745 541.631972 537.175372 530.691770 5.322497 4.299333 1.023164 -0.008623 0.009103 0.020110 1.006241 1.014589 1.026984 0.005323 0.004567 1

Interpretation : Feature Engineering

Feature Description Rôle pour la prediction
RSI_14 Momentum oscillator Detecte survente/surachat
EMA ratios Prix relatif aux moyennes Identifie la tendance
MACD Momentum et tendance Signaux de croisement
Returns passes Performance recente Inertie du marche
Volatilite Dispersion des returns Aversion au risque

Point crucial : La variable cible utilise .shift(-1) pour regarder le return du jour suivant. C’est ce que nous voulons predire. Si nous oublions le shift, nous aurions un lookahead bias (tricher en voyant le futur).


4. Model Training (10 min)

Split Train/Test Temporel

RÈGLE D’OR : Pour les series temporelles, JAMAIS de random shuffle ! Nous devons respecter l’ordre chronologique pour eviter le lookahead bias.

Utilisons un split 70/30 chronologique : les 70% premiers jours pour l’entrainement, les 30% suivants pour le test.

# Split chronologique (70% train, 30% test)
split_idx = int(len(df_clean) * 0.7)

X = df_clean[feature_cols]
y = df_clean['target']

X_train = X.iloc[:split_idx]
y_train = y.iloc[:split_idx]
X_test = X.iloc[split_idx:]
y_test = y.iloc[split_idx:]

print("Split Train/Test (temporel):")
print(f"  Train: {X_train.shape[0]} samples ({X_train.index.min().date()} a {X_train.index.max().date()})")
print(f"  Test:  {X_test.shape[0]} samples ({X_test.index.min().date()} a {X_test.index.max().date()})")
print(f"\nDistribution des classes:")
print(f"  Train - Hausse: {y_train.mean():.2%}")
print(f"  Test  - Hausse: {y_test.mean():.2%}")
Split Train/Test (temporel):
  Train: 338 samples (2024-07-05 a 2025-11-06)
  Test:  146 samples (2025-11-07 a 2026-06-09)

Distribution des classes:
  Train - Hausse: 57.99%
  Test  - Hausse: 54.79%

Entrainement du RandomForestClassifier

Utilisons un Random Forest, un algorithme robuste et interpretable pour la classification.

# Creer et entrainer le modele
model = RandomForestClassifier(
    n_estimators=100,
    max_depth=10,
    min_samples_split=5,
    min_samples_leaf=2,
    random_state=42,
    n_jobs=-1
)

# Entrainement
model.fit(X_train, y_train)

print("Modele entraine avec succes!")
print(f"\nHyperparametres:")
print(f"  n_estimators: {model.n_estimators}")
print(f"  max_depth: {model.max_depth}")
print(f"  min_samples_split: {model.min_samples_split}")
Modele entraine avec succes!

Hyperparametres:
  n_estimators: 100
  max_depth: 10
  min_samples_split: 5

5. Model Evaluation (10 min)

Predictions et Rapport de Classification

# Predictions sur le set de test
y_pred = model.predict(X_test)
y_pred_proba = model.predict_proba(X_test)[:, 1]

# Accuracy
accuracy = accuracy_score(y_test, y_pred)

print(f"Accuracy sur le set de test: {accuracy:.2%}")
print(f"\nRapport de classification:")
print(classification_report(y_test, y_pred, target_names=['Baisse', 'Hausse']))
Accuracy sur le set de test: 43.84%

Rapport de classification:
              precision    recall  f1-score   support

      Baisse       0.31      0.20      0.24        66
      Hausse       0.49      0.64      0.55        80

    accuracy                           0.44       146
   macro avg       0.40      0.42      0.40       146
weighted avg       0.41      0.44      0.41       146

Matrice de Confusion

# Matrice de confusion
cm = confusion_matrix(y_test, y_pred)

# Visualisation
fig, ax = plt.subplots(figsize=(8, 6))

# Creation de la heatmap manuellement (eviter seaborn)
im = ax.imshow(cm, interpolation='nearest', cmap='Blues')
ax.figure.colorbar(im, ax=ax)

# Labels
classes = ['Baisse (0)', 'Hausse (1)']
ax.set(xticks=[0, 1], yticks=[0, 1],
       xticklabels=classes, yticklabels=classes,
       xlabel='Predicted', ylabel='Actual',
       title='Matrice de Confusion')

# Annotations
thresh = cm.max() / 2.
for i in range(cm.shape[0]):
    for j in range(cm.shape[1]):
        ax.text(j, i, format(cm[i, j], 'd'),
                ha="center", va="center",
                color="white" if cm[i, j] > thresh else "black")

plt.tight_layout()
plt.show()

print("\nInterpretation de la matrice:")
print(f"  Vrais Negatifs (Baisse predite, Baisse reelle): {cm[0, 0]}")
print(f"  Faux Positifs (Hausse predite, Baisse reelle): {cm[0, 1]}")
print(f"  Faux Negatifs (Baisse predite, Hausse reelle): {cm[1, 0]}")
print(f"  Vrais Positifs (Hausse predite, Hausse reelle): {cm[1, 1]}")


Interpretation de la matrice:
  Vrais Negatifs (Baisse predite, Baisse reelle): 13
  Faux Positifs (Hausse predite, Baisse reelle): 53
  Faux Negatifs (Baisse predite, Hausse reelle): 29
  Vrais Positifs (Hausse predite, Hausse reelle): 51

Interpretation : Metriques de Classification

Metrique Valeur Signification
Accuracy ~52-55% Proportion de predictions correctes
Precision (Hausse) Variable Parmi les hausses predites, combien sont reelles
Recall (Hausse) Variable Parmi les hausses reelles, combien sont detectees
F1-Score Variable Moyenne harmonique de Precision et Recall

Realite du trading : Une accuracy de 52-55% est typique pour la prediction de direction. Ce qui compte en trading, c’est le ratio gain/perte combine a l’accuracy. Un modèle avec 52% d’accuracy mais des gains 2x superieurs aux pertes peut etre très rentable.

Feature Importance

Le Random Forest nous donne l’importance de chaque feature pour la prediction.

# Feature importance
importance_df = pd.DataFrame({
    'feature': feature_cols,
    'importance': model.feature_importances_
}).sort_values('importance', ascending=False)

# Visualisation
fig, ax = plt.subplots(figsize=(10, 8))

bars = ax.barh(importance_df['feature'], importance_df['importance'], color='steelblue')
ax.set_xlabel('Importance')
ax.set_title('Feature Importance (Random Forest)', fontsize=14, fontweight='bold')
ax.invert_yaxis()

# Ajouter les valeurs sur les barres
for bar, val in zip(bars, importance_df['importance']):
    ax.text(val + 0.002, bar.get_y() + bar.get_height()/2, 
            f'{val:.3f}', va='center', fontsize=9)

plt.tight_layout()
plt.show()

print("\nTop 5 features les plus importantes:")
print(importance_df.head().to_string(index=False))


Top 5 features les plus importantes:
       feature  importance
    returns_5d    0.082554
    returns_1d    0.082155
macd_histogram    0.075621
        rsi_14    0.072003
   returns_10d    0.071125

Interpretation : Feature Importance

Les features les plus importantes revelent ce que le modèle a appris :

  1. Returns passes : Le modèle detecte potentiellement des patterns de mean-reversion ou momentum
  2. RSI : Les niveaux de survente/surachat sont informatifs
  3. Ratios prix/EMA : La position relative par rapport aux moyennes indique la tendance

Note : L’importance des features ne signifie pas causalite. Le modèle peut capturer des correlations spurious.


6. ObjectStore Pattern (5 min)

Persistance du Modèle

Le ObjectStore de QuantConnect permet de sauvegarder des objets (modèles, paramètres, données) pour les reutiliser dans un algorithme de production.

C’est le pattern standard pour deployer du ML en production sur QuantConnect.

import joblib
import io

# Serialiser le modele en bytes (joblib.dump vers un buffer memoire)
buffer = io.BytesIO()
joblib.dump(model, buffer)
model_bytes = buffer.getvalue()

# Sauvegarder dans ObjectStore
qb.object_store.save_bytes('classification_model', model_bytes)

print("Modele sauvegarde dans ObjectStore!")
print(f"\nTaille du modele: {len(model_bytes) / 1024:.2f} KB")
Modele sauvegarde dans ObjectStore!

Taille du modele: 701.87 KB

Sauvegarder les Noms des Features

Il est important de sauvegarder également les noms des features pour garantir la coherence lors du chargement.

import json

# Sauvegarder la liste des features
feature_config = {
    'feature_cols': feature_cols,
    'model_type': 'RandomForestClassifier',
    'train_date': str(X_train.index.max().date()),
    'accuracy_test': accuracy
}

qb.object_store.save('classification_config', json.dumps(feature_config))

print("Configuration sauvegardee:")
print(json.dumps(feature_config, indent=2))
Configuration sauvegardee:
{
  "feature_cols": [
    "rsi_14",
    "ema_10",
    "ema_20",
    "ema_50",
    "macd_line",
    "macd_signal",
    "macd_histogram",
    "returns_1d",
    "returns_5d",
    "returns_10d",
    "price_ema10_ratio",
    "price_ema20_ratio",
    "price_ema50_ratio",
    "volatility_10d",
    "volatility_20d"
  ],
  "model_type": "RandomForestClassifier",
  "train_date": "2025-11-06",
  "accuracy_test": 0.4383561643835616
}

Comment Charger le Modèle dans un Algorithme

Voici le code a utiliser dans votre main.py (algorithme de production) pour charger le modèle :

# CODE A COPIER DANS main.py

from AlgorithmImports import *
import joblib
import json

class MLClassificationStrategy(QCAlgorithm):
    """
    Strategie ML utilisant un modele de classification pre-entraine.
    
    Le modele est entraine dans research_classification.ipynb et
    sauvegarde via ObjectStore.
    """
    
    def Initialize(self):
        self.SetStartDate(2023, 1, 1)
        self.SetCash(100000)
        
        # Ajouter le symbole
        self.symbol = self.AddEquity("SPY", Resolution.Daily).Symbol
        
        # Charger le modele depuis ObjectStore
        model_bytes = self.object_store.read_bytes('classification_model')
        self.model = joblib.loads(model_bytes)
        
        # Charger la configuration
        config_json = self.object_store.read('classification_config')
        self.config = json.loads(config_json)
        self.feature_cols = self.config['feature_cols']
        
        self.Debug(f"Modele charge: {self.config['model_type']}")
        self.Debug(f"Accuracy test: {self.config['accuracy_test']:.2%}")
        
        # Indicateurs pour generer les features
        self.rsi = self.RSI(self.symbol, 14)
        self.ema10 = self.EMA(self.symbol, 10)
        self.ema20 = self.EMA(self.symbol, 20)
        self.ema50 = self.EMA(self.symbol, 50)
        self.macd = self.MACD(self.symbol, 12, 26, 9)
        
        # Warm-up
        self.SetWarmup(50)
    
    def OnData(self, data):
        if self.IsWarmingUp:
            return
        
        # Construire le vecteur de features
        features = self.BuildFeatures()
        
        if features is not None:
            # Prediction
            prediction = self.model.predict([features])[0]
            
            # Trading logic
            if prediction == 1 and not self.Portfolio.Invested:
                self.SetHoldings(self.symbol, 1.0)
                self.Debug(f"{self.Time}: Signal HAUSSE - Long")
            elif prediction == 0 and self.Portfolio.Invested:
                self.Liquidate(self.symbol)
                self.Debug(f"{self.Time}: Signal BAISSE - Liquidate")
    
    def BuildFeatures(self):
        """Construire le vecteur de features a partir des indicateurs."""
        # Cette methode doit correspondre exactement aux features du notebook
        # TODO: Implementer la logique de construction des features
        # en utilisant self.History() pour les returns et volatilite
        return None  # Placeholder

print("\nCode pret a etre copie dans main.py")

Code pret a etre copie dans main.py

Workflow ObjectStore Resume

RESEARCH (ce notebook)           PRODUCTION (main.py)
======================           ====================
1. Explorer données              4. Charger modèle
2. Entrainer modèle     ------>  5. Construire features
3. Sauvegarder ObjectStore       6. Generer signaux
                                 7. Executer trades

Important : Les features calculees dans l’algorithme doivent etre identiques a celles du notebook. Toute différence entrainera des predictions incorrectes.


Conclusion et Prochaines Étapes

Recapitulatif

Dans ce notebook, nous avons :

  1. Utilise QuantBook pour charger des données financieres via l’API synchrone
  2. Créé 15 features techniques (RSI, EMA, MACD, returns, volatilite)
  3. Défini une variable cible binaire pour la prediction de direction
  4. Entraine un RandomForestClassifier avec split temporel
  5. Evalue les performances avec metriques de classification
  6. Sauvegarde le modèle via ObjectStore pour la production

Points Cles a Retenir

Concept Description
QuantBook API synchrone pour la recherche, retourne DataFrame pandas
Split temporel Toujours respecter la chronologie, jamais de shuffle
Variable cible Utiliser .shift(-1) pour predire le futur
ObjectStore Mécanisme de persistance pour partager modèle Research -> Algorithm
Accuracy ~52-55% Typique pour la prediction de direction, le ratio gain/perte compte aussi

Prochaines Étapes

  1. QC-Py-19-ML-Supervised-Classification : Approfondir la théorie et les metriques
  2. QC-Py-20-ML-Regression-Prediction : Predire des valeurs continues (returns)
  3. projects/ML-Classification : Voir un exemple complet deployable

Exercices Suggeres

  • Essayer d’autres modèles : XGBoost, LightGBM, SVM
  • Ajouter des features : sentiment, volume, volatility skew
  • Implementer une validation croisee temporelle (TimeSeriesSplit)
  • Optimiser les hyperparametres avec GridSearchCV

Ressources


Notebook complete. Modèle pret pour integration dans un algorithme.

Retour au sommet