fix: apply decision buy denials to exposure-increasing amendments

This commit is contained in:
boris
2026-09-08 01:00:52 +08:00
parent c85afb59ab
commit daa9d8d341
+52
View File
@@ -2838,6 +2838,18 @@ where
}
}
if existing.side == OrderSide::Buy
&& (target_total_quantity > existing.requested_quantity
|| target_limit_price > existing.limit_price)
&& let Some(denial) = self.runtime_buy_denials.borrow().get(&existing.symbol)
{
Self::emit_open_order_update_rejected(
report, date, order_id, Some(&existing.symbol), Some(existing.side),
reason, denial,
);
return;
}
let resets_queue_priority = target_limit_price.to_bits() != existing.limit_price.to_bits()
|| target_total_quantity > existing.requested_quantity;
{
@@ -8314,6 +8326,46 @@ mod tests {
assert!(broker.runtime_buy_denials.borrow().is_empty());
}
#[test]
fn decision_buy_denial_rejects_increasing_amendments_without_mutation() {
let date = limit_test_snapshot().date;
let data = DataSet::from_components(vec![limit_test_instrument()], vec![limit_test_snapshot()],
Vec::new(), vec![limit_test_candidate(true, true)], vec![limit_test_benchmark()]).unwrap();
for (quantity, price) in [(Some(300), None), (None, Some(10.5)),
(Some(100), Some(10.5)), (Some(300), Some(9.5))] {
let broker = BrokerSimulator::new(ChinaAShareCostModel::default(), ChinaEquityRuleHooks);
broker.upsert_open_order(test_open_order(1));
broker.upsert_open_order(test_open_order(2));
broker.runtime_buy_denials.borrow_mut().insert("000001.SZ".to_string(), "strategy_buy_condition_false".to_string());
let portfolio = PortfolioState::new(100_000.0);
let mut report = BrokerExecutionReport::default();
broker.modify_open_order(date, &portfolio, &data, 1, quantity, price, "amend", &mut report);
let orders = broker.open_orders.borrow();
assert_eq!(orders.iter().map(|order| order.order_id).collect::<Vec<_>>(), vec![1, 2]);
assert_eq!(orders[0].requested_quantity, 200);
assert_eq!(orders[0].remaining_quantity, 200);
assert_eq!(orders[0].limit_price, 10.0);
assert!(report.order_events.last().unwrap().reason.contains("strategy_buy_condition_false"));
}
}
#[test]
fn decision_buy_denial_allows_reducing_an_existing_buy() {
let date = limit_test_snapshot().date;
let data = DataSet::from_components(vec![limit_test_instrument()], vec![limit_test_snapshot()],
Vec::new(), vec![limit_test_candidate(true, true)], vec![limit_test_benchmark()]).unwrap();
let broker = BrokerSimulator::new(ChinaAShareCostModel::default(), ChinaEquityRuleHooks);
broker.upsert_open_order(test_open_order(1));
broker.runtime_buy_denials.borrow_mut().insert("000001.SZ".to_string(), "strategy_buy_condition_false".to_string());
let portfolio = PortfolioState::new(100_000.0);
let mut report = BrokerExecutionReport::default();
broker.modify_open_order(date, &portfolio, &data, 1, Some(100), Some(9.5), "reduce", &mut report);
let orders = broker.open_orders.borrow();
assert_eq!(orders[0].requested_quantity, 100);
assert_eq!(orders[0].limit_price, 9.5);
assert!(!report.order_events.last().unwrap().reason.contains("strategy_buy_condition_false"));
}
fn next_open_sell_decision() -> StrategyDecision {
StrategyDecision {
order_intents: vec![OrderIntent::Shares {