修正精确分钟执行价回退逻辑

This commit is contained in:
boris
2026-07-06 10:55:01 +08:00
parent 64298f09c1
commit 4fee8e1d07
+47 -4
View File
@@ -1285,17 +1285,21 @@ where
|| self.quote_has_executable_liquidity(quote, side, matching_type)) || self.quote_has_executable_liquidity(quote, side, matching_type))
}); });
}; };
quotes let latest = quotes
.iter() .iter()
.filter(|quote| { .filter(|quote| {
quote.timestamp <= cursor quote.timestamp <= cursor
&& self && self
.select_quote_reference_price(snapshot, quote, side, matching_type) .select_quote_reference_price(snapshot, quote, side, matching_type)
.is_some() .is_some()
&& (!require_executable_liquidity
|| self.quote_has_executable_liquidity(quote, side, matching_type))
}) })
.max_by_key(|quote| quote.timestamp) .max_by_key(|quote| quote.timestamp)?;
if require_executable_liquidity
&& !self.quote_has_executable_liquidity(latest, side, matching_type)
{
return None;
}
Some(latest)
} }
fn process_limit_shares( fn process_limit_shares(
@@ -6171,6 +6175,45 @@ mod tests {
assert_eq!(fill.legs[0].price, 10.0); assert_eq!(fill.legs[0].price, 10.0);
} }
#[test]
fn minute_last_exact_time_does_not_fallback_to_older_liquid_quote() {
let date = chrono::NaiveDate::from_ymd_opt(2025, 1, 2).expect("valid date");
let broker = BrokerSimulator::new(ChinaAShareCostModel::default(), ChinaEquityRuleHooks)
.with_matching_type(MatchingType::MinuteLast)
.with_volume_limit(true)
.with_volume_percent(0.25)
.with_liquidity_limit(true);
let mut quote_0931 = limit_test_quote(10.0, 9.99, 10.01);
quote_0931.timestamp = date.and_hms_opt(9, 31, 0).expect("valid timestamp");
quote_0931.volume_delta = 10_000;
quote_0931.ask1_volume = 10_000;
quote_0931.bid1_volume = 10_000;
let mut quote_1015 = limit_test_quote(10.2, 10.19, 10.21);
quote_1015.timestamp = date.and_hms_opt(10, 15, 0).expect("valid timestamp");
quote_1015.volume_delta = 0;
quote_1015.ask1_volume = 10_000;
quote_1015.bid1_volume = 10_000;
let fill = broker.select_execution_fill(
&limit_test_snapshot(),
&[quote_0931, quote_1015],
OrderSide::Sell,
MatchingType::MinuteLast,
Some(date.and_hms_opt(10, 15, 0).expect("valid timestamp")),
Some(date.and_hms_opt(10, 15, 0).expect("valid timestamp")),
1_000,
100,
100,
100,
false,
None,
None,
None,
);
assert!(fill.is_none(), "{fill:?}");
}
#[test] #[test]
fn minute_last_volume_limit_rejects_sub_lot_quote_volume() { fn minute_last_volume_limit_rejects_sub_lot_quote_volume() {
let date = chrono::NaiveDate::from_ymd_opt(2025, 1, 2).expect("valid date"); let date = chrono::NaiveDate::from_ymd_opt(2025, 1, 2).expect("valid date");