修复ALV日内补仓循环次数
This commit is contained in:
@@ -2241,7 +2241,7 @@ impl PlatformExprStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn try_daily_top_up_once(
|
fn try_daily_top_up_at_position(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &StrategyContext<'_>,
|
ctx: &StrategyContext<'_>,
|
||||||
day: &DayExpressionState,
|
day: &DayExpressionState,
|
||||||
@@ -2274,136 +2274,147 @@ impl PlatformExprStrategy {
|
|||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut budget_working_symbols = slot_working_symbols.clone();
|
let mut submitted_any = false;
|
||||||
budget_working_symbols.extend(same_bar_buy_symbols.iter().cloned());
|
loop {
|
||||||
if Self::effective_slot_count(&budget_working_symbols, pending_full_close_symbols)
|
let mut budget_working_symbols = slot_working_symbols.clone();
|
||||||
>= selection_limit
|
budget_working_symbols.extend(same_bar_buy_symbols.iter().cloned());
|
||||||
{
|
if Self::effective_slot_count(&budget_working_symbols, pending_full_close_symbols)
|
||||||
return Ok(false);
|
>= selection_limit
|
||||||
}
|
{
|
||||||
let value_symbols = budget_working_symbols.clone();
|
break;
|
||||||
let active_value = if debug_daily_top_up {
|
}
|
||||||
self.remaining_buy_cash_active_value(
|
let value_symbols = budget_working_symbols.clone();
|
||||||
|
let active_value = if debug_daily_top_up {
|
||||||
|
self.remaining_buy_cash_active_value(
|
||||||
|
ctx,
|
||||||
|
projected,
|
||||||
|
projection_date,
|
||||||
|
&budget_working_symbols,
|
||||||
|
&value_symbols,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
let slot_buy_cash = self.remaining_buy_cash_per_slot(
|
||||||
ctx,
|
ctx,
|
||||||
projected,
|
projected,
|
||||||
projection_date,
|
projection_date,
|
||||||
|
target_budget,
|
||||||
|
selection_limit,
|
||||||
&budget_working_symbols,
|
&budget_working_symbols,
|
||||||
&value_symbols,
|
&value_symbols,
|
||||||
)
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
};
|
|
||||||
let slot_buy_cash = self.remaining_buy_cash_per_slot(
|
|
||||||
ctx,
|
|
||||||
projected,
|
|
||||||
projection_date,
|
|
||||||
target_budget,
|
|
||||||
selection_limit,
|
|
||||||
&budget_working_symbols,
|
|
||||||
&value_symbols,
|
|
||||||
*pending_buy_value,
|
|
||||||
pending_full_close_symbols,
|
|
||||||
);
|
|
||||||
let available_buy_cash = slot_buy_cash.min(*aiquant_available_cash);
|
|
||||||
if debug_daily_top_up {
|
|
||||||
daily_top_up_debug_notes.push(format!(
|
|
||||||
"daily_top_up_budget date={} working={} value_symbols={} same_bar_buys={} active_value={:.4} pending_buy_value={:.4} target_budget={:.4} slot_buy_cash={:.4} available_cash={:.4} portfolio_cash={:.4}",
|
|
||||||
execution_date,
|
|
||||||
budget_working_symbols.len(),
|
|
||||||
value_symbols.len(),
|
|
||||||
same_bar_buy_symbols.len(),
|
|
||||||
active_value,
|
|
||||||
*pending_buy_value,
|
*pending_buy_value,
|
||||||
target_budget,
|
pending_full_close_symbols,
|
||||||
slot_buy_cash,
|
|
||||||
available_buy_cash,
|
|
||||||
*aiquant_available_cash
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if slot_buy_cash <= 0.0 || available_buy_cash < slot_buy_cash * 0.5 {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
for symbol in stock_list {
|
|
||||||
if current_position_symbol
|
|
||||||
.map(|current| current == symbol)
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let released_exit_position = projected.positions().contains_key(symbol)
|
|
||||||
&& !slot_working_symbols.contains(symbol)
|
|
||||||
&& !same_day_sold_symbols.contains(symbol)
|
|
||||||
&& !pending_full_close_symbols.contains(symbol);
|
|
||||||
if (projected.positions().contains_key(symbol) && !released_exit_position)
|
|
||||||
|| same_day_sold_symbols.contains(symbol)
|
|
||||||
|| (exit_symbols.contains(symbol) && !released_exit_position)
|
|
||||||
|| pending_full_close_symbols.contains(symbol)
|
|
||||||
|| delayed_sold_symbols.contains(symbol)
|
|
||||||
|| intraday_attempted_buys.contains(symbol)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if !defer_execution_risk
|
|
||||||
&& self
|
|
||||||
.buy_rejection_reason(
|
|
||||||
ctx,
|
|
||||||
execution_date,
|
|
||||||
symbol,
|
|
||||||
&self.stock_state(ctx, execution_date, symbol)?,
|
|
||||||
)?
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let decision_stock = self.stock_state_with_factor_date(
|
|
||||||
ctx,
|
|
||||||
decision_date,
|
|
||||||
selection_factor_date,
|
|
||||||
symbol,
|
|
||||||
)?;
|
|
||||||
let buy_cash = available_buy_cash * self.buy_scale(ctx, day, &decision_stock)?;
|
|
||||||
if buy_cash <= 0.0 {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
intraday_attempted_buys.insert(symbol.clone());
|
|
||||||
let cash_before_buy = projected.cash();
|
|
||||||
let order_result = self.project_order_value(
|
|
||||||
ctx,
|
|
||||||
projected,
|
|
||||||
projection_date,
|
|
||||||
symbol,
|
|
||||||
buy_cash,
|
|
||||||
projected_execution_state,
|
|
||||||
);
|
);
|
||||||
if order_result.was_submitted() {
|
let available_buy_cash = slot_buy_cash.min(*aiquant_available_cash);
|
||||||
order_intents.push(OrderIntent::Value {
|
if debug_daily_top_up {
|
||||||
symbol: symbol.clone(),
|
daily_top_up_debug_notes.push(format!(
|
||||||
value: buy_cash,
|
"daily_top_up_budget date={} working={} value_symbols={} same_bar_buys={} active_value={:.4} pending_buy_value={:.4} target_budget={:.4} slot_buy_cash={:.4} available_cash={:.4} portfolio_cash={:.4}",
|
||||||
reason: "daily_top_up_buy".to_string(),
|
execution_date,
|
||||||
});
|
budget_working_symbols.len(),
|
||||||
self.remember_position_entry_date(symbol, signal_date);
|
value_symbols.len(),
|
||||||
let spent = (cash_before_buy - projected.cash()).max(0.0);
|
same_bar_buy_symbols.len(),
|
||||||
*aiquant_available_cash = (*aiquant_available_cash - spent).max(0.0);
|
active_value,
|
||||||
slot_working_symbols.insert(symbol.clone());
|
*pending_buy_value,
|
||||||
same_bar_buy_symbols.insert(symbol.clone());
|
target_budget,
|
||||||
*pending_buy_value += available_buy_cash;
|
slot_buy_cash,
|
||||||
if debug_daily_top_up {
|
available_buy_cash,
|
||||||
daily_top_up_debug_notes.push(format!(
|
*aiquant_available_cash
|
||||||
"daily_top_up_fill date={} symbol={} requested_cash={:.4} filled_qty={} spent={:.4} remaining_cash={:.4}",
|
));
|
||||||
execution_date,
|
}
|
||||||
symbol,
|
if slot_buy_cash <= 0.0 || available_buy_cash < slot_buy_cash * 0.5 {
|
||||||
buy_cash,
|
break;
|
||||||
order_result.filled_quantity,
|
}
|
||||||
spent,
|
|
||||||
*aiquant_available_cash
|
let mut attempted_any = false;
|
||||||
));
|
let mut filled_any = false;
|
||||||
|
for symbol in stock_list {
|
||||||
|
if current_position_symbol
|
||||||
|
.map(|current| current == symbol)
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
return Ok(true);
|
let released_exit_position = projected.positions().contains_key(symbol)
|
||||||
|
&& !slot_working_symbols.contains(symbol)
|
||||||
|
&& !same_day_sold_symbols.contains(symbol)
|
||||||
|
&& !pending_full_close_symbols.contains(symbol);
|
||||||
|
if (projected.positions().contains_key(symbol) && !released_exit_position)
|
||||||
|
|| same_day_sold_symbols.contains(symbol)
|
||||||
|
|| (exit_symbols.contains(symbol) && !released_exit_position)
|
||||||
|
|| pending_full_close_symbols.contains(symbol)
|
||||||
|
|| delayed_sold_symbols.contains(symbol)
|
||||||
|
|| intraday_attempted_buys.contains(symbol)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !defer_execution_risk
|
||||||
|
&& self
|
||||||
|
.buy_rejection_reason(
|
||||||
|
ctx,
|
||||||
|
execution_date,
|
||||||
|
symbol,
|
||||||
|
&self.stock_state(ctx, execution_date, symbol)?,
|
||||||
|
)?
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let decision_stock = self.stock_state_with_factor_date(
|
||||||
|
ctx,
|
||||||
|
decision_date,
|
||||||
|
selection_factor_date,
|
||||||
|
symbol,
|
||||||
|
)?;
|
||||||
|
let buy_cash = available_buy_cash * self.buy_scale(ctx, day, &decision_stock)?;
|
||||||
|
if buy_cash <= 0.0 {
|
||||||
|
return Ok(submitted_any);
|
||||||
|
}
|
||||||
|
intraday_attempted_buys.insert(symbol.clone());
|
||||||
|
attempted_any = true;
|
||||||
|
let cash_before_buy = projected.cash();
|
||||||
|
let order_result = self.project_order_value(
|
||||||
|
ctx,
|
||||||
|
projected,
|
||||||
|
projection_date,
|
||||||
|
symbol,
|
||||||
|
buy_cash,
|
||||||
|
projected_execution_state,
|
||||||
|
);
|
||||||
|
if order_result.was_submitted() {
|
||||||
|
order_intents.push(OrderIntent::Value {
|
||||||
|
symbol: symbol.clone(),
|
||||||
|
value: buy_cash,
|
||||||
|
reason: "daily_top_up_buy".to_string(),
|
||||||
|
});
|
||||||
|
self.remember_position_entry_date(symbol, signal_date);
|
||||||
|
let spent = (cash_before_buy - projected.cash()).max(0.0);
|
||||||
|
*aiquant_available_cash = (*aiquant_available_cash - spent).max(0.0);
|
||||||
|
slot_working_symbols.insert(symbol.clone());
|
||||||
|
same_bar_buy_symbols.insert(symbol.clone());
|
||||||
|
*pending_buy_value += available_buy_cash;
|
||||||
|
if debug_daily_top_up {
|
||||||
|
daily_top_up_debug_notes.push(format!(
|
||||||
|
"daily_top_up_fill date={} symbol={} requested_cash={:.4} filled_qty={} spent={:.4} remaining_cash={:.4}",
|
||||||
|
execution_date,
|
||||||
|
symbol,
|
||||||
|
buy_cash,
|
||||||
|
order_result.filled_quantity,
|
||||||
|
spent,
|
||||||
|
*aiquant_available_cash
|
||||||
|
));
|
||||||
|
}
|
||||||
|
submitted_any = true;
|
||||||
|
filled_any = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !attempted_any || !filled_any {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(false)
|
Ok(submitted_any)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn effective_slot_count(
|
fn effective_slot_count(
|
||||||
@@ -8697,7 +8708,7 @@ impl Strategy for PlatformExprStrategy {
|
|||||||
unresolved_stop_loss_symbols.insert(position.symbol.clone());
|
unresolved_stop_loss_symbols.insert(position.symbol.clone());
|
||||||
}
|
}
|
||||||
if daily_top_up_active {
|
if daily_top_up_active {
|
||||||
self.try_daily_top_up_once(
|
self.try_daily_top_up_at_position(
|
||||||
ctx,
|
ctx,
|
||||||
&day,
|
&day,
|
||||||
&stock_list,
|
&stock_list,
|
||||||
@@ -8762,7 +8773,7 @@ impl Strategy for PlatformExprStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if daily_top_up_active {
|
if daily_top_up_active {
|
||||||
self.try_daily_top_up_once(
|
self.try_daily_top_up_at_position(
|
||||||
ctx,
|
ctx,
|
||||||
&day,
|
&day,
|
||||||
&stock_list,
|
&stock_list,
|
||||||
|
|||||||
Reference in New Issue
Block a user