Expose account runtime metrics
This commit is contained in:
@@ -6,8 +6,9 @@ use chrono::{NaiveDate, NaiveDateTime};
|
||||
use fidc_core::{
|
||||
BacktestConfig, BacktestEngine, BenchmarkSnapshot, BrokerSimulator, CandidateEligibility,
|
||||
ChinaAShareCostModel, ChinaEquityRuleHooks, DailyFactorSnapshot, DailyMarketSnapshot, DataSet,
|
||||
Instrument, IntradayExecutionQuote, OrderIntent, PriceField, ProcessEventKind, ScheduleRule,
|
||||
ScheduleStage, ScheduleTimeRule, Strategy, StrategyContext, StrategyDecision,
|
||||
Instrument, IntradayExecutionQuote, OpenOrderView, OrderIntent, OrderSide, OrderStatus,
|
||||
PortfolioState, PriceField, ProcessEventKind, ScheduleRule, ScheduleStage, ScheduleTimeRule,
|
||||
Strategy, StrategyContext, StrategyDecision,
|
||||
};
|
||||
|
||||
fn d(year: i32, month: u32, day: u32) -> NaiveDate {
|
||||
@@ -1226,6 +1227,79 @@ fn strategy_context_exposes_final_order_runtime_view() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strategy_context_exposes_rqalpha_style_account_runtime_view() {
|
||||
let prev_date = d(2025, 1, 2);
|
||||
let date = d(2025, 1, 3);
|
||||
let data = DataSet::from_components(
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
vec![BenchmarkSnapshot {
|
||||
date,
|
||||
benchmark: "000300.SH".to_string(),
|
||||
open: 100.0,
|
||||
close: 100.0,
|
||||
prev_close: 99.0,
|
||||
volume: 1_000_000,
|
||||
}],
|
||||
)
|
||||
.expect("dataset");
|
||||
let mut portfolio = PortfolioState::new(10_000.0);
|
||||
portfolio
|
||||
.position_mut("000001.SZ")
|
||||
.buy(prev_date, 100, 10.0);
|
||||
portfolio.begin_trading_day();
|
||||
portfolio.position_mut("000001.SZ").buy(date, 50, 11.0);
|
||||
portfolio
|
||||
.position_mut("000001.SZ")
|
||||
.sell(40, 12.0)
|
||||
.expect("sell");
|
||||
portfolio.position_mut("000001.SZ").record_trade_cost(3.0);
|
||||
let open_orders = vec![OpenOrderView {
|
||||
order_id: 7,
|
||||
symbol: "000002.SZ".to_string(),
|
||||
side: OrderSide::Buy,
|
||||
requested_quantity: 100,
|
||||
filled_quantity: 0,
|
||||
remaining_quantity: 50,
|
||||
unfilled_quantity: 50,
|
||||
status: OrderStatus::Pending,
|
||||
avg_price: 0.0,
|
||||
transaction_cost: 0.0,
|
||||
limit_price: 12.0,
|
||||
reason: "pending_buy".to_string(),
|
||||
}];
|
||||
let subscriptions = BTreeSet::new();
|
||||
let ctx = StrategyContext {
|
||||
execution_date: date,
|
||||
decision_date: date,
|
||||
decision_index: 0,
|
||||
data: &data,
|
||||
portfolio: &portfolio,
|
||||
open_orders: &open_orders,
|
||||
dynamic_universe: None,
|
||||
subscriptions: &subscriptions,
|
||||
process_events: &[],
|
||||
active_process_event: None,
|
||||
active_datetime: None,
|
||||
order_events: &[],
|
||||
fills: &[],
|
||||
};
|
||||
|
||||
let account = ctx.account();
|
||||
|
||||
assert!((account.starting_cash - 10_000.0).abs() < 1e-6);
|
||||
assert!((account.frozen_cash - 600.0).abs() < 1e-6);
|
||||
assert!((account.available_cash - 9_400.0).abs() < 1e-6);
|
||||
assert!((account.transaction_cost - 3.0).abs() < 1e-6);
|
||||
assert!((account.daily_pnl - 247.0).abs() < 1e-6);
|
||||
assert!((account.daily_returns - portfolio.daily_returns()).abs() < 1e-6);
|
||||
assert!((account.total_returns - portfolio.total_returns()).abs() < 1e-6);
|
||||
assert!((ctx.available_cash() - account.available_cash).abs() < 1e-6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn engine_rejects_pending_limit_orders_at_market_close() {
|
||||
let date1 = d(2025, 1, 2);
|
||||
|
||||
Reference in New Issue
Block a user