Add Events
add_events lets an AQE strategy subscribe to extra market-data event streams in addition to the strategy’s main timeframe. The first supported event stream is EventStreamType::Bar.
The main strategy timeframe is always registered automatically from the timeframe passed to run_backtest(...) or configured for the live runtime. You only call add_events when you want additional feature timeframes such as 1m, 15m, or 1h.
Basic usage
Section titled “Basic usage”Register feature streams in on_start:
use aq_engine::core::strategy::{EventStreamType, StrategyContext};use aq_engine::core::utils::timeframe::{TimeFrame, TimeFrameUnit};
fn on_start(&mut self, ctx: &mut dyn StrategyContext) { ctx.add_events( EventStreamType::Bar, Some(TimeFrame::new(15, TimeFrameUnit::Minute)), );}AQE applies that stream to every asset in the loaded universe. If the strategy trades BTC and ETH, a 15m feature bar stream is registered for both symbols.
Calling ctx.add_events(EventStreamType::Bar, None) refers to the main timeframe and is de-duplicated with the automatic main stream.
Event options
Section titled “Event options”Use EventStreamRequest when you need options:
use aq_engine::core::strategy::{EventStreamRequest, EventStreamType, StrategyContext};use aq_engine::core::utils::timeframe::{TimeFrame, TimeFrameUnit};
fn on_start(&mut self, ctx: &mut dyn StrategyContext) { ctx.add_events_with_options( EventStreamRequest::bar(Some(TimeFrame::new(1, TimeFrameUnit::Hour))) .allow_trading(true), );}allow_trading controls strategy and alpha-model generation for that event stream:
falseis the default for feature streams. AQE updates history and callson_bar, but does not call alpha modelgenerate_insightsor strategygenerate_insightsfor that feature event.trueallows alpha modelgenerate_insightsand strategygenerate_insightsto run for that feature event.
Broker execution still follows the normal execution path. Feature bars are designed to enrich strategy context and signal generation; they should not be treated as a separate broker fill stream.
History keys
Section titled “History keys”The main timeframe keeps the base symbol as its history key:
let main_history = ctx.history().get(symbol);Feature timeframes use {symbol}:{timeframe}:
let feature_history = ctx.history().get("BTC:15m");let faster_history = ctx.history().get("BTC:1m");let hourly_history = ctx.history().get("ETH:1h");This keeps feature data separate from the main strategy history. Indicators and custom state should read from the key that matches the event or signal they are using.
Reading the current event
Section titled “Reading the current event”Use ctx.current_event() inside on_bar, alpha models, or generate_insights to inspect the event that AQE is currently processing:
fn on_bar(&mut self, ctx: &mut dyn StrategyContext, symbol: &str, _bar: &BarData) { let Some(event) = ctx.current_event() else { return; };
let history = ctx.history().get(&event.history_key);
if event.is_feature { println!( "feature bar: {} {} history={} allow_trading={}", event.symbol, event.timeframe, event.history_key, event.allow_trading, ); } else { println!("main bar: {symbol}"); }}StrategyEventContext includes:
event_typesymboltimeframehistory_keyis_featureallow_tradingtimestamp
The context remains active through the full bar-processing scope for that event: history update, indicator update, on_bar, alpha model generation, and strategy generation when the event is allowed to generate insights.
When to use feature streams
Section titled “When to use feature streams”Use feature streams when a strategy needs more than one market-data resolution:
- a daily strategy that reads
15mstructure before generating a signal; - a
1hstrategy that uses1mvolatility or liquidity filters; - a main execution timeframe with higher-timeframe confirmation.
Keep the main timeframe as the primary execution clock. Use feature streams for context unless you intentionally allow that stream to generate insights.
We use essential cookies and storage for sign-in, account security, colour theme preferences, this notice, and required PostHog internal usage, session quality, and reliability metrics. We do not use advertising cookies.
