统一次日开盘新仓目标市值指令

This commit is contained in:
boris
2026-07-12 05:55:55 +08:00
parent 214872dfbf
commit 0ea5fae69d
+101 -34
View File
@@ -2287,8 +2287,14 @@ impl PlatformExprStrategy {
}; };
if self.config.matching_type == MatchingType::NextBarOpen { if self.config.matching_type == MatchingType::NextBarOpen {
if let Some(market) = ctx.data.market(date, symbol) { if let Some(market) = ctx.data.market(date, symbol) {
if market.prev_close.is_finite() && market.prev_close > 0.0 { let signal_visible_price = if ctx.is_lagged_execution() && date == ctx.decision_date
return position.quantity as f64 * market.prev_close; {
market.close
} else {
market.prev_close
};
if signal_visible_price.is_finite() && signal_visible_price > 0.0 {
return position.quantity as f64 * signal_visible_price;
} }
} }
} }
@@ -9579,22 +9585,57 @@ impl Strategy for PlatformExprStrategy {
{ {
continue; continue;
} }
let target_cash = if self.config.aiquant_transaction_cost { if self.config.aiquant_transaction_cost {
fixed_buy_cash * stock_scale let target_value = fixed_buy_cash * stock_scale;
} else { if target_value <= 0.0 {
let slot_buy_cash = self.remaining_buy_cash_per_slot( continue;
}
if !defer_execution_risk
&& self
.buy_rejection_reason(
ctx,
execution_date,
symbol,
&self.stock_state(ctx, execution_date, symbol)?,
)?
.is_some()
{
continue;
}
if !self.stock_passes_expr(ctx, &day, &decision_stock)? {
continue;
}
self.project_order_value(
ctx, ctx,
&projected, &mut projected,
projection_date, projection_date,
target_budget, symbol,
selection_limit, target_value,
&rebalance_working_symbols, &mut projected_execution_state,
&rebalance_value_symbols,
rebalance_pending_buy_value,
&pending_full_close_symbols,
); );
slot_buy_cash * stock_scale order_intents.push(OrderIntent::TargetValue {
}; symbol: symbol.clone(),
target_value,
reason: "periodic_rebalance_buy".to_string(),
});
self.remember_position_entry_date(symbol, signal_date);
aiquant_available_cash = projected.cash().max(0.0);
rebalance_working_symbols.insert(symbol.clone());
slot_working_symbols.insert(symbol.clone());
continue;
}
let slot_buy_cash = self.remaining_buy_cash_per_slot(
ctx,
&projected,
projection_date,
target_budget,
selection_limit,
&rebalance_working_symbols,
&rebalance_value_symbols,
rebalance_pending_buy_value,
&pending_full_close_symbols,
);
let target_cash = slot_buy_cash * stock_scale;
let buy_cash = target_cash.min(aiquant_available_cash); let buy_cash = target_cash.min(aiquant_available_cash);
if buy_cash <= 0.0 { if buy_cash <= 0.0 {
if debug_projection { if debug_projection {
@@ -18579,6 +18620,11 @@ mod tests {
OrderIntent::Value { symbol, value, .. } => { OrderIntent::Value { symbol, value, .. } => {
symbol == limit_symbol && *value > 0.0 symbol == limit_symbol && *value > 0.0
} }
OrderIntent::TargetValue {
symbol,
target_value,
..
} => symbol == limit_symbol && *target_value > 0.0,
_ => false, _ => false,
}), }),
"{:?}", "{:?}",
@@ -18779,6 +18825,13 @@ mod tests {
intent, intent,
OrderIntent::Value { symbol, value, .. } OrderIntent::Value { symbol, value, .. }
if symbol == candidate_symbol && *value > 0.0 if symbol == candidate_symbol && *value > 0.0
) || matches!(
intent,
OrderIntent::TargetValue {
symbol,
target_value,
..
} if symbol == candidate_symbol && *target_value > 0.0
)), )),
"{:?}", "{:?}",
decision.order_intents decision.order_intents
@@ -25251,7 +25304,11 @@ mod tests {
.filter(|intent| { .filter(|intent| {
matches!( matches!(
intent, intent,
OrderIntent::Value { reason, .. } if reason == "periodic_rebalance_buy" OrderIntent::TargetValue {
target_value,
reason,
..
} if *target_value > 0.0 && reason == "periodic_rebalance_buy"
) )
}) })
.count(); .count();
@@ -25429,8 +25486,13 @@ mod tests {
assert!( assert!(
!decision.order_intents.iter().any(|intent| matches!( !decision.order_intents.iter().any(|intent| matches!(
intent, intent,
OrderIntent::Value { symbol, reason, .. } OrderIntent::TargetValue {
if symbol == "000001.SZ" && reason == "periodic_rebalance_buy" symbol,
target_value,
reason,
} if symbol == "000001.SZ"
&& *target_value > 0.0
&& reason == "periodic_rebalance_buy"
)), )),
"{:?}", "{:?}",
decision.order_intents decision.order_intents
@@ -25438,8 +25500,13 @@ mod tests {
assert!( assert!(
decision.order_intents.iter().any(|intent| matches!( decision.order_intents.iter().any(|intent| matches!(
intent, intent,
OrderIntent::Value { symbol, reason, .. } OrderIntent::TargetValue {
if symbol == "000003.SZ" && reason == "periodic_rebalance_buy" symbol,
target_value,
reason,
} if symbol == "000003.SZ"
&& *target_value > 0.0
&& reason == "periodic_rebalance_buy"
)), )),
"{:?}", "{:?}",
decision.order_intents decision.order_intents
@@ -25629,7 +25696,11 @@ mod tests {
.filter(|intent| { .filter(|intent| {
matches!( matches!(
intent, intent,
OrderIntent::Value { reason, .. } if reason == "periodic_rebalance_buy" OrderIntent::TargetValue {
target_value,
reason,
..
} if *target_value > 0.0 && reason == "periodic_rebalance_buy"
) )
}) })
.count(); .count();
@@ -25650,8 +25721,12 @@ mod tests {
.order_intents .order_intents
.iter() .iter()
.filter_map(|intent| match intent { .filter_map(|intent| match intent {
OrderIntent::Value { value, reason, .. } if reason == "periodic_rebalance_buy" => { OrderIntent::TargetValue {
Some(*value) target_value,
reason,
..
} if *target_value > 0.0 && reason == "periodic_rebalance_buy" => {
Some(*target_value)
} }
_ => None, _ => None,
}) })
@@ -25660,18 +25735,10 @@ mod tests {
assert!( assert!(
periodic_buy_values periodic_buy_values
.iter() .iter()
.take(periodic_buy_values.len().saturating_sub(1))
.all(|value| (*value - equal_weight_target).abs() < 1e-6), .all(|value| (*value - equal_weight_target).abs() < 1e-6),
"{:?}", "{:?}",
decision.order_intents decision.order_intents
); );
assert!(
periodic_buy_values
.last()
.is_some_and(|value| *value > 0.0 && *value <= equal_weight_target),
"{:?}",
decision.order_intents
);
} }
#[test] #[test]
@@ -25819,13 +25886,13 @@ mod tests {
assert!( assert!(
decision.order_intents.iter().any(|intent| matches!( decision.order_intents.iter().any(|intent| matches!(
intent, intent,
OrderIntent::Value { OrderIntent::TargetValue {
symbol, symbol,
value, target_value,
reason, reason,
} if symbol == "000002.SZ" } if symbol == "000002.SZ"
&& reason == "periodic_rebalance_buy" && reason == "periodic_rebalance_buy"
&& (*value - 10_000.0).abs() < 1e-6 && (*target_value - 10_000.0).abs() < 1e-6
)), )),
"{:?}", "{:?}",
decision.order_intents decision.order_intents