diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index dbc7860..6e635fd 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -7810,7 +7810,11 @@ impl Strategy for PlatformExprStrategy { let debug_daily_top_up = std::env::var("FIDC_BT_DEBUG_DAILY_TOP_UP") .map(|value| value == "1" || value.eq_ignore_ascii_case("true")) .unwrap_or(false); + let debug_projection = std::env::var("FIDC_BT_DEBUG_PLATFORM_PROJECTION") + .map(|value| value == "1" || value.eq_ignore_ascii_case("true")) + .unwrap_or(false); let mut daily_top_up_debug_notes = Vec::::new(); + let mut projection_debug_notes = Vec::::new(); let mut exit_symbols = BTreeSet::new(); let mut same_day_sold_symbols = BTreeSet::::new(); let mut intraday_attempted_buys = BTreeSet::::new(); @@ -8529,9 +8533,21 @@ impl Strategy for PlatformExprStrategy { }; let buy_cash = target_cash.min(aiquant_available_cash); if buy_cash <= 0.0 { + if debug_projection { + projection_debug_notes.push(format!( + "periodic_buy_skip_nonpositive_cash symbol={} target_cash={:.4} available_cash={:.4} stock_scale={:.4}", + symbol, target_cash, aiquant_available_cash, stock_scale + )); + } break; } if self.config.aiquant_transaction_cost && buy_cash < target_cash * 0.5 { + if debug_projection { + projection_debug_notes.push(format!( + "periodic_buy_skip_insufficient_cash symbol={} buy_cash={:.4} target_cash={:.4} available_cash={:.4}", + symbol, buy_cash, target_cash, aiquant_available_cash + )); + } break; } if !defer_execution_risk @@ -8546,7 +8562,19 @@ impl Strategy for PlatformExprStrategy { { continue; } - if !self.stock_passes_expr(ctx, &day, &decision_stock)? { + let stock_expr_pass = self.stock_passes_expr(ctx, &day, &decision_stock)?; + if !stock_expr_pass { + if debug_projection { + projection_debug_notes.push(format!( + "periodic_buy_skip_stock_expr symbol={} ma5={:.4} ma10={:.4} ma30={:.4} volume_ma5={:.4} volume_ma100={:.4}", + symbol, + decision_stock.stock_ma5, + decision_stock.stock_ma10, + decision_stock.stock_ma30, + decision_stock.stock_volume_ma5, + decision_stock.stock_volume_ma100 + )); + } continue; } let cash_before_buy = projected.cash(); @@ -8569,6 +8597,44 @@ impl Strategy for PlatformExprStrategy { rebalance_working_symbols.insert(symbol.clone()); slot_working_symbols.insert(symbol.clone()); rebalance_pending_buy_value += buy_cash; + } else if debug_projection { + let market = ctx.data.market(projection_date, symbol); + let candidate = ctx.data.candidate(projection_date, symbol); + let factor = ctx.data.factor(selection_factor_date, symbol); + let quote_count = ctx.data.execution_quotes_on(projection_date, symbol).len(); + let sizing_price = market.map(|market| { + let raw = if self.config.aiquant_transaction_cost { + self.aiquant_scheduled_last_price(ctx, projection_date, symbol) + .unwrap_or_else(|| { + self.projected_execution_price(market, OrderSide::Buy) + }) + } else { + self.projected_execution_price(market, OrderSide::Buy) + }; + self.projected_apply_slippage(market, OrderSide::Buy, raw, None) + }); + projection_debug_notes.push(format!( + "periodic_buy_project_zero symbol={} buy_cash={:.4} target_cash={:.4} available_cash={:.4} projection_date={} execution_date={} market={} factor={} candidate={} has_day_quotes={} quote_count={} sizing_price={:.4} market_volume={} minute_volume={} paused={} allow_buy={} is_kcb={} upper_limit={:.4} lower_limit={:.4}", + symbol, + buy_cash, + target_cash, + aiquant_available_cash, + projection_date, + execution_date, + market.is_some(), + factor.is_some(), + candidate.is_some(), + ctx.data.has_execution_quotes_on_date(projection_date), + quote_count, + sizing_price.unwrap_or(f64::NAN), + market.map(|item| item.volume).unwrap_or(0), + market.map(|item| item.minute_volume).unwrap_or(0), + market.map(|item| item.paused).unwrap_or(false), + candidate.map(|item| item.allow_buy).unwrap_or(false), + candidate.map(|item| item.is_kcb).unwrap_or(false), + market.map(|item| item.upper_limit).unwrap_or(f64::NAN), + market.map(|item| item.lower_limit).unwrap_or(f64::NAN) + )); } } } @@ -8636,6 +8702,7 @@ impl Strategy for PlatformExprStrategy { diagnostics.extend(selection_notes); diagnostics.extend(explicit_action_diagnostics); diagnostics.extend(daily_top_up_debug_notes); + diagnostics.extend(projection_debug_notes); let notes = vec![ format!("stock_list={}", stock_list.len()),