统一回测策略风控字段校验

This commit is contained in:
boris
2026-08-29 14:52:03 +08:00
parent ff2844884d
commit f3a37157fc
5 changed files with 337 additions and 3 deletions
+104
View File
@@ -2388,6 +2388,19 @@ where
.sum()
}
fn reserved_open_buy_quantity(&self, symbol: &str, exclude_order_id: Option<u64>) -> u32 {
self.open_orders
.borrow()
.iter()
.filter(|order| {
order.side == OrderSide::Buy
&& order.symbol == symbol
&& exclude_order_id.is_none_or(|order_id| order.order_id != order_id)
})
.map(|order| order.remaining_quantity)
.sum()
}
fn process_open_orders(
&self,
date: NaiveDate,
@@ -4251,6 +4264,49 @@ where
return Ok(());
}
let size_check_price = limit_price.unwrap_or_else(|| {
self.execution_order_limit_check_price(
date,
data,
symbol,
snapshot,
OrderSide::Sell,
algo_request,
)
});
if let Some(rule_reason) = ChinaAShareRiskControl::order_size_rejection_reason_with_config(
OrderSide::Sell,
requested_qty,
position.quantity,
size_check_price,
&self.risk_config,
) {
report.order_events.push(OrderEvent {
date,
decision_date: None,
order_created_date: None,
execution_date: None,
order_id: Some(order_id),
symbol: symbol.to_string(),
side: OrderSide::Sell,
requested_quantity: requested_qty,
filled_quantity: 0,
status: OrderStatus::Rejected,
reason: format!("{reason}: {rule_reason}"),
});
Self::emit_order_process_event(
report,
date,
Self::creation_reject_kind(emit_creation_events),
order_id,
symbol,
OrderSide::Sell,
format!("status=Rejected reason={rule_reason}"),
);
self.clear_open_order(order_id);
return Ok(());
}
if emit_creation_events {
Self::emit_order_process_event(
report,
@@ -5984,6 +6040,54 @@ where
return Ok(());
}
let current_position_quantity = portfolio
.position(symbol)
.map(|position| position.quantity)
.unwrap_or(0)
.saturating_add(self.reserved_open_buy_quantity(symbol, Some(order_id)));
let size_check_price = limit_price.unwrap_or_else(|| {
self.execution_order_limit_check_price(
date,
data,
symbol,
snapshot,
OrderSide::Buy,
algo_request,
)
});
if let Some(rule_reason) = ChinaAShareRiskControl::order_size_rejection_reason_with_config(
OrderSide::Buy,
requested_qty,
current_position_quantity,
size_check_price,
&self.risk_config,
) {
report.order_events.push(OrderEvent {
date,
decision_date: None,
order_created_date: None,
execution_date: None,
order_id: Some(order_id),
symbol: symbol.to_string(),
side: OrderSide::Buy,
requested_quantity: requested_qty,
filled_quantity: 0,
status: OrderStatus::Rejected,
reason: format!("{reason}: {rule_reason}"),
});
Self::emit_order_process_event(
report,
date,
Self::creation_reject_kind(emit_creation_events),
order_id,
symbol,
OrderSide::Buy,
format!("status=Rejected reason={rule_reason}"),
);
self.clear_open_order(order_id);
return Ok(());
}
if emit_creation_events {
Self::emit_order_process_event(
report,