修正满仓后既有目标调仓中断
This commit is contained in:
@@ -10606,7 +10606,9 @@ impl Strategy for PlatformExprStrategy {
|
||||
continue;
|
||||
}
|
||||
if rebalance_working_symbols.len() >= selection_limit {
|
||||
break;
|
||||
// New symbols cannot consume another slot, but later ranked symbols may
|
||||
// already be held and still require a target-value adjustment.
|
||||
continue;
|
||||
}
|
||||
if ((pre_rebalance_symbols.contains(symbol)
|
||||
|| projected.positions().contains_key(symbol))
|
||||
@@ -11072,7 +11074,7 @@ mod tests {
|
||||
let previous_date = d(2025, 1, 2);
|
||||
let execution_date = d(2025, 1, 3);
|
||||
let unresolved_symbol = "000999.SZ";
|
||||
let active_symbols = ["000001.SZ", "000002.SZ"];
|
||||
let active_symbols = ["000001.SZ", "000002.SZ", "000003.SZ"];
|
||||
let data = DataSet::from_components(
|
||||
std::iter::once(Instrument {
|
||||
symbol: unresolved_symbol.to_string(),
|
||||
@@ -11164,6 +11166,9 @@ mod tests {
|
||||
portfolio
|
||||
.position_mut(unresolved_symbol)
|
||||
.buy(previous_date, 1_000, 10.0);
|
||||
portfolio
|
||||
.position_mut("000003.SZ")
|
||||
.buy(previous_date, 100, 10.0);
|
||||
let subscriptions = BTreeSet::new();
|
||||
let before_delisting_ctx = StrategyContext {
|
||||
execution_date: previous_date,
|
||||
@@ -11205,21 +11210,28 @@ mod tests {
|
||||
let mut cfg = PlatformExprStrategyConfig::microcap_rotation();
|
||||
cfg.signal_symbol = "000001.SZ".to_string();
|
||||
cfg.refresh_rate = 1;
|
||||
cfg.max_positions = 2;
|
||||
cfg.max_positions = 3;
|
||||
cfg.benchmark_short_ma_days = 1;
|
||||
cfg.benchmark_long_ma_days = 1;
|
||||
cfg.market_cap_lower_expr = "0".to_string();
|
||||
cfg.market_cap_upper_expr = "100".to_string();
|
||||
cfg.selection_limit_expr = "2".to_string();
|
||||
cfg.selection_limit_expr = "3".to_string();
|
||||
cfg.stock_filter_expr = "close > 0".to_string();
|
||||
cfg.stop_loss_expr.clear();
|
||||
cfg.take_profit_expr.clear();
|
||||
cfg.aiquant_transaction_cost = true;
|
||||
cfg.daily_replacement_limit = 2;
|
||||
cfg.daily_replacement_limit = 3;
|
||||
cfg.selection_buffer_multiple = 2.0;
|
||||
cfg.rebalance_existing_positions = false;
|
||||
let mut strategy = PlatformExprStrategy::new(cfg);
|
||||
strategy.rebalance_day_counter = 1;
|
||||
strategy.last_trading_ratio = Some(0.1);
|
||||
strategy.last_target_selection = Some(
|
||||
active_symbols
|
||||
.iter()
|
||||
.map(|symbol| (*symbol).to_string())
|
||||
.collect(),
|
||||
);
|
||||
|
||||
let decision = strategy.on_day(&ctx).expect("platform decision");
|
||||
|
||||
@@ -11233,7 +11245,9 @@ mod tests {
|
||||
decision
|
||||
.diagnostics
|
||||
.iter()
|
||||
.any(|note| note == "selected_symbols=000001.SZ,000002.SZ")
|
||||
.any(|note| note == "selected_symbols=000001.SZ,000002.SZ,000003.SZ"),
|
||||
"{:?}",
|
||||
decision.diagnostics
|
||||
);
|
||||
assert!(!decision.order_intents.iter().any(|intent| {
|
||||
matches!(
|
||||
@@ -11265,6 +11279,18 @@ mod tests {
|
||||
&& reason == "periodic_rebalance_buy"
|
||||
)
|
||||
}));
|
||||
assert!(decision.order_intents.iter().any(|intent| {
|
||||
matches!(
|
||||
intent,
|
||||
OrderIntent::TargetValue {
|
||||
symbol,
|
||||
target_value,
|
||||
reason,
|
||||
} if symbol == "000003.SZ"
|
||||
&& *target_value > 0.0
|
||||
&& reason == "periodic_rebalance_target_adjust"
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user