修复表达式策略next-open风控日期语义
This commit is contained in:
@@ -4915,6 +4915,7 @@ impl PlatformExprStrategy {
|
||||
};
|
||||
let selection_date = if self.config.aiquant_transaction_cost
|
||||
&& self.config.intraday_execution_time.is_some()
|
||||
&& !ctx.is_lagged_execution()
|
||||
{
|
||||
ctx.execution_date
|
||||
} else {
|
||||
@@ -5756,9 +5757,10 @@ impl PlatformExprStrategy {
|
||||
&self,
|
||||
ctx: &StrategyContext<'_>,
|
||||
) -> Result<StrategyDecision, BacktestError> {
|
||||
let day = self.day_state(ctx, ctx.execution_date)?;
|
||||
let decision_date = ctx.decision_date;
|
||||
let day = self.day_state(ctx, decision_date)?;
|
||||
let (order_intents, action_diagnostics) =
|
||||
self.explicit_action_intents(ctx, ctx.execution_date, &day)?;
|
||||
self.explicit_action_intents(ctx, decision_date, &day)?;
|
||||
let mut diagnostics = vec![format!(
|
||||
"platform_expr signal={} last={:.2} explicit_actions={} stage={}",
|
||||
self.config.signal_symbol,
|
||||
@@ -5921,7 +5923,8 @@ impl PlatformExprStrategy {
|
||||
let Some(market) = ctx.data.market(date, &factor.symbol) else {
|
||||
continue;
|
||||
};
|
||||
if self
|
||||
if !ctx.is_lagged_execution()
|
||||
&& self
|
||||
.selection_risk_rejection_reason(ctx, date, &factor.symbol, candidate, market)
|
||||
.is_some()
|
||||
{
|
||||
@@ -5956,6 +5959,9 @@ impl PlatformExprStrategy {
|
||||
date: NaiveDate,
|
||||
factor_date: NaiveDate,
|
||||
) -> Vec<FidcRiskDecisionAudit> {
|
||||
if ctx.is_lagged_execution() {
|
||||
return Vec::new();
|
||||
}
|
||||
let mut decisions = Vec::new();
|
||||
for factor in ctx.data.factor_snapshots_on(factor_date) {
|
||||
if ctx.has_dynamic_universe() && !ctx.dynamic_universe_contains(&factor.symbol) {
|
||||
@@ -6401,13 +6407,18 @@ impl PlatformExprStrategy {
|
||||
|
||||
let mut selected = Vec::new();
|
||||
for (candidate, stock, _) in candidates {
|
||||
if let Some(reason) = self.stock_selection_limit_rejection_reason(&stock) {
|
||||
if !ctx.is_lagged_execution()
|
||||
&& let Some(reason) = self.stock_selection_limit_rejection_reason(&stock)
|
||||
{
|
||||
if diagnostics.len() < 12 {
|
||||
diagnostics.push(format!("{} rejected by {}", candidate.symbol, reason));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if let Some(reason) = self.buy_rejection_reason(ctx, date, &candidate.symbol, &stock)? {
|
||||
if !ctx.is_lagged_execution()
|
||||
&& let Some(reason) =
|
||||
self.buy_rejection_reason(ctx, date, &candidate.symbol, &stock)?
|
||||
{
|
||||
if diagnostics.len() < 12 {
|
||||
diagnostics.push(format!("{} rejected by {}", candidate.symbol, reason));
|
||||
}
|
||||
@@ -7083,13 +7094,17 @@ impl PlatformExprStrategy {
|
||||
if quote_candidate_symbols.len() < quote_candidate_limit {
|
||||
quote_candidate_symbols.push(symbol.clone());
|
||||
}
|
||||
if let Some(reason) = self.stock_selection_limit_rejection_reason(stock) {
|
||||
if !ctx.is_lagged_execution()
|
||||
&& let Some(reason) = self.stock_selection_limit_rejection_reason(stock)
|
||||
{
|
||||
if diagnostics.len() < 12 {
|
||||
diagnostics.push(format!("{symbol} quote_plan rejected by {reason}"));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if let Some(reason) = self.buy_rejection_reason(ctx, date, symbol, &stock)? {
|
||||
if !ctx.is_lagged_execution()
|
||||
&& let Some(reason) = self.buy_rejection_reason(ctx, date, symbol, &stock)?
|
||||
{
|
||||
if diagnostics.len() < 12 {
|
||||
diagnostics.push(format!("{symbol} quote_plan rejected by {reason}"));
|
||||
}
|
||||
@@ -7123,11 +7138,11 @@ impl PlatformExprStrategy {
|
||||
ctx: &StrategyContext<'_>,
|
||||
_scope_limit: usize,
|
||||
) -> Result<PlatformSelectionQuotePlan, BacktestError> {
|
||||
if !self.config.rotation_enabled || self.config.in_skip_window(ctx.execution_date) {
|
||||
if !self.config.rotation_enabled || self.config.in_skip_window(ctx.decision_date) {
|
||||
return Ok(PlatformSelectionQuotePlan {
|
||||
execution_date: ctx.execution_date,
|
||||
decision_date: ctx.decision_date,
|
||||
selection_date: ctx.execution_date,
|
||||
selection_date: ctx.decision_date,
|
||||
factor_date: ctx.decision_date,
|
||||
requires_intraday_selection_quotes: false,
|
||||
band_low: 0.0,
|
||||
@@ -7178,21 +7193,21 @@ impl PlatformExprStrategy {
|
||||
fn stop_take_action(
|
||||
&self,
|
||||
ctx: &StrategyContext<'_>,
|
||||
_signal_date: NaiveDate,
|
||||
execution_date: NaiveDate,
|
||||
signal_date: NaiveDate,
|
||||
_execution_date: NaiveDate,
|
||||
day: &DayExpressionState,
|
||||
symbol: &str,
|
||||
) -> Result<(bool, bool), BacktestError> {
|
||||
let Some(position) = ctx.portfolio.position(symbol) else {
|
||||
return Ok((false, false));
|
||||
};
|
||||
self.stop_take_action_for_position(ctx, execution_date, day, position)
|
||||
self.stop_take_action_for_position(ctx, signal_date, day, position)
|
||||
}
|
||||
|
||||
fn stop_take_action_for_position(
|
||||
&self,
|
||||
ctx: &StrategyContext<'_>,
|
||||
execution_date: NaiveDate,
|
||||
signal_date: NaiveDate,
|
||||
day: &DayExpressionState,
|
||||
position: &crate::portfolio::Position,
|
||||
) -> Result<(bool, bool), BacktestError> {
|
||||
@@ -7219,7 +7234,7 @@ impl PlatformExprStrategy {
|
||||
}
|
||||
let stock = match self.stock_state_at_time(
|
||||
ctx,
|
||||
execution_date,
|
||||
signal_date,
|
||||
symbol,
|
||||
Some(self.intraday_execution_start_time()),
|
||||
) {
|
||||
@@ -7249,9 +7264,9 @@ impl PlatformExprStrategy {
|
||||
prev_close: stock.prev_close,
|
||||
holding_return,
|
||||
quantity: position.quantity as i64,
|
||||
sellable_qty: position.sellable_qty(execution_date) as i64,
|
||||
sellable: position.sellable_qty(execution_date) as i64,
|
||||
closable: position.sellable_qty(execution_date) as i64,
|
||||
sellable_qty: position.sellable_qty(signal_date) as i64,
|
||||
sellable: position.sellable_qty(signal_date) as i64,
|
||||
closable: position.sellable_qty(signal_date) as i64,
|
||||
old_quantity: position.day_start_quantity() as i64,
|
||||
bought_quantity: position.bought_quantity() as i64,
|
||||
sold_quantity: position.sold_quantity() as i64,
|
||||
@@ -7352,7 +7367,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
.filter(|symbol| !symbol.trim().is_empty())
|
||||
.cloned()
|
||||
.collect::<BTreeSet<_>>();
|
||||
if self.config.rotation_enabled && !self.config.in_skip_window(ctx.execution_date) {
|
||||
if self.config.rotation_enabled && !self.config.in_skip_window(ctx.decision_date) {
|
||||
let plan = self.selection_quote_plan(ctx, 0)?;
|
||||
symbols.extend(plan.order_symbols);
|
||||
symbols.extend(plan.candidate_symbols);
|
||||
@@ -7366,7 +7381,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
) -> Result<StrategyDecision, BacktestError> {
|
||||
if self.config.explicit_action_stage == PlatformExplicitActionStage::OpenAuction
|
||||
&& !self.config.explicit_actions.is_empty()
|
||||
&& self.explicit_actions_active(ctx.data.calendar(), ctx.execution_date)
|
||||
&& self.explicit_actions_active(ctx.data.calendar(), ctx.decision_date)
|
||||
{
|
||||
return self.explicit_action_decision(ctx);
|
||||
}
|
||||
@@ -7376,14 +7391,21 @@ impl Strategy for PlatformExprStrategy {
|
||||
fn on_day(&mut self, ctx: &StrategyContext<'_>) -> Result<StrategyDecision, BacktestError> {
|
||||
let execution_date = ctx.execution_date;
|
||||
let decision_date = ctx.decision_date;
|
||||
let in_skip_window = self.config.in_skip_window(execution_date);
|
||||
let defer_execution_risk = ctx.is_lagged_execution();
|
||||
let signal_date = decision_date;
|
||||
let projection_date = if defer_execution_risk {
|
||||
signal_date
|
||||
} else {
|
||||
execution_date
|
||||
};
|
||||
let in_skip_window = self.config.in_skip_window(signal_date);
|
||||
|
||||
let day = self.day_state(ctx, decision_date)?;
|
||||
let (selection_market_date, selection_universe_factor_date, selection_factor_date) =
|
||||
self.selection_dates(ctx);
|
||||
let (explicit_action_intents, explicit_action_diagnostics) = if !in_skip_window
|
||||
&& self.config.explicit_action_stage == PlatformExplicitActionStage::OnDay
|
||||
&& self.explicit_actions_active(ctx.data.calendar(), execution_date)
|
||||
&& self.explicit_actions_active(ctx.data.calendar(), signal_date)
|
||||
{
|
||||
self.explicit_action_intents(ctx, decision_date, &day)?
|
||||
} else {
|
||||
@@ -7398,7 +7420,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
let previous_trading_ratio = self.last_trading_ratio.unwrap_or(1.0);
|
||||
let weak_market_shrink_due =
|
||||
trading_ratio.is_finite() && trading_ratio < previous_trading_ratio - 1e-9;
|
||||
let marked_total_value = self.marked_total_value(ctx, execution_date);
|
||||
let marked_total_value = self.marked_total_value(ctx, projection_date);
|
||||
let mut aiquant_total_value = if marked_total_value.is_finite() && marked_total_value > 0.0
|
||||
{
|
||||
marked_total_value
|
||||
@@ -7445,14 +7467,14 @@ impl Strategy for PlatformExprStrategy {
|
||||
} else if let Some(schedule) = &self.config.rebalance_schedule {
|
||||
schedule.matches(
|
||||
ctx.data.calendar(),
|
||||
execution_date,
|
||||
signal_date,
|
||||
ScheduleStage::OnDay,
|
||||
default_stage_time(ScheduleStage::OnDay),
|
||||
) || empty_rebalance_retry
|
||||
} else if self.config.calendar_rebalance_interval {
|
||||
self.last_rebalance_date
|
||||
.map(|last| {
|
||||
execution_date.signed_duration_since(last).num_days()
|
||||
signal_date.signed_duration_since(last).num_days()
|
||||
>= effective_refresh_rate as i64
|
||||
})
|
||||
.unwrap_or(true)
|
||||
@@ -7489,7 +7511,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
}
|
||||
match self.stock_is_at_upper_limit_at_time(
|
||||
ctx,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&position.symbol,
|
||||
delayed_limit_exit_time,
|
||||
)? {
|
||||
@@ -7517,7 +7539,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
if self
|
||||
.aiquant_scheduled_quote_at_time(
|
||||
ctx,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&symbol,
|
||||
Some(delayed_limit_exit_time),
|
||||
)
|
||||
@@ -7527,7 +7549,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
}
|
||||
let stock = match self.stock_state_at_time(
|
||||
ctx,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&symbol,
|
||||
Some(delayed_limit_exit_time),
|
||||
) {
|
||||
@@ -7559,7 +7581,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
});
|
||||
let projected_sold = if ctx
|
||||
.data
|
||||
.execution_quotes_on(execution_date, &symbol)
|
||||
.execution_quotes_on(projection_date, &symbol)
|
||||
.is_empty()
|
||||
{
|
||||
false
|
||||
@@ -7567,7 +7589,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
self.project_target_zero_at_time(
|
||||
ctx,
|
||||
&mut projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&symbol,
|
||||
&mut projected_execution_state,
|
||||
Some(delayed_limit_exit_time),
|
||||
@@ -7583,7 +7605,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
}
|
||||
if !delayed_sold_symbols.is_empty() {
|
||||
let projected_total =
|
||||
self.marked_total_value_for_portfolio(ctx, &projected, execution_date);
|
||||
self.marked_total_value_for_portfolio(ctx, &projected, projection_date);
|
||||
if projected_total.is_finite() && projected_total > 0.0 {
|
||||
aiquant_total_value = projected_total;
|
||||
}
|
||||
@@ -7608,7 +7630,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
reason: "seasonal_stop_window".to_string(),
|
||||
});
|
||||
}
|
||||
let mut notes = vec![format!("seasonal stop window on {}", execution_date)];
|
||||
let mut notes = vec![format!("seasonal stop window on {}", signal_date)];
|
||||
if !delayed_sold_symbols.is_empty() {
|
||||
notes.push(format!(
|
||||
"delayed limit open sells before seasonal stop: {}",
|
||||
@@ -7659,7 +7681,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
}
|
||||
if self.regular_sell_should_wait_due_to_highlimit(
|
||||
ctx,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&position.symbol,
|
||||
self.intraday_execution_start_time(),
|
||||
)? {
|
||||
@@ -7667,7 +7689,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
}
|
||||
if self.candidate_requires_risk_level_forced_exit(
|
||||
ctx,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&position.symbol,
|
||||
risk_level_forced_exit_time,
|
||||
)? {
|
||||
@@ -7676,7 +7698,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
continue;
|
||||
}
|
||||
let (stop_hit, profit_hit) =
|
||||
self.stop_take_action_for_position(ctx, execution_date, &day, position)?;
|
||||
self.stop_take_action_for_position(ctx, signal_date, &day, position)?;
|
||||
if stop_hit {
|
||||
pending_full_close_symbols.insert(position.symbol.clone());
|
||||
continue;
|
||||
@@ -7685,14 +7707,15 @@ impl Strategy for PlatformExprStrategy {
|
||||
pending_full_close_symbols.insert(position.symbol.clone());
|
||||
continue;
|
||||
}
|
||||
let can_sell = self.can_sell_position(ctx, execution_date, &position.symbol);
|
||||
let can_sell = defer_execution_risk
|
||||
|| self.can_sell_position(ctx, execution_date, &position.symbol);
|
||||
if !can_sell {
|
||||
continue;
|
||||
}
|
||||
if self.config.delayed_limit_open_exit_enabled {
|
||||
let stock = match self.stock_state_at_time(
|
||||
ctx,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&position.symbol,
|
||||
Some(self.intraday_execution_start_time()),
|
||||
) {
|
||||
@@ -7726,7 +7749,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
.project_target_zero_at_time(
|
||||
ctx,
|
||||
&mut projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&symbol,
|
||||
&mut projected_execution_state,
|
||||
Some(risk_level_forced_exit_time),
|
||||
@@ -7755,7 +7778,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
}
|
||||
if self.regular_sell_should_wait_due_to_highlimit(
|
||||
ctx,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&position.symbol,
|
||||
self.intraday_execution_start_time(),
|
||||
)? {
|
||||
@@ -7767,7 +7790,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
let current_value = self.projected_position_value_at_execution_price(
|
||||
ctx,
|
||||
&projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&position.symbol,
|
||||
);
|
||||
if let Some(threshold) = self
|
||||
@@ -7788,7 +7811,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
self.project_target_value(
|
||||
ctx,
|
||||
&mut trial_projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&position.symbol,
|
||||
target_value,
|
||||
&mut trial_execution_state,
|
||||
@@ -7834,15 +7857,16 @@ impl Strategy for PlatformExprStrategy {
|
||||
}
|
||||
if self.regular_sell_should_wait_due_to_highlimit(
|
||||
ctx,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&position.symbol,
|
||||
self.intraday_execution_start_time(),
|
||||
)? {
|
||||
continue;
|
||||
}
|
||||
let (stop_hit, profit_hit) =
|
||||
self.stop_take_action_for_position(ctx, execution_date, &day, projected_position)?;
|
||||
let can_sell = self.can_sell_position(ctx, execution_date, &position.symbol);
|
||||
self.stop_take_action_for_position(ctx, signal_date, &day, projected_position)?;
|
||||
let can_sell = defer_execution_risk
|
||||
|| self.can_sell_position(ctx, execution_date, &position.symbol);
|
||||
if stop_hit {
|
||||
exit_symbols.insert(position.symbol.clone());
|
||||
order_intents.push(OrderIntent::TargetValue {
|
||||
@@ -7855,7 +7879,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
.project_target_zero(
|
||||
ctx,
|
||||
&mut projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&position.symbol,
|
||||
&mut projected_execution_state,
|
||||
)
|
||||
@@ -7883,7 +7907,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
.project_target_zero(
|
||||
ctx,
|
||||
&mut projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&position.symbol,
|
||||
&mut projected_execution_state,
|
||||
)
|
||||
@@ -7919,7 +7943,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
self.remaining_buy_cash_active_value(
|
||||
ctx,
|
||||
&projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
&working_symbols,
|
||||
&value_symbols,
|
||||
)
|
||||
@@ -7929,7 +7953,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
let slot_buy_cash = self.remaining_buy_cash_per_slot(
|
||||
ctx,
|
||||
&projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
target_budget,
|
||||
selection_limit,
|
||||
&working_symbols,
|
||||
@@ -7966,9 +7990,14 @@ impl Strategy for PlatformExprStrategy {
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let execution_stock = self.stock_state(ctx, execution_date, symbol)?;
|
||||
if self
|
||||
.buy_rejection_reason(ctx, execution_date, symbol, &execution_stock)?
|
||||
if !defer_execution_risk
|
||||
&& self
|
||||
.buy_rejection_reason(
|
||||
ctx,
|
||||
execution_date,
|
||||
symbol,
|
||||
&self.stock_state(ctx, execution_date, symbol)?,
|
||||
)?
|
||||
.is_some()
|
||||
{
|
||||
continue;
|
||||
@@ -7990,7 +8019,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
let filled_qty = self.project_order_value(
|
||||
ctx,
|
||||
&mut projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
symbol,
|
||||
buy_cash,
|
||||
&mut projected_execution_state,
|
||||
@@ -8041,13 +8070,13 @@ impl Strategy for PlatformExprStrategy {
|
||||
}
|
||||
if self.regular_sell_should_wait_due_to_highlimit(
|
||||
ctx,
|
||||
execution_date,
|
||||
projection_date,
|
||||
symbol,
|
||||
self.intraday_execution_start_time(),
|
||||
)? {
|
||||
continue;
|
||||
}
|
||||
if !self.can_sell_position(ctx, execution_date, symbol) {
|
||||
if !defer_execution_risk && !self.can_sell_position(ctx, execution_date, symbol) {
|
||||
continue;
|
||||
}
|
||||
order_intents.push(OrderIntent::TargetValue {
|
||||
@@ -8059,7 +8088,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
.project_target_zero(
|
||||
ctx,
|
||||
&mut projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
symbol,
|
||||
&mut projected_execution_state,
|
||||
)
|
||||
@@ -8109,16 +8138,21 @@ impl Strategy for PlatformExprStrategy {
|
||||
let current_value = self.projected_position_value_at_execution_price(
|
||||
ctx,
|
||||
&projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
symbol,
|
||||
);
|
||||
let buy_cash = (target_cash - current_value).min(aiquant_available_cash);
|
||||
if buy_cash <= 0.0 {
|
||||
continue;
|
||||
}
|
||||
let execution_stock = self.stock_state(ctx, execution_date, symbol)?;
|
||||
if self
|
||||
.buy_rejection_reason(ctx, execution_date, symbol, &execution_stock)?
|
||||
if !defer_execution_risk
|
||||
&& self
|
||||
.buy_rejection_reason(
|
||||
ctx,
|
||||
execution_date,
|
||||
symbol,
|
||||
&self.stock_state(ctx, execution_date, symbol)?,
|
||||
)?
|
||||
.is_some()
|
||||
{
|
||||
continue;
|
||||
@@ -8130,7 +8164,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
let filled_qty = self.project_order_value(
|
||||
ctx,
|
||||
&mut projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
symbol,
|
||||
buy_cash,
|
||||
&mut projected_execution_state,
|
||||
@@ -8164,7 +8198,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
let slot_buy_cash = self.remaining_buy_cash_per_slot(
|
||||
ctx,
|
||||
&projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
target_budget,
|
||||
selection_limit,
|
||||
&rebalance_working_symbols,
|
||||
@@ -8180,9 +8214,14 @@ impl Strategy for PlatformExprStrategy {
|
||||
if self.config.aiquant_transaction_cost && buy_cash < target_cash * 0.5 {
|
||||
break;
|
||||
}
|
||||
let execution_stock = self.stock_state(ctx, execution_date, symbol)?;
|
||||
if self
|
||||
.buy_rejection_reason(ctx, execution_date, symbol, &execution_stock)?
|
||||
if !defer_execution_risk
|
||||
&& self
|
||||
.buy_rejection_reason(
|
||||
ctx,
|
||||
execution_date,
|
||||
symbol,
|
||||
&self.stock_state(ctx, execution_date, symbol)?,
|
||||
)?
|
||||
.is_some()
|
||||
{
|
||||
continue;
|
||||
@@ -8194,7 +8233,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
let filled_qty = self.project_order_value(
|
||||
ctx,
|
||||
&mut projected,
|
||||
execution_date,
|
||||
projection_date,
|
||||
symbol,
|
||||
buy_cash,
|
||||
&mut projected_execution_state,
|
||||
@@ -8216,7 +8255,7 @@ impl Strategy for PlatformExprStrategy {
|
||||
if self.config.rotation_enabled && self.config.rebalance_schedule.is_none() {
|
||||
if self.config.calendar_rebalance_interval {
|
||||
if periodic_rebalance {
|
||||
self.last_rebalance_date = Some(execution_date);
|
||||
self.last_rebalance_date = Some(signal_date);
|
||||
}
|
||||
} else if periodic_rebalance {
|
||||
self.rebalance_day_counter = 1;
|
||||
@@ -13945,7 +13984,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn platform_aiquant_intraday_selection_filters_limits_on_execution_date() {
|
||||
fn platform_next_open_selection_ignores_execution_day_limit_state() {
|
||||
let factor_date = d(2023, 11, 10);
|
||||
let decision_date = d(2023, 11, 13);
|
||||
let execution_date = d(2023, 11, 14);
|
||||
@@ -14186,7 +14225,7 @@ mod tests {
|
||||
decision
|
||||
.diagnostics
|
||||
.iter()
|
||||
.any(|item| item.contains("selection_market_date=2023-11-14")),
|
||||
.any(|item| item.contains("selection_market_date=2023-11-13")),
|
||||
"{:?}",
|
||||
decision.diagnostics
|
||||
);
|
||||
@@ -14202,7 +14241,7 @@ mod tests {
|
||||
decision
|
||||
.diagnostics
|
||||
.iter()
|
||||
.any(|item| item == "selected_symbols=000002.SZ"),
|
||||
.any(|item| item == "selected_symbols=600462.SH"),
|
||||
"{:?}",
|
||||
decision.diagnostics
|
||||
);
|
||||
@@ -14210,7 +14249,7 @@ mod tests {
|
||||
decision
|
||||
.diagnostics
|
||||
.iter()
|
||||
.any(|item| item == "600462.SH rejected by upper_limit"),
|
||||
.all(|item| item != "600462.SH rejected by upper_limit"),
|
||||
"{:?}",
|
||||
decision.diagnostics
|
||||
);
|
||||
@@ -14218,9 +14257,9 @@ mod tests {
|
||||
decision.order_intents.iter().any(|intent| match intent {
|
||||
OrderIntent::Shares {
|
||||
symbol, quantity, ..
|
||||
} => symbol == fallback_symbol && *quantity > 0,
|
||||
} => symbol == limit_symbol && *quantity > 0,
|
||||
OrderIntent::Value { symbol, value, .. } => {
|
||||
symbol == fallback_symbol && *value > 0.0
|
||||
symbol == limit_symbol && *value > 0.0
|
||||
}
|
||||
_ => false,
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user