修正精确分钟执行价回退逻辑
This commit is contained in:
@@ -1285,17 +1285,21 @@ where
|
||||
|| self.quote_has_executable_liquidity(quote, side, matching_type))
|
||||
});
|
||||
};
|
||||
quotes
|
||||
let latest = quotes
|
||||
.iter()
|
||||
.filter(|quote| {
|
||||
quote.timestamp <= cursor
|
||||
&& self
|
||||
.select_quote_reference_price(snapshot, quote, side, matching_type)
|
||||
.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(
|
||||
@@ -6171,6 +6175,45 @@ mod tests {
|
||||
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]
|
||||
fn minute_last_volume_limit_rejects_sub_lot_quote_volume() {
|
||||
let date = chrono::NaiveDate::from_ymd_opt(2025, 1, 2).expect("valid date");
|
||||
|
||||
Reference in New Issue
Block a user