Mise en route
Ce que fait AQE
Section intitulée « Ce que fait AQE »AlgoQuant Engine est le runtime qui exécute votre stratégie, gère les insights, communique avec les courtiers et datafeeds, et produit soit :
- des artefacts de backtest sur disque
- des données de session live pour AlgoQuant Studio
- ou les deux, selon votre mode d’exécution
Au centre de ce flux se trouve le cycle de vie de stratégie :
on_startuniverseiniton_bargenerate_insightsinsight_pipelineon_teardown
pub trait Strategy { fn on_start(&mut self, ctx: &mut dyn StrategyContext); fn init(&mut self, ctx: &mut dyn StrategyContext, asset: &Asset); fn universe(&self, ctx: &mut dyn StrategyContext) -> HashSet<String>; fn on_bar(&mut self, ctx: &mut dyn StrategyContext, symbol: &str, bar: &BarData); fn generate_insights(&mut self, ctx: &mut dyn StrategyContext, symbol: &str); fn insight_pipeline(&mut self, ctx: &mut dyn StrategyContext, insight: &Insight); fn on_teardown(&mut self, ctx: &mut dyn StrategyContext);}Une stratégie vide
Section intitulée « Une stratégie vide »Commencez avec la plus petite surface de stratégie possible. Elle donne les hooks runtime sans introduire encore de modèles alpha ni de pipes.
use aq_engine::core::broker::data_feeds::yahoo::YahooFinanceDataFeed;use aq_engine::core::broker::paper_broker::PaperBroker;use aq_engine::core::broker::UnifiedBroker;use aq_engine::core::broker::types::{Asset, BarData};use aq_engine::core::insight::Insight;use aq_engine::core::strategy::{Strategy, StrategyContext, StrategyState};use aq_engine::core::utils::timeframe::{TimeFrame, TimeFrameUnit};use chrono::{Duration, Utc};use std::collections::HashSet;
pub struct BlankStrategy;
impl Strategy for BlankStrategy { fn on_start(&mut self, ctx: &mut dyn StrategyContext) {}
fn init(&mut self, ctx: &mut dyn StrategyContext, asset: &Asset) {}
fn universe(&self, ctx: &mut dyn StrategyContext) -> HashSet<String> { HashSet::from([String::from("AAPL")]) }
fn on_bar(&mut self, ctx: &mut dyn StrategyContext, symbol: &str, bar: &BarData) {}
fn generate_insights(&mut self, ctx: &mut dyn StrategyContext, symbol: &str) {}
fn insight_pipeline(&mut self, ctx: &mut dyn StrategyContext, insight: &Insight) {}
fn on_teardown(&mut self, ctx: &mut dyn StrategyContext) {}}
let execution = PaperBroker::new(100_000.0);let data = YahooFinanceDataFeed::new();let broker = UnifiedBroker::new_backtest(execution, data);
let timeframe = TimeFrame::new(1, TimeFrameUnit::Day);let strategy = BlankStrategy;
let mut state = StrategyState::new( "blank-strategy".to_string(), "Blank Strategy".to_string(), strategy, broker, timeframe.clone(),);
let start = Utc::now() - Duration::days(30);let end = Utc::now();
let results = state.run_backtest(start, end, timeframe).await?;results.print_metrics();Ce bloc de départ montre le plus petit chemin complet : définir une stratégie, connecter un paper broker et un datafeed, exécuter le backtest et inspecter les métriques produites. Le flux de stockage du backtest est expliqué plus loin dans cette page.
Ce qu’est un insight
Section intitulée « Ce qu’est un insight »Un insight est l’objet d’intention de trading d’AQE. Il représente un trade potentiel ou actif et porte les informations nécessaires pour le gérer dans le runtime :
- side
- symbole
- confiance
- timeframe
- type d’ordre et détails d’entrée
- niveaux de take-profit et stop-loss
- écart de trailing stop
- informations de fill et de clôture
- historique d’état
pub struct Insight { pub insight_id: Uuid, pub state: InsightState, pub order_id: Option<String>, pub side: OrderSide, pub symbol: String, pub quantity: Option<f64>, pub order_type: OrderType, pub order_class: OrderClass, pub limit_price: Option<f64>, pub stop_price: Option<f64>, pub take_profit_levels: Option<Vec<f64>>, pub stop_loss_levels: Option<Vec<f64>>, pub trailing_stop_price: Option<f64>, pub confidence: u8, pub timeframe: TimeFrame, pub period_unfilled: Option<u32>, pub period_till_tp: Option<u32>, pub filled_price: Option<f64>, pub close_price: Option<f64>, pub state_history: Vec<(DateTime<Utc>, InsightState, Option<String>)>,}Vous créez généralement un insight dans un modèle alpha ou dans generate_insights(), puis vous laissez le pipeline d’insights le dimensionner, ajouter les contrôles de risque et le soumettre.
Les insights peuvent aussi participer à une structure parent/enfant. C’est utile quand un insight principal génère des intentions de trade de suivi qui doivent rester liées à la position ou au workflow parent.
Fonctionnement du moteur
Section intitulée « Fonctionnement du moteur »on_start
Section intitulée « on_start »Utilisez on_start pour enregistrer la configuration runtime partagée :
- indicateurs
- alphas
- pipes
- paramètres de risque
- barres de warm-up
universe
Section intitulée « universe »universe() retourne les symboles tradés par la stratégie. AQE utilise ces symboles pour charger les métadonnées Asset depuis la stack data/broker sélectionnée.
init() s’exécute une fois par actif après le chargement de l’univers. Utilisez-le pour l’initialisation par actif, par exemple :
- variables par symbole
- état d’indicateur propre au symbole
- configuration consciente de l’actif
on_bar() est appelé à chaque nouvelle barre pour un symbole. C’est ici que vous mettez à jour l’état de stratégie depuis les dernières données de marché.
generate_insights
Section intitulée « generate_insights »Après on_bar(), AQE appelle generate_insights(). C’est ici que vous créez de nouveaux insights et les ajoutez au runtime.
insight_pipeline
Section intitulée « insight_pipeline »Après le traitement des barres, AQE exécute le pipeline d’insights. Les pipes peuvent dimensionner, valider, soumettre, rejeter, annuler ou clôturer les insights selon leur état courant.
Générer un insight
Section intitulée « Générer un insight »Voici le pattern utilisateur le plus simple : créer un insight, définir les champs clés et l’ajouter au contexte.
use aq_engine::core::broker::types::OrderSide;use aq_engine::core::insight::{types::StrategyType, Insight};
fn generate_insights(&mut self, ctx: &mut dyn StrategyContext, symbol: &str) { let mut insight = Insight::new( OrderSide::Buy, symbol.to_string(), StrategyType::Testing, ctx.timeframe().clone(), 80, None, );
insight .set_limit_price(Some(200.0)) .set_take_profit_levels(Some(vec![206.0])) .set_stop_loss(Some(197.5)) .set_period_unfilled(Some(5)) .set_period_till_tp(Some(12));
ctx.add_insight(insight);}Assembler avec des modèles alpha
Section intitulée « Assembler avec des modèles alpha »Les modèles alpha permettent de déplacer la génération de signaux hors du corps principal de la stratégie. AQE appelle leur cycle de vie dans le même runtime :
start()init(asset)generate_insights(symbol)
pub trait AlphaModel { fn version(&self) -> &str; fn start(&mut self, ctx: &mut dyn StrategyContext); fn init(&mut self, ctx: &mut dyn StrategyContext, asset: &Asset); fn generate_insights(&mut self, ctx: &mut dyn StrategyContext, symbol: &str) -> AlphaResult;}Un exemple réel est EmaPriceCrossover, qui :
- enregistre ATR et EMA dans
start() - lit l’historique et les métadonnées de l’actif
- construit un
Insight - le retourne via
AlphaResult
Assembler avec des pipes
Section intitulée « Assembler avec des pipes »Les insight pipes s’exécutent après la création des insights. Elles sont utiles pour :
- la conversion d’entrée marché
- le sizing dynamique de quantité
- la gestion stop-loss et take-profit
- les fenêtres de trading
- la gestion de l’expiration
- la soumission
pub trait InsightPipe { fn version(&self) -> &str; fn run(&mut self, ctx: &mut dyn StrategyContext, insight: &mut Insight) -> InsightPipeResult;}Une composition typique pour un nouvel insight est :
- créer l’insight
- définir l’intention d’entrée
- dimensionner la quantité
- appliquer stop loss / take profit
- valider le reward-to-risk ou les règles de session
- soumettre l’insight
Insights enfants
Section intitulée « Insights enfants »AQE prend en charge les relations parent/enfant directement sur le modèle d’insight :
parent_idchildren
Cela permet de construire des workflows où un insight en génère un autre lié sans perdre la lignée dans l’historique d’état et l’inspection.
pub fn add_child_insight( &mut self, mut child_insight: Insight, _ctx: &mut dyn StrategyContext,) -> &mut Self { child_insight.strategy_type = StrategyType::Custom(format!("{}-CHILD", self.strategy_type.to_string())); child_insight.parent_id = Some(self.insight_id); if child_insight.quantity.is_none() { child_insight.quantity = self.quantity; }
let child_id = child_insight.insight_id; self.children.push(child_insight);
self.update_state( self.state.clone(), Some(format!("Added child insight: {:?}", child_id)), ); self}En pratique :
- l’insight parent est créé et géré normalement
- le parent peut attacher des insights enfants pendant la logique de stratégie
- AQE met ces enfants en file pour les soumettre au bon moment dans la boucle runtime
- les lignes parent et enfant restent liées par
parent_id
C’est particulièrement utile pour :
- logique de suivi multi-jambes
- entrées échelonnées
- intentions de trade dérivées depuis un signal déjà actif
Sélectionner un courtier et un datafeed
Section intitulée « Sélectionner un courtier et un datafeed »AQE expose actuellement :
- courtier d’exécution :
PaperBroker
- datafeed :
YahooFinanceDataFeed
Ils sont combinés via UnifiedBroker.
let execution = PaperBroker::new(100_000.0);let data = YahooFinanceDataFeed::new();let broker = UnifiedBroker::new_backtest(execution, data);En mode live, le même runtime côté stratégie est utilisé, mais le moteur passe par run_live(...) au lieu de run_backtest(...).
Exécuter en mode backtest
Section intitulée « Exécuter en mode backtest »Le runner de backtest suit ce flux :
// 1. strategy.on_start(ctx)// 2. load_universe() -> strategy.init per asset// 3. alpha.start() per alpha// 4. alpha.init(asset) per alpha per asset// 5. broker.load_backtest_data()// 6. loop: broker.step() -> _on_bar() -> run_insight_pipeline()// 7. strategy.on_teardown(ctx)// 8. return BacktestResultsLes exécutions générées enregistrent les artefacts sur disque sous :
backtests/<run_id>/backtest.db
AQE écrit l’artefact SQLite avec :
pub async fn write_backtest_db( dir_path: &Path, results: &BacktestResults, state: &BacktestState,) -> Result<(), String> { std::fs::create_dir_all(dir_path).map_err(to_storage_err)?; let conn = connect_database(dir_path).await?; init_schema(&conn).await?; insert_trade_log(&conn, &results.trade_log).await?; insert_round_trips(&conn, &round_trips).await?; insert_trade_log_rows(&conn, &round_trips, &results.trade_log).await?; insert_account_history(&conn, &results.account_history).await?; insert_insights(&conn, &insights).await?; insert_bars(&conn, &state.historical_bars).await?; Ok(())}Vous pouvez inspecter ces résultats dans :
- AlgoQuant Studio, via les vues Backtest Results
- n’importe quel lecteur SQLite, si vous voulez inspecter
backtest.dbdirectement
Exécuter en live
Section intitulée « Exécuter en live »Le mode live utilise la même structure stratégie/runtime, mais s’abonne aux données live et aux mises à jour de trade.
Vous pouvez exécuter AQE en live :
- avec AQS, en passant l’authentification et en activant la synchronisation live
- sans AQS, en exécutant
run_live(None)
if let Err(e) = state.run_live(auth).await { eprintln!("Live execution failed: {:?}", e); std::process::exit(1);}Quand l’authentification est fournie, AQE écrit l’état live dans des tables scoped AQS comme :
insightsstrategy_accountsstrategy_equity_pointsstrategy_live_metricsstrategy_events
Quand l’authentification est omise, AQE peut toujours fonctionner en live localement sans synchroniser dans AQS.
Lire ensuite
Section intitulée « Lire ensuite »- Insights pour le cycle de vie complet et le modèle d’état.
- Courtiers et flux de données pour les intégrations actuelles.
- Modèles alpha pour les patterns de génération de signaux.
- Pipelines d’insights pour le sizing, la validation et la gestion des trades.
Nous utilisons des cookies et du stockage essentiels pour la connexion, la sécurité du compte, les préférences de thème, cet avis et les métriques internes PostHog nécessaires sur l’utilisation, la qualité de session et la fiabilité. Nous n’utilisons pas de cookies publicitaires.