增加回测结束边界状态审计
This commit is contained in:
@@ -6,12 +6,13 @@ use std::sync::{Arc, Mutex};
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
use fidc_core::{
|
||||
BacktestConfig, BacktestEngine, BacktestProcessMod, BacktestProcessModLoader,
|
||||
BenchmarkSnapshot, BrokerSimulator, CandidateEligibility, ChinaAShareCostModel,
|
||||
ChinaEquityRuleHooks, DailyFactorSnapshot, DailyMarketSnapshot, DataSet, ExecutionQuoteRequest,
|
||||
FuturesAccountState, FuturesCommissionType, FuturesContractSpec, FuturesDirection,
|
||||
FuturesOrderIntent, FuturesPositionEffect, FuturesTradingParameter, FuturesValidationConfig,
|
||||
Instrument, IntradayExecutionQuote, IntradayOrderBookDepthLevel, MatchingType,
|
||||
NumericFactorMap, OpenOrderView, OrderIntent, OrderSide, OrderStatus, PlatformExprStrategy,
|
||||
BacktestTerminalAssetClass, BacktestTerminalStatus, BenchmarkSnapshot, BrokerSimulator,
|
||||
CandidateEligibility, ChinaAShareCostModel, ChinaEquityRuleHooks, DailyFactorSnapshot,
|
||||
DailyMarketSnapshot, DataSet, ExecutionQuoteRequest, FuturesAccountState,
|
||||
FuturesCommissionType, FuturesContractSpec, FuturesDirection, FuturesOrderIntent,
|
||||
FuturesPositionEffect, FuturesTradingParameter, FuturesValidationConfig, Instrument,
|
||||
IntradayExecutionQuote, IntradayOrderBookDepthLevel, MatchingType, NumericFactorMap,
|
||||
OpenOrderView, OrderIntent, OrderSide, OrderStatus, PlatformExprStrategy,
|
||||
PlatformExprStrategyConfig, PlatformTradeAction, PortfolioState, PriceField, ProcessEvent,
|
||||
ProcessEventBus, ProcessEventKind, ScheduleRule, ScheduleStage, ScheduleTimeRule, Strategy,
|
||||
StrategyContext, StrategyDecision,
|
||||
@@ -1683,6 +1684,61 @@ fn engine_matches_pending_futures_limit_order_with_data_driven_costs() {
|
||||
.expect("long futures position");
|
||||
assert_eq!(position.quantity, 2);
|
||||
assert!((position.contract_multiplier - 300.0).abs() < 1e-6);
|
||||
assert_eq!(result.terminal_audit.status, BacktestTerminalStatus::Clean);
|
||||
assert_eq!(result.terminal_audit.open_order_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn engine_reports_pending_futures_order_at_backtest_boundary() {
|
||||
let date = d(2025, 1, 2);
|
||||
let broker = BrokerSimulator::new_with_execution_price(
|
||||
ChinaAShareCostModel::default(),
|
||||
ChinaEquityRuleHooks::default(),
|
||||
PriceField::Open,
|
||||
);
|
||||
let mut engine = BacktestEngine::new(
|
||||
two_day_futures_data(),
|
||||
FuturesLimitOrderStrategy,
|
||||
broker,
|
||||
BacktestConfig {
|
||||
initial_cash: 100_000.0,
|
||||
benchmark_code: "000300.SH".to_string(),
|
||||
start_date: Some(date),
|
||||
end_date: Some(date),
|
||||
decision_lag_trading_days: 0,
|
||||
execution_price_field: PriceField::Open,
|
||||
},
|
||||
)
|
||||
.with_futures_initial_cash(1_000_000.0);
|
||||
|
||||
let result = engine.run().expect("backtest succeeds");
|
||||
|
||||
assert!(result.fills.is_empty());
|
||||
assert_eq!(
|
||||
result.terminal_audit.status,
|
||||
BacktestTerminalStatus::CompletedWithPendingState
|
||||
);
|
||||
assert_eq!(result.terminal_audit.last_execution_date, Some(date));
|
||||
assert_eq!(result.terminal_audit.stock_open_order_count, 0);
|
||||
assert_eq!(result.terminal_audit.futures_open_order_count, 1);
|
||||
assert_eq!(result.terminal_audit.open_order_count(), 1);
|
||||
assert_eq!(result.terminal_audit.omitted_open_order_count, 0);
|
||||
assert_eq!(result.terminal_audit.open_order_samples.len(), 1);
|
||||
assert_eq!(
|
||||
result.terminal_audit.open_order_samples[0].asset_class,
|
||||
BacktestTerminalAssetClass::Futures
|
||||
);
|
||||
assert_eq!(result.terminal_audit.open_order_samples[0].symbol, "IF2501");
|
||||
assert_eq!(
|
||||
result.terminal_audit.open_order_samples[0].remaining_quantity,
|
||||
2
|
||||
);
|
||||
assert!(
|
||||
result
|
||||
.order_events
|
||||
.iter()
|
||||
.any(|event| { event.symbol == "IF2501" && event.status == OrderStatus::Pending })
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2895,6 +2951,8 @@ fn engine_applies_account_cash_flow_and_financing_intents() {
|
||||
assert!(result.process_events.iter().any(|event| {
|
||||
event.kind == ProcessEventKind::AccountManagementFee && event.detail.contains("fee=42.00")
|
||||
}));
|
||||
assert_eq!(result.terminal_audit.status, BacktestTerminalStatus::Clean);
|
||||
assert_eq!(result.terminal_audit.pending_cash_flow_count, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -3066,6 +3124,8 @@ fn engine_rejects_pending_limit_orders_at_market_close() {
|
||||
assert!(result.process_events.iter().any(|event| {
|
||||
event.date == date1 && event.kind == ProcessEventKind::OrderUnsolicitedUpdate
|
||||
}));
|
||||
assert_eq!(result.terminal_audit.status, BacktestTerminalStatus::Clean);
|
||||
assert_eq!(result.terminal_audit.stock_open_order_count, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user