切换回测执行价为分钟线语义
This commit is contained in:
@@ -190,7 +190,7 @@ fn engine_preloads_declared_decision_quotes_for_current_positions() {
|
||||
ChinaEquityRuleHooks,
|
||||
PriceField::Last,
|
||||
)
|
||||
.with_matching_type(MatchingType::NextTickLast)
|
||||
.with_matching_type(MatchingType::NextMinuteLast)
|
||||
.with_intraday_execution_start_time(t(10, 40, 0));
|
||||
let config = BacktestConfig {
|
||||
initial_cash: 10_000.0,
|
||||
@@ -385,7 +385,7 @@ fn engine_reuses_preloaded_decision_quotes_without_loader_call() {
|
||||
ChinaEquityRuleHooks,
|
||||
PriceField::Last,
|
||||
)
|
||||
.with_matching_type(MatchingType::NextTickLast)
|
||||
.with_matching_type(MatchingType::NextMinuteLast)
|
||||
.with_intraday_execution_start_time(t(10, 40, 0));
|
||||
let config = BacktestConfig {
|
||||
initial_cash: 10_000.0,
|
||||
@@ -587,7 +587,7 @@ fn engine_loads_distinct_decision_quote_times_on_same_day() {
|
||||
ChinaEquityRuleHooks,
|
||||
PriceField::Last,
|
||||
)
|
||||
.with_matching_type(MatchingType::NextTickLast)
|
||||
.with_matching_type(MatchingType::NextMinuteLast)
|
||||
.with_intraday_execution_start_time(t(10, 40, 0));
|
||||
let config = BacktestConfig {
|
||||
initial_cash: 10_000.0,
|
||||
|
||||
@@ -799,7 +799,7 @@ impl Strategy for UniverseDirectiveStrategy {
|
||||
|
||||
impl Strategy for TickProbeStrategy {
|
||||
fn name(&self) -> &str {
|
||||
"tick-probe"
|
||||
"minute-probe"
|
||||
}
|
||||
|
||||
fn on_day(
|
||||
@@ -812,26 +812,26 @@ impl Strategy for TickProbeStrategy {
|
||||
exit_symbols: BTreeSet::new(),
|
||||
order_intents: vec![OrderIntent::Subscribe {
|
||||
symbols: BTreeSet::from(["000001.SZ".to_string()]),
|
||||
reason: "subscribe_tick_probe".to_string(),
|
||||
reason: "subscribe_minute_probe".to_string(),
|
||||
}],
|
||||
notes: Vec::new(),
|
||||
diagnostics: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn on_tick(
|
||||
fn on_minute(
|
||||
&mut self,
|
||||
ctx: &StrategyContext<'_>,
|
||||
quote: &IntradayExecutionQuote,
|
||||
) -> Result<StrategyDecision, fidc_core::BacktestError> {
|
||||
let visible_last = ctx
|
||||
.history_bars("e.symbol, 9, "tick", "last", true)
|
||||
.history_bars("e.symbol, 9, "1m", "last", true)
|
||||
.iter()
|
||||
.map(|value| format!("{value:.2}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
let previous_last = ctx
|
||||
.history_bars("e.symbol, 9, "tick", "last", false)
|
||||
.history_bars("e.symbol, 9, "1m", "last", false)
|
||||
.iter()
|
||||
.map(|value| format!("{value:.2}"))
|
||||
.collect::<Vec<_>>()
|
||||
@@ -853,7 +853,7 @@ impl Strategy for TickProbeStrategy {
|
||||
order_intents: vec![OrderIntent::Shares {
|
||||
symbol: quote.symbol.clone(),
|
||||
quantity: 100,
|
||||
reason: "tick_buy".to_string(),
|
||||
reason: "minute_buy".to_string(),
|
||||
}],
|
||||
notes: Vec::new(),
|
||||
diagnostics: Vec::new(),
|
||||
@@ -919,10 +919,10 @@ impl Strategy for DataApiProbeStrategy {
|
||||
let daily_price_count = ctx
|
||||
.get_price("000001.SZ", d(2025, 1, 3), ctx.execution_date, "1d")
|
||||
.len();
|
||||
let tick_alias_price_bars =
|
||||
ctx.get_price("000001.SZ", d(2025, 1, 3), ctx.execution_date, "tick");
|
||||
let tick_price_count = tick_alias_price_bars.len();
|
||||
let tick_alias_frequency = tick_alias_price_bars
|
||||
let minute_price_bars =
|
||||
ctx.get_price("000001.SZ", d(2025, 1, 3), ctx.execution_date, "1m");
|
||||
let minute_price_count = minute_price_bars.len();
|
||||
let minute_frequency = minute_price_bars
|
||||
.first()
|
||||
.map(|bar| bar.frequency.clone())
|
||||
.unwrap_or_default();
|
||||
@@ -930,7 +930,7 @@ impl Strategy for DataApiProbeStrategy {
|
||||
ctx.instruments_history(&["000001.SZ", "000002.SZ"]).len();
|
||||
let active_instrument_count = ctx.active_instruments(&["000001.SZ", "000002.SZ"]).len();
|
||||
self.snapshots.borrow_mut().push(format!(
|
||||
"daily={daily_close};previous={previous_close};minute={tick_last};previous_minute={previous_tick_last};current={current_close};instrument={instrument_name};all={};history={instrument_history_count};active={active_instrument_count};range={trading_date_count};prev={prev_date};next={next_date};suspended={suspended};st={st_flags};price_daily={daily_price_count};price_tick={tick_price_count};tick_alias_frequency={tick_alias_frequency}",
|
||||
"daily={daily_close};previous={previous_close};minute={tick_last};previous_minute={previous_tick_last};current={current_close};instrument={instrument_name};all={};history={instrument_history_count};active={active_instrument_count};range={trading_date_count};prev={prev_date};next={next_date};suspended={suspended};st={st_flags};price_daily={daily_price_count};price_tick={minute_price_count};minute_frequency={minute_frequency}",
|
||||
ctx.all_instruments().len()
|
||||
));
|
||||
}
|
||||
@@ -2046,25 +2046,25 @@ fn engine_runs_subscribed_tick_hooks_and_executes_tick_orders() {
|
||||
]
|
||||
);
|
||||
assert_eq!(result.fills.len(), 1);
|
||||
assert_eq!(result.fills[0].reason, "tick_buy");
|
||||
assert_eq!(result.fills[0].reason, "minute_buy");
|
||||
assert_eq!(result.fills[0].quantity, 100);
|
||||
assert!(
|
||||
result
|
||||
.process_events
|
||||
.iter()
|
||||
.any(|event| event.kind == ProcessEventKind::PreTick)
|
||||
.any(|event| event.kind == ProcessEventKind::PreMinute)
|
||||
);
|
||||
assert!(
|
||||
result
|
||||
.process_events
|
||||
.iter()
|
||||
.any(|event| event.kind == ProcessEventKind::Tick)
|
||||
.any(|event| event.kind == ProcessEventKind::Minute)
|
||||
);
|
||||
assert!(
|
||||
result
|
||||
.process_events
|
||||
.iter()
|
||||
.any(|event| event.kind == ProcessEventKind::PostTick)
|
||||
.any(|event| event.kind == ProcessEventKind::PostMinute)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2253,7 +2253,7 @@ fn strategy_context_exposes_engine_native_data_helpers() {
|
||||
assert_eq!(
|
||||
snapshots.borrow().as_slice(),
|
||||
[
|
||||
"daily=10.10,10.20;previous=10.00,10.10;minute=10.15,10.25;previous_minute=10.15;current=10.20;instrument=Anchor;all=2;history=2;active=1;range=3;prev=2025-01-03;next=2025-01-06;suspended=0,1,0;st=0,1,0;price_daily=2;price_tick=3;tick_alias_frequency=1m"
|
||||
"daily=10.10,10.20;previous=10.00,10.10;minute=10.15,10.25;previous_minute=10.15;current=10.20;instrument=Anchor;all=2;history=2;active=1;range=3;prev=2025-01-03;next=2025-01-06;suspended=0,1,0;st=0,1,0;price_daily=2;price_tick=3;minute_frequency=1m"
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ fn broker_delayed_limit_open_sell_uses_tick_price() {
|
||||
ChinaEquityRuleHooks::default(),
|
||||
PriceField::Last,
|
||||
)
|
||||
.with_matching_type(MatchingType::NextTickLast)
|
||||
.with_matching_type(MatchingType::NextMinuteLast)
|
||||
.with_intraday_execution_start_time(NaiveTime::from_hms_opt(9, 31, 0).unwrap())
|
||||
.with_volume_limit(false)
|
||||
.with_liquidity_limit(false);
|
||||
@@ -1809,7 +1809,7 @@ fn broker_rejects_intraday_last_order_without_execution_quotes() {
|
||||
order_intents: vec![OrderIntent::Value {
|
||||
symbol: "000002.SZ".to_string(),
|
||||
value: 100_000.0,
|
||||
reason: "missing_tick_quotes".to_string(),
|
||||
reason: "missing_minute_quotes".to_string(),
|
||||
}],
|
||||
notes: Vec::new(),
|
||||
diagnostics: Vec::new(),
|
||||
@@ -2173,7 +2173,7 @@ fn broker_cancels_market_buy_when_tick_has_no_volume() {
|
||||
report.order_events[0].status,
|
||||
fidc_core::OrderStatus::Canceled
|
||||
);
|
||||
assert!(report.order_events[0].reason.contains("tick no volume"));
|
||||
assert!(report.order_events[0].reason.contains("minute no volume"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2888,7 +2888,7 @@ fn broker_uses_best_own_price_for_intraday_matching() {
|
||||
ChinaEquityRuleHooks::default(),
|
||||
PriceField::Last,
|
||||
)
|
||||
.with_matching_type(MatchingType::NextTickBestOwn);
|
||||
.with_matching_type(MatchingType::NextMinuteBestOwn);
|
||||
|
||||
let report = broker
|
||||
.execute(
|
||||
@@ -3003,7 +3003,7 @@ fn broker_uses_best_counterparty_price_for_intraday_matching() {
|
||||
ChinaEquityRuleHooks::default(),
|
||||
PriceField::Last,
|
||||
)
|
||||
.with_matching_type(MatchingType::NextTickBestCounterparty);
|
||||
.with_matching_type(MatchingType::NextMinuteBestCounterparty);
|
||||
|
||||
let report = broker
|
||||
.execute(
|
||||
|
||||
Reference in New Issue
Block a user