区分股票池退出后重新入场
This commit is contained in:
@@ -653,6 +653,7 @@ pub struct PlatformExprStrategyConfig {
|
|||||||
pub delayed_limit_open_exit_time: Option<NaiveTime>,
|
pub delayed_limit_open_exit_time: Option<NaiveTime>,
|
||||||
pub release_slot_on_exit_signal: bool,
|
pub release_slot_on_exit_signal: bool,
|
||||||
pub redistribute_target_weights_after_exit: bool,
|
pub redistribute_target_weights_after_exit: bool,
|
||||||
|
pub reenter_exited_targets: bool,
|
||||||
pub explicit_action_stage: PlatformExplicitActionStage,
|
pub explicit_action_stage: PlatformExplicitActionStage,
|
||||||
pub explicit_action_schedule: Option<PlatformRebalanceSchedule>,
|
pub explicit_action_schedule: Option<PlatformRebalanceSchedule>,
|
||||||
pub subscription_guard_required: bool,
|
pub subscription_guard_required: bool,
|
||||||
@@ -729,6 +730,7 @@ impl PlatformExprStrategyConfig {
|
|||||||
delayed_limit_open_exit_time: None,
|
delayed_limit_open_exit_time: None,
|
||||||
release_slot_on_exit_signal: false,
|
release_slot_on_exit_signal: false,
|
||||||
redistribute_target_weights_after_exit: false,
|
redistribute_target_weights_after_exit: false,
|
||||||
|
reenter_exited_targets: false,
|
||||||
explicit_action_stage: PlatformExplicitActionStage::OnDay,
|
explicit_action_stage: PlatformExplicitActionStage::OnDay,
|
||||||
explicit_action_schedule: None,
|
explicit_action_schedule: None,
|
||||||
subscription_guard_required: false,
|
subscription_guard_required: false,
|
||||||
@@ -2436,11 +2438,13 @@ impl PlatformExprStrategy {
|
|||||||
self.position_entry_dates.remove(symbol);
|
self.position_entry_dates.remove(symbol);
|
||||||
self.position_holding_days.remove(symbol);
|
self.position_holding_days.remove(symbol);
|
||||||
self.position_holding_days_last_counted.remove(symbol);
|
self.position_holding_days_last_counted.remove(symbol);
|
||||||
if let Some(target_order) = &mut self.last_target_order {
|
if !self.config.reenter_exited_targets {
|
||||||
target_order.retain(|target| target != symbol);
|
if let Some(target_order) = &mut self.last_target_order {
|
||||||
}
|
target_order.retain(|target| target != symbol);
|
||||||
if let Some(target_selection) = &mut self.last_target_selection {
|
}
|
||||||
target_selection.remove(symbol);
|
if let Some(target_selection) = &mut self.last_target_selection {
|
||||||
|
target_selection.remove(symbol);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13863,6 +13867,35 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stock_pool_target_lifecycle_keeps_exits_for_next_day_reentry() {
|
||||||
|
let date = d(2025, 1, 3);
|
||||||
|
let mut config = PlatformExprStrategyConfig::generic();
|
||||||
|
config.reenter_exited_targets = true;
|
||||||
|
let mut strategy = PlatformExprStrategy::new(config);
|
||||||
|
strategy.last_target_order = Some(vec!["KEEP".to_string(), "EXITED".to_string()]);
|
||||||
|
strategy.last_target_selection =
|
||||||
|
Some(BTreeSet::from(["KEEP".to_string(), "EXITED".to_string()]));
|
||||||
|
strategy
|
||||||
|
.position_entry_dates
|
||||||
|
.insert("EXITED".to_string(), date);
|
||||||
|
|
||||||
|
strategy.forget_position_entry_date("EXITED");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
strategy.last_target_order.as_deref(),
|
||||||
|
Some(["KEEP".to_string(), "EXITED".to_string()].as_slice())
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
strategy
|
||||||
|
.last_target_selection
|
||||||
|
.as_ref()
|
||||||
|
.expect("target selection")
|
||||||
|
.contains("EXITED")
|
||||||
|
);
|
||||||
|
assert!(!strategy.position_entry_dates.contains_key("EXITED"));
|
||||||
|
}
|
||||||
|
|
||||||
fn single_symbol_platform_data(dates: &[NaiveDate], symbol: &str) -> DataSet {
|
fn single_symbol_platform_data(dates: &[NaiveDate], symbol: &str) -> DataSet {
|
||||||
DataSet::from_components(
|
DataSet::from_components(
|
||||||
vec![Instrument {
|
vec![Instrument {
|
||||||
|
|||||||
@@ -1022,6 +1022,8 @@ pub struct StrategyExpressionTradingConfig {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub redistribute_target_weights_after_exit: Option<bool>,
|
pub redistribute_target_weights_after_exit: Option<bool>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub reenter_exited_targets: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
pub subscription_guard_required: Option<bool>,
|
pub subscription_guard_required: Option<bool>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub subscriptions: Vec<String>,
|
pub subscriptions: Vec<String>,
|
||||||
@@ -2299,6 +2301,9 @@ pub fn platform_expr_config_from_spec(
|
|||||||
if let Some(enabled) = trading.redistribute_target_weights_after_exit {
|
if let Some(enabled) = trading.redistribute_target_weights_after_exit {
|
||||||
cfg.redistribute_target_weights_after_exit = enabled;
|
cfg.redistribute_target_weights_after_exit = enabled;
|
||||||
}
|
}
|
||||||
|
if let Some(enabled) = trading.reenter_exited_targets {
|
||||||
|
cfg.reenter_exited_targets = enabled;
|
||||||
|
}
|
||||||
if let Some(enabled) = trading.delayed_limit_open_exit {
|
if let Some(enabled) = trading.delayed_limit_open_exit {
|
||||||
cfg.delayed_limit_open_exit_enabled = enabled;
|
cfg.delayed_limit_open_exit_enabled = enabled;
|
||||||
if enabled {
|
if enabled {
|
||||||
@@ -3490,7 +3495,8 @@ mod tests {
|
|||||||
"rebalanceExistingPositions": true,
|
"rebalanceExistingPositions": true,
|
||||||
"holdUntilExit": true,
|
"holdUntilExit": true,
|
||||||
"releaseSlotOnExitSignal": true,
|
"releaseSlotOnExitSignal": true,
|
||||||
"redistributeTargetWeightsAfterExit": true
|
"redistributeTargetWeightsAfterExit": true,
|
||||||
|
"reenterExitedTargets": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -3505,6 +3511,7 @@ mod tests {
|
|||||||
assert!(cfg.hold_until_exit_enabled);
|
assert!(cfg.hold_until_exit_enabled);
|
||||||
assert!(cfg.release_slot_on_exit_signal);
|
assert!(cfg.release_slot_on_exit_signal);
|
||||||
assert!(cfg.redistribute_target_weights_after_exit);
|
assert!(cfg.redistribute_target_weights_after_exit);
|
||||||
|
assert!(cfg.reenter_exited_targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user