统一次日开盘新仓目标市值指令
This commit is contained in:
@@ -2287,8 +2287,14 @@ impl PlatformExprStrategy {
|
||||
};
|
||||
if self.config.matching_type == MatchingType::NextBarOpen {
|
||||
if let Some(market) = ctx.data.market(date, symbol) {
|
||||
if market.prev_close.is_finite() && market.prev_close > 0.0 {
|
||||
return position.quantity as f64 * market.prev_close;
|
||||
let signal_visible_price = if ctx.is_lagged_execution() && date == ctx.decision_date
|
||||
{
|
||||
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;
|
||||
}
|
||||
let target_cash = if self.config.aiquant_transaction_cost {
|
||||
fixed_buy_cash * stock_scale
|
||||
} else {
|
||||
let slot_buy_cash = self.remaining_buy_cash_per_slot(
|
||||
if self.config.aiquant_transaction_cost {
|
||||
let target_value = fixed_buy_cash * stock_scale;
|
||||
if target_value <= 0.0 {
|
||||
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,
|
||||
&projected,
|
||||
&mut projected,
|
||||
projection_date,
|
||||
target_budget,
|
||||
selection_limit,
|
||||
&rebalance_working_symbols,
|
||||
&rebalance_value_symbols,
|
||||
rebalance_pending_buy_value,
|
||||
&pending_full_close_symbols,
|
||||
symbol,
|
||||
target_value,
|
||||
&mut projected_execution_state,
|
||||
);
|
||||
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);
|
||||
if buy_cash <= 0.0 {
|
||||
if debug_projection {
|
||||
@@ -18579,6 +18620,11 @@ mod tests {
|
||||
OrderIntent::Value { symbol, value, .. } => {
|
||||
symbol == limit_symbol && *value > 0.0
|
||||
}
|
||||
OrderIntent::TargetValue {
|
||||
symbol,
|
||||
target_value,
|
||||
..
|
||||
} => symbol == limit_symbol && *target_value > 0.0,
|
||||
_ => false,
|
||||
}),
|
||||
"{:?}",
|
||||
@@ -18779,6 +18825,13 @@ mod tests {
|
||||
intent,
|
||||
OrderIntent::Value { symbol, value, .. }
|
||||
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
|
||||
@@ -25251,7 +25304,11 @@ mod tests {
|
||||
.filter(|intent| {
|
||||
matches!(
|
||||
intent,
|
||||
OrderIntent::Value { reason, .. } if reason == "periodic_rebalance_buy"
|
||||
OrderIntent::TargetValue {
|
||||
target_value,
|
||||
reason,
|
||||
..
|
||||
} if *target_value > 0.0 && reason == "periodic_rebalance_buy"
|
||||
)
|
||||
})
|
||||
.count();
|
||||
@@ -25429,8 +25486,13 @@ mod tests {
|
||||
assert!(
|
||||
!decision.order_intents.iter().any(|intent| matches!(
|
||||
intent,
|
||||
OrderIntent::Value { symbol, reason, .. }
|
||||
if symbol == "000001.SZ" && reason == "periodic_rebalance_buy"
|
||||
OrderIntent::TargetValue {
|
||||
symbol,
|
||||
target_value,
|
||||
reason,
|
||||
} if symbol == "000001.SZ"
|
||||
&& *target_value > 0.0
|
||||
&& reason == "periodic_rebalance_buy"
|
||||
)),
|
||||
"{:?}",
|
||||
decision.order_intents
|
||||
@@ -25438,8 +25500,13 @@ mod tests {
|
||||
assert!(
|
||||
decision.order_intents.iter().any(|intent| matches!(
|
||||
intent,
|
||||
OrderIntent::Value { symbol, reason, .. }
|
||||
if symbol == "000003.SZ" && reason == "periodic_rebalance_buy"
|
||||
OrderIntent::TargetValue {
|
||||
symbol,
|
||||
target_value,
|
||||
reason,
|
||||
} if symbol == "000003.SZ"
|
||||
&& *target_value > 0.0
|
||||
&& reason == "periodic_rebalance_buy"
|
||||
)),
|
||||
"{:?}",
|
||||
decision.order_intents
|
||||
@@ -25629,7 +25696,11 @@ mod tests {
|
||||
.filter(|intent| {
|
||||
matches!(
|
||||
intent,
|
||||
OrderIntent::Value { reason, .. } if reason == "periodic_rebalance_buy"
|
||||
OrderIntent::TargetValue {
|
||||
target_value,
|
||||
reason,
|
||||
..
|
||||
} if *target_value > 0.0 && reason == "periodic_rebalance_buy"
|
||||
)
|
||||
})
|
||||
.count();
|
||||
@@ -25650,8 +25721,12 @@ mod tests {
|
||||
.order_intents
|
||||
.iter()
|
||||
.filter_map(|intent| match intent {
|
||||
OrderIntent::Value { value, reason, .. } if reason == "periodic_rebalance_buy" => {
|
||||
Some(*value)
|
||||
OrderIntent::TargetValue {
|
||||
target_value,
|
||||
reason,
|
||||
..
|
||||
} if *target_value > 0.0 && reason == "periodic_rebalance_buy" => {
|
||||
Some(*target_value)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
@@ -25660,18 +25735,10 @@ mod tests {
|
||||
assert!(
|
||||
periodic_buy_values
|
||||
.iter()
|
||||
.take(periodic_buy_values.len().saturating_sub(1))
|
||||
.all(|value| (*value - equal_weight_target).abs() < 1e-6),
|
||||
"{:?}",
|
||||
decision.order_intents
|
||||
);
|
||||
assert!(
|
||||
periodic_buy_values
|
||||
.last()
|
||||
.is_some_and(|value| *value > 0.0 && *value <= equal_weight_target),
|
||||
"{:?}",
|
||||
decision.order_intents
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -25819,13 +25886,13 @@ mod tests {
|
||||
assert!(
|
||||
decision.order_intents.iter().any(|intent| matches!(
|
||||
intent,
|
||||
OrderIntent::Value {
|
||||
OrderIntent::TargetValue {
|
||||
symbol,
|
||||
value,
|
||||
target_value,
|
||||
reason,
|
||||
} if symbol == "000002.SZ"
|
||||
&& reason == "periodic_rebalance_buy"
|
||||
&& (*value - 10_000.0).abs() < 1e-6
|
||||
&& (*target_value - 10_000.0).abs() < 1e-6
|
||||
)),
|
||||
"{:?}",
|
||||
decision.order_intents
|
||||
|
||||
Reference in New Issue
Block a user