Wire futures order intents into engine

This commit is contained in:
boris
2026-04-23 20:38:36 -07:00
parent db4e385308
commit 3439b5d8d0
6 changed files with 214 additions and 14 deletions

View File

@@ -939,6 +939,16 @@ where
));
Ok(())
}
OrderIntent::Futures { intent } => {
report.diagnostics.push(format!(
"engine_futures_intent_skipped symbol={} direction={} effect={} reason={}",
intent.symbol,
intent.direction.as_str(),
intent.effect.as_str(),
intent.reason
));
Ok(())
}
}
}

View File

@@ -12,7 +12,7 @@ use crate::events::{
AccountEvent, FillEvent, OrderEvent, OrderSide, OrderStatus, PositionEvent, ProcessEvent,
ProcessEventKind,
};
use crate::futures::FuturesAccountState;
use crate::futures::{FuturesAccountState, FuturesExecutionReport};
use crate::metrics::{BacktestMetrics, compute_backtest_metrics};
use crate::portfolio::{CashReceivable, HoldingSummary, PortfolioState};
use crate::rules::EquityRuleHooks;
@@ -103,6 +103,7 @@ pub struct BacktestEngine<S, C, R> {
dynamic_universe: Option<BTreeSet<String>>,
subscriptions: BTreeSet<String>,
futures_account: Option<FuturesAccountState>,
next_futures_order_id: u64,
}
impl<S, C, R> BacktestEngine<S, C, R> {
@@ -122,6 +123,7 @@ impl<S, C, R> BacktestEngine<S, C, R> {
dynamic_universe: None,
subscriptions: BTreeSet::new(),
futures_account: None,
next_futures_order_id: 1,
}
}
@@ -454,6 +456,37 @@ where
},
)?;
}
crate::strategy::OrderIntent::Futures { intent } => {
let order_id = self.next_futures_order_id;
self.next_futures_order_id += 1;
let report = if let Some(account) = self.futures_account.as_mut() {
account.execute_order(execution_date, Some(order_id), intent)
} else {
let mut report = FuturesExecutionReport::default();
let side = intent.side();
report.order_events.push(OrderEvent {
date: execution_date,
order_id: Some(order_id),
symbol: intent.symbol,
side,
requested_quantity: intent.quantity,
filled_quantity: 0,
status: OrderStatus::Rejected,
reason: format!(
"{}: futures account is not enabled direction={} effect={}",
intent.reason,
intent.direction.as_str(),
intent.effect.as_str()
),
});
report
};
decision.diagnostics.push(format!(
"futures_order order_id={order_id} events={}",
report.order_events.len()
));
merge_futures_report(directive_report, report);
}
other => retained.push(other),
}
}
@@ -2246,6 +2279,14 @@ fn merge_broker_report(target: &mut BrokerExecutionReport, incoming: BrokerExecu
target.diagnostics.extend(incoming.diagnostics);
}
fn merge_futures_report(target: &mut BrokerExecutionReport, incoming: FuturesExecutionReport) {
target.order_events.extend(incoming.order_events);
target.fill_events.extend(incoming.fill_events);
target.position_events.extend(incoming.position_events);
target.account_events.extend(incoming.account_events);
target.diagnostics.extend(incoming.diagnostics);
}
mod date_format {
use chrono::NaiveDate;
use serde::Serializer;

View File

@@ -121,6 +121,14 @@ impl FuturesOrderIntent {
reason: reason.into(),
}
}
pub fn side(&self) -> OrderSide {
if self.effect == FuturesPositionEffect::Open {
self.direction.open_side()
} else {
self.direction.close_side()
}
}
}
#[derive(Debug, Clone, Default)]
@@ -505,11 +513,7 @@ impl FuturesAccountState {
intent: FuturesOrderIntent,
) -> FuturesExecutionReport {
let mut report = FuturesExecutionReport::default();
let side = if intent.effect == FuturesPositionEffect::Open {
intent.direction.open_side()
} else {
intent.direction.close_side()
};
let side = intent.side();
if intent.quantity == 0 || !intent.price.is_finite() || intent.price <= 0.0 {
report.order_events.push(OrderEvent {

View File

@@ -10,7 +10,7 @@ use crate::cost::ChinaAShareCostModel;
use crate::data::{DailyMarketSnapshot, DataSet, IntradayExecutionQuote, PriceBar, PriceField};
use crate::engine::BacktestError;
use crate::events::{FillEvent, OrderEvent, OrderSide, OrderStatus, ProcessEvent};
use crate::futures::FuturesAccountState;
use crate::futures::{FuturesAccountState, FuturesOrderIntent};
use crate::instrument::Instrument;
use crate::portfolio::PortfolioState;
use crate::scheduler::ScheduleRule;
@@ -902,6 +902,9 @@ pub enum OrderIntent {
rate: f64,
reason: String,
},
Futures {
intent: FuturesOrderIntent,
},
}
#[derive(Debug, Clone)]