Expose futures account runtime view
This commit is contained in:
@@ -12,6 +12,7 @@ use crate::events::{
|
|||||||
AccountEvent, FillEvent, OrderEvent, OrderSide, OrderStatus, PositionEvent, ProcessEvent,
|
AccountEvent, FillEvent, OrderEvent, OrderSide, OrderStatus, PositionEvent, ProcessEvent,
|
||||||
ProcessEventKind,
|
ProcessEventKind,
|
||||||
};
|
};
|
||||||
|
use crate::futures::FuturesAccountState;
|
||||||
use crate::metrics::{BacktestMetrics, compute_backtest_metrics};
|
use crate::metrics::{BacktestMetrics, compute_backtest_metrics};
|
||||||
use crate::portfolio::{CashReceivable, HoldingSummary, PortfolioState};
|
use crate::portfolio::{CashReceivable, HoldingSummary, PortfolioState};
|
||||||
use crate::rules::EquityRuleHooks;
|
use crate::rules::EquityRuleHooks;
|
||||||
@@ -101,6 +102,7 @@ pub struct BacktestEngine<S, C, R> {
|
|||||||
process_event_bus: ProcessEventBus,
|
process_event_bus: ProcessEventBus,
|
||||||
dynamic_universe: Option<BTreeSet<String>>,
|
dynamic_universe: Option<BTreeSet<String>>,
|
||||||
subscriptions: BTreeSet<String>,
|
subscriptions: BTreeSet<String>,
|
||||||
|
futures_account: Option<FuturesAccountState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, C, R> BacktestEngine<S, C, R> {
|
impl<S, C, R> BacktestEngine<S, C, R> {
|
||||||
@@ -119,6 +121,7 @@ impl<S, C, R> BacktestEngine<S, C, R> {
|
|||||||
process_event_bus: ProcessEventBus::new(),
|
process_event_bus: ProcessEventBus::new(),
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: BTreeSet::new(),
|
subscriptions: BTreeSet::new(),
|
||||||
|
futures_account: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +130,23 @@ impl<S, C, R> BacktestEngine<S, C, R> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_futures_account(mut self, account: FuturesAccountState) -> Self {
|
||||||
|
self.futures_account = Some(account);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_futures_initial_cash(self, initial_cash: f64) -> Self {
|
||||||
|
self.with_futures_account(FuturesAccountState::new(initial_cash))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn futures_account(&self) -> Option<&FuturesAccountState> {
|
||||||
|
self.futures_account.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn futures_account_mut(&mut self) -> Option<&mut FuturesAccountState> {
|
||||||
|
self.futures_account.as_mut()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process_event_bus_mut(&mut self) -> &mut ProcessEventBus {
|
pub fn process_event_bus_mut(&mut self) -> &mut ProcessEventBus {
|
||||||
&mut self.process_event_bus
|
&mut self.process_event_bus
|
||||||
}
|
}
|
||||||
@@ -184,6 +204,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
portfolio,
|
portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
open_orders,
|
open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -224,6 +245,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
portfolio,
|
portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
open_orders,
|
open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -264,6 +286,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
portfolio,
|
portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
open_orders,
|
open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -333,6 +356,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&*portfolio,
|
&*portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
open_orders,
|
open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -378,6 +402,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&*portfolio,
|
&*portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
open_orders,
|
open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -411,6 +436,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&*portfolio,
|
&*portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
open_orders,
|
open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -540,6 +566,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&pre_open_orders,
|
&pre_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -554,6 +581,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
data: &self.data,
|
data: &self.data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: self.futures_account.as_ref(),
|
||||||
open_orders: &pre_open_orders,
|
open_orders: &pre_open_orders,
|
||||||
dynamic_universe: self.dynamic_universe.as_ref(),
|
dynamic_universe: self.dynamic_universe.as_ref(),
|
||||||
subscriptions: &self.subscriptions,
|
subscriptions: &self.subscriptions,
|
||||||
@@ -574,6 +602,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&pre_open_orders,
|
&pre_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -592,6 +621,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&pre_open_orders,
|
&pre_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -619,6 +649,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&pre_open_orders,
|
&pre_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -635,6 +666,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&pre_open_orders,
|
&pre_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -653,6 +685,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&pre_open_orders,
|
&pre_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -668,6 +701,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
data: &self.data,
|
data: &self.data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: self.futures_account.as_ref(),
|
||||||
open_orders: &pre_open_orders,
|
open_orders: &pre_open_orders,
|
||||||
dynamic_universe: self.dynamic_universe.as_ref(),
|
dynamic_universe: self.dynamic_universe.as_ref(),
|
||||||
subscriptions: &self.subscriptions,
|
subscriptions: &self.subscriptions,
|
||||||
@@ -688,6 +722,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&pre_open_orders,
|
&pre_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -721,6 +756,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_auction_open_orders,
|
&post_auction_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -735,6 +771,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_auction_open_orders,
|
&post_auction_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -752,6 +789,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_auction_open_orders,
|
&post_auction_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -769,6 +807,7 @@ where
|
|||||||
decision_index: decision_idx,
|
decision_index: decision_idx,
|
||||||
data: &self.data,
|
data: &self.data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: self.futures_account.as_ref(),
|
||||||
open_orders: &on_day_open_orders,
|
open_orders: &on_day_open_orders,
|
||||||
dynamic_universe: self.dynamic_universe.as_ref(),
|
dynamic_universe: self.dynamic_universe.as_ref(),
|
||||||
subscriptions: &self.subscriptions,
|
subscriptions: &self.subscriptions,
|
||||||
@@ -794,6 +833,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&on_day_open_orders,
|
&on_day_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -811,6 +851,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&on_day_open_orders,
|
&on_day_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -828,6 +869,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&bar_open_orders,
|
&bar_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -846,6 +888,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&bar_open_orders,
|
&bar_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -861,6 +904,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
data: &self.data,
|
data: &self.data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: self.futures_account.as_ref(),
|
||||||
open_orders: &bar_open_orders,
|
open_orders: &bar_open_orders,
|
||||||
dynamic_universe: self.dynamic_universe.as_ref(),
|
dynamic_universe: self.dynamic_universe.as_ref(),
|
||||||
subscriptions: &self.subscriptions,
|
subscriptions: &self.subscriptions,
|
||||||
@@ -881,6 +925,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&bar_open_orders,
|
&bar_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -912,6 +957,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_intraday_open_orders,
|
&post_intraday_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -933,6 +979,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_intraday_open_orders,
|
&post_intraday_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -949,6 +996,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_intraday_open_orders,
|
&post_intraday_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -979,6 +1027,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&tick_open_orders,
|
&tick_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -997,6 +1046,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&tick_open_orders,
|
&tick_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1013,6 +1063,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
data: &self.data,
|
data: &self.data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: self.futures_account.as_ref(),
|
||||||
open_orders: &tick_open_orders,
|
open_orders: &tick_open_orders,
|
||||||
dynamic_universe: self.dynamic_universe.as_ref(),
|
dynamic_universe: self.dynamic_universe.as_ref(),
|
||||||
subscriptions: &self.subscriptions,
|
subscriptions: &self.subscriptions,
|
||||||
@@ -1032,6 +1083,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&tick_open_orders,
|
&tick_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1067,6 +1119,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_tick_open_orders,
|
&post_tick_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1082,6 +1135,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_tick_open_orders,
|
&post_tick_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1116,6 +1170,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_trade_open_orders,
|
&post_trade_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1130,6 +1185,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
data: &self.data,
|
data: &self.data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: self.futures_account.as_ref(),
|
||||||
open_orders: &post_trade_open_orders,
|
open_orders: &post_trade_open_orders,
|
||||||
dynamic_universe: self.dynamic_universe.as_ref(),
|
dynamic_universe: self.dynamic_universe.as_ref(),
|
||||||
subscriptions: &self.subscriptions,
|
subscriptions: &self.subscriptions,
|
||||||
@@ -1150,6 +1206,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_trade_open_orders,
|
&post_trade_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1168,6 +1225,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_trade_open_orders,
|
&post_trade_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1196,6 +1254,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_trade_open_orders,
|
&post_trade_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1228,6 +1287,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_close_open_orders,
|
&post_close_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1244,6 +1304,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_close_open_orders,
|
&post_close_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1258,6 +1319,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
data: &self.data,
|
data: &self.data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: self.futures_account.as_ref(),
|
||||||
open_orders: &post_close_open_orders,
|
open_orders: &post_close_open_orders,
|
||||||
dynamic_universe: self.dynamic_universe.as_ref(),
|
dynamic_universe: self.dynamic_universe.as_ref(),
|
||||||
subscriptions: &self.subscriptions,
|
subscriptions: &self.subscriptions,
|
||||||
@@ -1278,6 +1340,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_close_open_orders,
|
&post_close_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1296,6 +1359,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_close_open_orders,
|
&post_close_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1338,6 +1402,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&portfolio,
|
&portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
&post_close_open_orders,
|
&post_close_open_orders,
|
||||||
self.dynamic_universe.as_ref(),
|
self.dynamic_universe.as_ref(),
|
||||||
&self.subscriptions,
|
&self.subscriptions,
|
||||||
@@ -1769,6 +1834,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
data: &self.data,
|
data: &self.data,
|
||||||
portfolio,
|
portfolio,
|
||||||
|
futures_account: self.futures_account.as_ref(),
|
||||||
open_orders,
|
open_orders,
|
||||||
dynamic_universe,
|
dynamic_universe,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
@@ -1808,6 +1874,7 @@ where
|
|||||||
decision_index,
|
decision_index,
|
||||||
&self.data,
|
&self.data,
|
||||||
&*portfolio,
|
&*portfolio,
|
||||||
|
self.futures_account.as_ref(),
|
||||||
open_orders,
|
open_orders,
|
||||||
dynamic_universe,
|
dynamic_universe,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
@@ -1952,6 +2019,7 @@ fn collect_scheduled_decisions<S: Strategy>(
|
|||||||
decision_index: usize,
|
decision_index: usize,
|
||||||
data: &crate::data::DataSet,
|
data: &crate::data::DataSet,
|
||||||
portfolio: &PortfolioState,
|
portfolio: &PortfolioState,
|
||||||
|
futures_account: Option<&FuturesAccountState>,
|
||||||
open_orders: &[crate::strategy::OpenOrderView],
|
open_orders: &[crate::strategy::OpenOrderView],
|
||||||
dynamic_universe: Option<&BTreeSet<String>>,
|
dynamic_universe: Option<&BTreeSet<String>>,
|
||||||
subscriptions: &BTreeSet<String>,
|
subscriptions: &BTreeSet<String>,
|
||||||
@@ -1971,6 +2039,7 @@ fn collect_scheduled_decisions<S: Strategy>(
|
|||||||
decision_index,
|
decision_index,
|
||||||
data,
|
data,
|
||||||
portfolio,
|
portfolio,
|
||||||
|
futures_account,
|
||||||
open_orders,
|
open_orders,
|
||||||
dynamic_universe,
|
dynamic_universe,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
@@ -1986,6 +2055,7 @@ fn collect_scheduled_decisions<S: Strategy>(
|
|||||||
decision_index,
|
decision_index,
|
||||||
data,
|
data,
|
||||||
portfolio,
|
portfolio,
|
||||||
|
futures_account,
|
||||||
open_orders,
|
open_orders,
|
||||||
dynamic_universe,
|
dynamic_universe,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
@@ -2005,6 +2075,7 @@ fn collect_scheduled_decisions<S: Strategy>(
|
|||||||
decision_index,
|
decision_index,
|
||||||
data,
|
data,
|
||||||
portfolio,
|
portfolio,
|
||||||
|
futures_account,
|
||||||
open_orders,
|
open_orders,
|
||||||
dynamic_universe,
|
dynamic_universe,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
@@ -2025,6 +2096,7 @@ fn publish_phase_event<S: Strategy>(
|
|||||||
decision_index: usize,
|
decision_index: usize,
|
||||||
data: &crate::data::DataSet,
|
data: &crate::data::DataSet,
|
||||||
portfolio: &PortfolioState,
|
portfolio: &PortfolioState,
|
||||||
|
futures_account: Option<&FuturesAccountState>,
|
||||||
open_orders: &[crate::strategy::OpenOrderView],
|
open_orders: &[crate::strategy::OpenOrderView],
|
||||||
dynamic_universe: Option<&BTreeSet<String>>,
|
dynamic_universe: Option<&BTreeSet<String>>,
|
||||||
subscriptions: &BTreeSet<String>,
|
subscriptions: &BTreeSet<String>,
|
||||||
@@ -2049,6 +2121,7 @@ fn publish_phase_event<S: Strategy>(
|
|||||||
decision_index,
|
decision_index,
|
||||||
data,
|
data,
|
||||||
portfolio,
|
portfolio,
|
||||||
|
futures_account,
|
||||||
open_orders,
|
open_orders,
|
||||||
dynamic_universe,
|
dynamic_universe,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
@@ -2071,6 +2144,7 @@ fn publish_process_events<S: Strategy>(
|
|||||||
decision_index: usize,
|
decision_index: usize,
|
||||||
data: &crate::data::DataSet,
|
data: &crate::data::DataSet,
|
||||||
portfolio: &PortfolioState,
|
portfolio: &PortfolioState,
|
||||||
|
futures_account: Option<&FuturesAccountState>,
|
||||||
open_orders: &[crate::strategy::OpenOrderView],
|
open_orders: &[crate::strategy::OpenOrderView],
|
||||||
dynamic_universe: Option<&BTreeSet<String>>,
|
dynamic_universe: Option<&BTreeSet<String>>,
|
||||||
subscriptions: &BTreeSet<String>,
|
subscriptions: &BTreeSet<String>,
|
||||||
@@ -2086,6 +2160,7 @@ fn publish_process_events<S: Strategy>(
|
|||||||
decision_index,
|
decision_index,
|
||||||
data,
|
data,
|
||||||
portfolio,
|
portfolio,
|
||||||
|
futures_account,
|
||||||
open_orders,
|
open_orders,
|
||||||
dynamic_universe,
|
dynamic_universe,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
@@ -2109,6 +2184,7 @@ fn publish_custom_process_event<S: Strategy>(
|
|||||||
decision_index: usize,
|
decision_index: usize,
|
||||||
data: &crate::data::DataSet,
|
data: &crate::data::DataSet,
|
||||||
portfolio: &PortfolioState,
|
portfolio: &PortfolioState,
|
||||||
|
futures_account: Option<&FuturesAccountState>,
|
||||||
open_orders: &[crate::strategy::OpenOrderView],
|
open_orders: &[crate::strategy::OpenOrderView],
|
||||||
dynamic_universe: Option<&BTreeSet<String>>,
|
dynamic_universe: Option<&BTreeSet<String>>,
|
||||||
subscriptions: &BTreeSet<String>,
|
subscriptions: &BTreeSet<String>,
|
||||||
@@ -2123,6 +2199,7 @@ fn publish_custom_process_event<S: Strategy>(
|
|||||||
decision_index,
|
decision_index,
|
||||||
data,
|
data,
|
||||||
portfolio,
|
portfolio,
|
||||||
|
futures_account,
|
||||||
open_orders,
|
open_orders,
|
||||||
dynamic_universe,
|
dynamic_universe,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
|
|||||||
@@ -353,6 +353,7 @@ impl FuturesPosition {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FuturesAccountState {
|
pub struct FuturesAccountState {
|
||||||
|
starting_cash: f64,
|
||||||
total_cash: f64,
|
total_cash: f64,
|
||||||
frozen_cash: f64,
|
frozen_cash: f64,
|
||||||
positions: BTreeMap<(String, FuturesDirection), FuturesPosition>,
|
positions: BTreeMap<(String, FuturesDirection), FuturesPosition>,
|
||||||
@@ -361,12 +362,17 @@ pub struct FuturesAccountState {
|
|||||||
impl FuturesAccountState {
|
impl FuturesAccountState {
|
||||||
pub fn new(total_cash: f64) -> Self {
|
pub fn new(total_cash: f64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
starting_cash: total_cash,
|
||||||
total_cash,
|
total_cash,
|
||||||
frozen_cash: 0.0,
|
frozen_cash: 0.0,
|
||||||
positions: BTreeMap::new(),
|
positions: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn starting_cash(&self) -> f64 {
|
||||||
|
self.starting_cash
|
||||||
|
}
|
||||||
|
|
||||||
pub fn total_cash(&self) -> f64 {
|
pub fn total_cash(&self) -> f64 {
|
||||||
self.total_cash
|
self.total_cash
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4072,6 +4072,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -4231,6 +4232,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -4349,6 +4351,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -4472,6 +4475,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -4578,6 +4582,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -4679,6 +4684,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -4798,6 +4804,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -4920,6 +4927,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -5047,6 +5055,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &open_orders,
|
open_orders: &open_orders,
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -5184,6 +5193,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &open_orders,
|
open_orders: &open_orders,
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -5293,6 +5303,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -5430,6 +5441,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -5548,6 +5560,7 @@ mod tests {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crate::cost::ChinaAShareCostModel;
|
|||||||
use crate::data::{DailyMarketSnapshot, DataSet, IntradayExecutionQuote, PriceBar, PriceField};
|
use crate::data::{DailyMarketSnapshot, DataSet, IntradayExecutionQuote, PriceBar, PriceField};
|
||||||
use crate::engine::BacktestError;
|
use crate::engine::BacktestError;
|
||||||
use crate::events::{FillEvent, OrderEvent, OrderSide, OrderStatus, ProcessEvent};
|
use crate::events::{FillEvent, OrderEvent, OrderSide, OrderStatus, ProcessEvent};
|
||||||
|
use crate::futures::FuturesAccountState;
|
||||||
use crate::instrument::Instrument;
|
use crate::instrument::Instrument;
|
||||||
use crate::portfolio::PortfolioState;
|
use crate::portfolio::PortfolioState;
|
||||||
use crate::scheduler::ScheduleRule;
|
use crate::scheduler::ScheduleRule;
|
||||||
@@ -133,6 +134,7 @@ pub struct StrategyContext<'a> {
|
|||||||
pub decision_index: usize,
|
pub decision_index: usize,
|
||||||
pub data: &'a DataSet,
|
pub data: &'a DataSet,
|
||||||
pub portfolio: &'a PortfolioState,
|
pub portfolio: &'a PortfolioState,
|
||||||
|
pub futures_account: Option<&'a FuturesAccountState>,
|
||||||
pub open_orders: &'a [OpenOrderView],
|
pub open_orders: &'a [OpenOrderView],
|
||||||
pub dynamic_universe: Option<&'a BTreeSet<String>>,
|
pub dynamic_universe: Option<&'a BTreeSet<String>>,
|
||||||
pub subscriptions: &'a BTreeSet<String>,
|
pub subscriptions: &'a BTreeSet<String>,
|
||||||
@@ -393,19 +395,55 @@ impl StrategyContext<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn future_account(&self) -> Option<PortfolioRuntimeView> {
|
pub fn future_account(&self) -> Option<PortfolioRuntimeView> {
|
||||||
None
|
self.futures_account.map(|account| {
|
||||||
|
let starting_cash = account.starting_cash();
|
||||||
|
let total_value = account.total_value();
|
||||||
|
let daily_pnl = account.daily_pnl();
|
||||||
|
let static_base = total_value - daily_pnl;
|
||||||
|
let unit_net_value = safe_ratio(total_value, starting_cash);
|
||||||
|
let static_unit_net_value = safe_ratio(static_base, starting_cash);
|
||||||
|
PortfolioRuntimeView {
|
||||||
|
account_type: "FUTURE",
|
||||||
|
starting_cash,
|
||||||
|
units: 1.0,
|
||||||
|
cash: account.cash(),
|
||||||
|
available_cash: account.cash(),
|
||||||
|
frozen_cash: account.frozen_cash(),
|
||||||
|
market_value: account.market_value(),
|
||||||
|
total_value,
|
||||||
|
portfolio_value: total_value,
|
||||||
|
total_equity: total_value,
|
||||||
|
unit_net_value,
|
||||||
|
static_unit_net_value,
|
||||||
|
daily_pnl,
|
||||||
|
daily_returns: safe_ratio(daily_pnl, static_base),
|
||||||
|
total_returns: safe_ratio(total_value - starting_cash, starting_cash),
|
||||||
|
transaction_cost: account.transaction_cost(),
|
||||||
|
trading_pnl: account.trading_pnl(),
|
||||||
|
position_pnl: account.position_pnl(),
|
||||||
|
cash_liabilities: 0.0,
|
||||||
|
management_fee_rate: 0.0,
|
||||||
|
management_fees: 0.0,
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn account_by_type(&self, account_type: &str) -> Option<PortfolioRuntimeView> {
|
pub fn account_by_type(&self, account_type: &str) -> Option<PortfolioRuntimeView> {
|
||||||
if account_type.eq_ignore_ascii_case("STOCK") {
|
if account_type.eq_ignore_ascii_case("STOCK") {
|
||||||
Some(self.stock_account())
|
Some(self.stock_account())
|
||||||
|
} else if account_type.eq_ignore_ascii_case("FUTURE") {
|
||||||
|
self.future_account()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accounts(&self) -> BTreeMap<String, PortfolioRuntimeView> {
|
pub fn accounts(&self) -> BTreeMap<String, PortfolioRuntimeView> {
|
||||||
BTreeMap::from([("STOCK".to_string(), self.stock_account())])
|
let mut accounts = BTreeMap::from([("STOCK".to_string(), self.stock_account())]);
|
||||||
|
if let Some(future_account) = self.future_account() {
|
||||||
|
accounts.insert("FUTURE".to_string(), future_account);
|
||||||
|
}
|
||||||
|
accounts
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frozen_cash(&self) -> f64 {
|
pub fn frozen_cash(&self) -> f64 {
|
||||||
@@ -673,6 +711,14 @@ impl StrategyContext<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn safe_ratio(numerator: f64, denominator: f64) -> f64 {
|
||||||
|
if denominator.abs() <= f64::EPSILON {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
numerator / denominator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct StrategyDecision {
|
pub struct StrategyDecision {
|
||||||
pub rebalance: bool,
|
pub rebalance: bool,
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ use chrono::{NaiveDate, NaiveDateTime};
|
|||||||
use fidc_core::{
|
use fidc_core::{
|
||||||
BacktestConfig, BacktestEngine, BenchmarkSnapshot, BrokerSimulator, CandidateEligibility,
|
BacktestConfig, BacktestEngine, BenchmarkSnapshot, BrokerSimulator, CandidateEligibility,
|
||||||
ChinaAShareCostModel, ChinaEquityRuleHooks, DailyFactorSnapshot, DailyMarketSnapshot, DataSet,
|
ChinaAShareCostModel, ChinaEquityRuleHooks, DailyFactorSnapshot, DailyMarketSnapshot, DataSet,
|
||||||
Instrument, IntradayExecutionQuote, OpenOrderView, OrderIntent, OrderSide, OrderStatus,
|
FuturesAccountState, FuturesContractSpec, FuturesDirection, Instrument, IntradayExecutionQuote,
|
||||||
PortfolioState, PriceField, ProcessEventKind, ScheduleRule, ScheduleStage, ScheduleTimeRule,
|
OpenOrderView, OrderIntent, OrderSide, OrderStatus, PortfolioState, PriceField,
|
||||||
Strategy, StrategyContext, StrategyDecision,
|
ProcessEventKind, ScheduleRule, ScheduleStage, ScheduleTimeRule, Strategy, StrategyContext,
|
||||||
|
StrategyDecision,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn d(year: i32, month: u32, day: u32) -> NaiveDate {
|
fn d(year: i32, month: u32, day: u32) -> NaiveDate {
|
||||||
@@ -1330,6 +1331,7 @@ fn strategy_context_exposes_rqalpha_style_account_runtime_view() {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &open_orders,
|
open_orders: &open_orders,
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -1358,6 +1360,39 @@ fn strategy_context_exposes_rqalpha_style_account_runtime_view() {
|
|||||||
ctx.accounts().keys().cloned().collect::<Vec<_>>(),
|
ctx.accounts().keys().cloned().collect::<Vec<_>>(),
|
||||||
vec!["STOCK".to_string()]
|
vec!["STOCK".to_string()]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let spec = FuturesContractSpec::new(300.0, 0.12, 0.14);
|
||||||
|
let mut futures_account = FuturesAccountState::new(500_000.0);
|
||||||
|
futures_account.open("IF2501", FuturesDirection::Long, spec, 2, 4000.0, 12.0);
|
||||||
|
futures_account.mark_price("IF2501", FuturesDirection::Long, 4010.0);
|
||||||
|
let future_ctx = StrategyContext {
|
||||||
|
execution_date: date,
|
||||||
|
decision_date: date,
|
||||||
|
decision_index: 0,
|
||||||
|
data: &data,
|
||||||
|
portfolio: &portfolio,
|
||||||
|
futures_account: Some(&futures_account),
|
||||||
|
open_orders: &open_orders,
|
||||||
|
dynamic_universe: None,
|
||||||
|
subscriptions: &subscriptions,
|
||||||
|
process_events: &[],
|
||||||
|
active_process_event: None,
|
||||||
|
active_datetime: None,
|
||||||
|
order_events: &[],
|
||||||
|
fills: &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
let future_account = future_ctx.future_account().expect("future account");
|
||||||
|
assert_eq!(future_account.account_type, "FUTURE");
|
||||||
|
assert!((future_account.starting_cash - 500_000.0).abs() < 1e-6);
|
||||||
|
assert!((future_account.cash - 211_268.0).abs() < 1e-6);
|
||||||
|
assert!((future_account.market_value - 2_406_000.0).abs() < 1e-6);
|
||||||
|
assert!((future_account.total_value - 505_988.0).abs() < 1e-6);
|
||||||
|
assert!((future_ctx.account_by_type("future").unwrap().cash - 211_268.0).abs() < 1e-6);
|
||||||
|
assert_eq!(
|
||||||
|
future_ctx.accounts().keys().cloned().collect::<Vec<_>>(),
|
||||||
|
vec!["FUTURE".to_string(), "STOCK".to_string()]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ fn strategy_emits_target_weights_and_diagnostics() {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
@@ -73,6 +74,7 @@ fn jq_strategy_emits_same_day_decision() {
|
|||||||
decision_index: 0,
|
decision_index: 0,
|
||||||
data: &data,
|
data: &data,
|
||||||
portfolio: &portfolio,
|
portfolio: &portfolio,
|
||||||
|
futures_account: None,
|
||||||
open_orders: &[],
|
open_orders: &[],
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
subscriptions: &subscriptions,
|
subscriptions: &subscriptions,
|
||||||
|
|||||||
@@ -89,7 +89,10 @@ current alignment pass.
|
|||||||
margin, daily mark-to-market settlement, and short close cashflow
|
margin, daily mark-to-market settlement, and short close cashflow
|
||||||
- [x] standalone futures order execution model with open, close, close-today,
|
- [x] standalone futures order execution model with open, close, close-today,
|
||||||
close-yesterday, margin rejection, order/fill/position/account events
|
close-yesterday, margin rejection, order/fill/position/account events
|
||||||
- [ ] wire futures account into the generic backtest engine runtime
|
- [x] wire futures account runtime view into `BacktestEngine` and
|
||||||
|
`StrategyContext` (`future_account`, `account_by_type("FUTURE")`,
|
||||||
|
`accounts`)
|
||||||
|
- [ ] wire futures order intents into the generic `BacktestEngine` execution loop
|
||||||
- [ ] futures intraday matching integration and expiration settlement
|
- [ ] futures intraday matching integration and expiration settlement
|
||||||
|
|
||||||
## Execution Order
|
## Execution Order
|
||||||
@@ -109,6 +112,6 @@ current alignment pass.
|
|||||||
Active implementation target: continue account parity after exposing the stock
|
Active implementation target: continue account parity after exposing the stock
|
||||||
account runtime view, core Portfolio fields, deposit/withdraw, financing
|
account runtime view, core Portfolio fields, deposit/withdraw, financing
|
||||||
liability APIs, management-fee callbacks, stock account accessors, and the
|
liability APIs, management-fee callbacks, stock account accessors, and the
|
||||||
standalone futures account/order execution model; next gap is wiring futures
|
standalone futures account/order execution model plus generic engine runtime
|
||||||
into the generic engine runtime and adding futures intraday/expiration
|
account visibility; next gap is wiring futures order intents into the generic
|
||||||
semantics.
|
engine execution loop and adding futures intraday/expiration semantics.
|
||||||
|
|||||||
Reference in New Issue
Block a user