统一回测策略风控字段校验
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user