Implémentation d'un pipeline de trading quantitatif avec Microsoft Qlib

Initialisation de l'environnement et ingestion des données

L'opérationnalisation d'une infrastructure de recherche quantitative exige une configuration rigoureuse des dépendances et le chargement standardisé des séries temporelles financières. Le framework Qlib impose un format de stockage binaire spécifique et nécessite la déclaration explicite de la région géographique ciblée avant toute interaction.

import qlib
import pandas as pd
from qlib.constant import REG_CN
from qlib.utils import exists_qlib_data, init_instance_by_config
from qlib.workflow import R
from qlib.workflow.record_temp import SignalRecord, PortAnaRecord
from qlib.utils import flatten_dict

repertoire_donnees = "~/.qlib/qlib_data/cn_data"
if not exists_qlib_data(repertoire_donnees):
    print(f"Aucune base historique détectée dans {repertoire_donnees}. Téléchargement requis.")
    # Exécution du script officiel : python scripts/get_data.py qlib_data --target_dir ~/.qlib/qlib_data/cn_data --region cn

qlib.init(provider_uri=repertoire_donnees, region=REG_CN)

Configuration du pipeline d'apprentissage automatique

La préparation des caractéristiques techniques et la définition des hyperparamètres s'orchestrent via des structures de configuration. Cette section initialise l'ensemble de facteurs Alpha158 et un modèle de régression basé sur les arbres décisionnels.

fenetre_temporelle = {
    "start_time": "2008-01-01",
    "end_time": "2020-08-01",
    "fit_start_time": "2008-01-01",
    "fit_end_time": "2014-12-31",
    "instruments": "csi300",
}

schema_experimentale = {
    "model": {
        "class": "LGBModel",
        "module_path": "qlib.contrib.model.gbdt",
        "kwargs": {
            "loss": "mse",
            "colsample_bytree": 0.8879,
            "learning_rate": 0.0421,
            "n_estimators": 100,
            "subsample": 0.9
        }
    },
    "dataset": {
        "class": "DatasetH",
        "module_path": "qlib.data.dataset",
        "kwargs": {
            "handler": {
                "class": "Alpha158",
                "module_path": "qlib.contrib.data.handler",
                "kwargs": fenetre_temporelle,
            },
            "segments": {
                "train": ("2008-01-01", "2014-12-31"),
                "valid": ("2015-01-01", "2016-12-31"),
                "test": ("2017-01-01", "2020-08-01"),
            }
        }
    }
}

L'instanciation des composants et le cycle d'entraînement sont gérés par le système de traçabilité natif, permettant le versionnage des paramètres et des artefacts produits.

def executer_entrainement(config):
    instance_modele = init_instance_by_config(config["model"])
    instance_dataset = init_instance_by_config(config["dataset"])
    
    with R.start(experiment_name="phase_apprentissage"):
        R.log_params(**flatten_dict(config))
        instance_modele.fit(instance_dataset)
        R.save_objects(modele_entraine=instance_modele)
        return R.get_recorder().id, instance_modele, instance_dataset

id_session, modele_actif, dataset_actif = executer_entrainement(schema_experimentale)

Simulation de backtesting et exécution stratégique

La validation historique repose sur la définition d'un exécuteur de simulation, d'une politique d'allocation dynamique et des contraintes de marché réalistes (frais de transaction, limites de prix, slippage).

parametres_backtest = {
    "executor": {
        "class": "SimulatorExecutor",
        "module_path": "qlib.backtest.executor",
        "kwargs": {
            "time_per_step": "day",
            "generate_portfolio_metrics": True,
        }
    },
    "strategy": {
        "class": "TopkDropoutStrategy",
        "module_path": "qlib.contrib.strategy.signal_strategy",
        "kwargs": {
            "signal": None,
            "topk": 50,
            "n_drop": 5,
        }
    },
    "backtest": {
        "start_time": "2017-01-01",
        "end_time": "2020-08-01",
        "account": 1e8,
        "benchmark": "SH000300",
        "exchange_kwargs": {
            "freq": "day",
            "limit_threshold": 0.095,
            "deal_price": "close",
            "open_cost": 0.0005,
            "close_cost": 0.0015,
            "min_cost": 5,
        }
    }
}
def lancer_simulation(modele_ref, donnees_ref, config_sim):
    config_sim["strategy"]["kwargs"]["model"] = modele_ref
    config_sim["strategy"]["kwargs"]["dataset"] = donnees_ref
    
    with R.start(experiment_name="phase_backtest"):
        recordeur = R.get_recorder()
        id_sim = recordeur.id
        
        generateur = SignalRecord(modele_ref, donnees_ref, recordeur)
        generateur.generate()
        
        analyseur = PortAnaRecord(recordeur, config_sim, "day")
        analyseur.generate()
        return id_sim

id_resultats = lancer_simulation(modele_actif, dataset_actif, parametres_backtest)

Extraction des métriques et visualisation des performances

L'exploitation des artefacts de backtesting permet de reconstruire les prédictions, les pondérations historiques et les indicateurs de risque agrégés. Les modules d'analyse calculent la corrélation croisée (IC) entre les signaux générés et les rendements observés.

from qlib.contrib.report import analysis_model, analysis_position

session_finale = R.get_recorder(recorder_id=id_resultats, experiment_name="phase_backtest")
predictions_brutes = session_finale.load_object("pred.pkl")
bilan_journalier = session_finale.load_object("portfolio_analysis/report_normal_1day.pkl")
allocations_historiques = session_finale.load_object("portfolio_analysis/positions_normal_1day.pkl")
synthese_risques = session_finale.load_object("portfolio_analysis/port_analysis_1day.pkl")

analysis_position.report_graph(bilan_journalier)
analysis_position.risk_analysis_graph(synthese_risques, bilan_journalier)

cibles = dataset_actif.prepare("test", col_set="label")
cibles.columns = ["rendement_reel"]

fusion_donnees = pd.concat([cibles, predictions_brutes], axis=1, sort=True).reindex(cibles.index)

analysis_position.score_ic_graph(fusion_donnees)
analysis_model.model_performance_graph(fusion_donnees)

Étiquettes: microsoft-qlib quantitative-finance lightgbm backtesting alpha-factors

Publié le 18 août à 16h48