统一次日开盘新仓目标市值指令
This commit is contained in:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user