Expose futures account runtime view
This commit is contained in:
@@ -10,6 +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::instrument::Instrument;
|
||||
use crate::portfolio::PortfolioState;
|
||||
use crate::scheduler::ScheduleRule;
|
||||
@@ -133,6 +134,7 @@ pub struct StrategyContext<'a> {
|
||||
pub decision_index: usize,
|
||||
pub data: &'a DataSet,
|
||||
pub portfolio: &'a PortfolioState,
|
||||
pub futures_account: Option<&'a FuturesAccountState>,
|
||||
pub open_orders: &'a [OpenOrderView],
|
||||
pub dynamic_universe: Option<&'a BTreeSet<String>>,
|
||||
pub subscriptions: &'a BTreeSet<String>,
|
||||
@@ -393,19 +395,55 @@ impl StrategyContext<'_> {
|
||||
}
|
||||
|
||||
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> {
|
||||
if account_type.eq_ignore_ascii_case("STOCK") {
|
||||
Some(self.stock_account())
|
||||
} else if account_type.eq_ignore_ascii_case("FUTURE") {
|
||||
self.future_account()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -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)]
|
||||
pub struct StrategyDecision {
|
||||
pub rebalance: bool,
|
||||
|
||||
Reference in New Issue
Block a user