Skip to content

Insights

An insight is AQE’s unit of trading intent. It starts as a candidate trade and can move through submission, execution, fills, partial closes, and final closure while preserving a state history that AQS can inspect later.

Core fields include:

  • symbol
  • side
  • confidence
  • timeframe
  • parent/child lineage
  • quantity
  • entry structure
  • take-profit and stop-loss levels
  • trailing stop gap
  • fill and close prices
  • state history
aq-engine/src/core/insight/insight.rs
pub struct Insight {
pub insight_id: Uuid,
pub parent_id: Option<Uuid>,
pub state: InsightState,
pub children: Vec<Insight>,
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 filled_price: Option<f64>,
pub close_price: Option<f64>,
pub partial_closes: Vec<PartialCloseResult>,
pub state_history: Vec<(DateTime<Utc>, InsightState, Option<String>)>,
}

AQE tracks insights through a state machine that includes:

  • New
  • Executed
  • Filled
  • Closed
  • Cancelled
  • Rejected

Typical paths look like:

  • New -> Executed -> Filled -> Closed
  • New -> Rejected
  • Executed -> Cancelled
  • Filled -> Closed

Expiry, pipe failures, broker rejections, and trade updates all feed into those transitions.

The most common user-facing pattern is:

let mut insight = Insight::new(
OrderSide::Buy,
"AAPL".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);

From there, the insight pipeline can add sizing, validations, or submission behaviour.

AQE supports child insights directly on the core insight model. A parent insight can attach one or more child insights and preserve that relationship through the runtime and the snapshot data model.

aq-engine/src/core/insight/insight.rs
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
}

That gives you two important capabilities:

  • lineage: child insights remain connected to the original parent through parent_id
  • deferred submission: AQE can queue child insights and submit them at the right time in the runtime loop

Typical use cases include:

  • staged entries
  • follow-up signals derived from a parent fill
  • multi-step trade plans that need a linked inspection trail

AQE supports two important lifecycle controls:

  • period_unfilled
    • applies while the insight is still New or Executed
    • expired insights are rejected or cancellation is requested, depending on state
  • period_till_tp
    • applies once the insight is Filled
    • expiry can trigger a close request

Those checks are enforced by the runtime, not by the UI.

Every significant change can be recorded into state_history, including:

  • state transitions
  • submission
  • broker acceptance
  • fills
  • partial closes
  • cancellation requests
  • rejections
  • expiry handling

That history is what makes the shared inspector in AQS and Backtest Results useful for review.

The insight stores the configuration you define, but the broker owns the actual execution legs:

  • take profit legs
  • stop loss legs
  • trailing stop legs

For example, a trailing stop is defined on the insight as a float gap, while the broker creates and manages the actual trailing stop leg during execution.

Insights can record partial close results over time. That matters for:

  • scale-out strategies
  • multi-target exits
  • accurate inspection in AQS and backtest review

If a strategy uses more than one take-profit level, AQE can close part of the quantity while leaving the remaining position open.

Child insights and partial closes solve different problems:

  • partial closes keep one insight open while reducing size over time
  • child insights create separate linked insights with their own lifecycle
  • aq-engine/src/core/insight/insight.rs
  • aq-engine/src/core/insight/snapshot.rs
  • aq-engine/src/core/strategy/mod.rs