跳过无加载器的行情规划
This commit is contained in:
@@ -2519,7 +2519,7 @@ where
|
|||||||
)?;
|
)?;
|
||||||
let on_day_open_orders = self.open_order_views();
|
let on_day_open_orders = self.open_order_views();
|
||||||
let decision_quote_times = self.strategy.decision_quote_times();
|
let decision_quote_times = self.strategy.decision_quote_times();
|
||||||
if !decision_quote_times.is_empty() {
|
if self.execution_quote_loader.is_some() && !decision_quote_times.is_empty() {
|
||||||
let decision_quote_symbols =
|
let decision_quote_symbols =
|
||||||
self.strategy.decision_quote_symbols(&StrategyContext {
|
self.strategy.decision_quote_symbols(&StrategyContext {
|
||||||
execution_date,
|
execution_date,
|
||||||
|
|||||||
@@ -62,6 +62,78 @@ impl Strategy for DecisionQuoteReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct NoLoaderDecisionQuoteStrategy {
|
||||||
|
symbol_plan_calls: Arc<Mutex<usize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Strategy for NoLoaderDecisionQuoteStrategy {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"no_loader_decision_quote_strategy"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decision_quote_times(&self) -> Vec<NaiveTime> {
|
||||||
|
vec![t(10, 18, 0)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decision_quote_symbols(
|
||||||
|
&mut self,
|
||||||
|
_ctx: &StrategyContext<'_>,
|
||||||
|
) -> Result<std::collections::BTreeSet<String>, fidc_core::BacktestError> {
|
||||||
|
*self
|
||||||
|
.symbol_plan_calls
|
||||||
|
.lock()
|
||||||
|
.expect("symbol plan counter mutex") += 1;
|
||||||
|
Ok(std::collections::BTreeSet::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn engine_skips_decision_quote_symbol_plan_without_loader() {
|
||||||
|
let date = d(2026, 1, 5);
|
||||||
|
let data = DataSet::from_components(
|
||||||
|
Vec::new(),
|
||||||
|
Vec::new(),
|
||||||
|
Vec::new(),
|
||||||
|
Vec::new(),
|
||||||
|
vec![BenchmarkSnapshot {
|
||||||
|
date,
|
||||||
|
benchmark: "000852.SH".to_string(),
|
||||||
|
open: 1000.0,
|
||||||
|
close: 1001.0,
|
||||||
|
prev_close: 999.0,
|
||||||
|
volume: 1_000_000,
|
||||||
|
}],
|
||||||
|
)
|
||||||
|
.expect("dataset");
|
||||||
|
let broker = BrokerSimulator::new_with_execution_price(
|
||||||
|
ChinaAShareCostModel::default(),
|
||||||
|
ChinaEquityRuleHooks,
|
||||||
|
PriceField::Close,
|
||||||
|
)
|
||||||
|
.with_matching_type(MatchingType::CurrentBarClose);
|
||||||
|
let config = BacktestConfig {
|
||||||
|
initial_cash: 10_000.0,
|
||||||
|
benchmark_code: "000852.SH".to_string(),
|
||||||
|
start_date: Some(date),
|
||||||
|
end_date: Some(date),
|
||||||
|
decision_lag_trading_days: 0,
|
||||||
|
execution_price_field: PriceField::Close,
|
||||||
|
};
|
||||||
|
let symbol_plan_calls = Arc::new(Mutex::new(0usize));
|
||||||
|
let strategy = NoLoaderDecisionQuoteStrategy {
|
||||||
|
symbol_plan_calls: Arc::clone(&symbol_plan_calls),
|
||||||
|
};
|
||||||
|
let mut engine = BacktestEngine::new(data, strategy, broker, config);
|
||||||
|
|
||||||
|
engine.run().expect("backtest should run");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
*symbol_plan_calls.lock().expect("symbol plan counter mutex"),
|
||||||
|
0,
|
||||||
|
"a preloaded/no-loader engine cannot use a newly computed quote symbol plan"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn engine_preloads_declared_decision_quotes_for_current_positions() {
|
fn engine_preloads_declared_decision_quotes_for_current_positions() {
|
||||||
let first = d(2026, 1, 5);
|
let first = d(2026, 1, 5);
|
||||||
|
|||||||
Reference in New Issue
Block a user