it be better
This commit is contained in:
33
src/bot.rs
33
src/bot.rs
@@ -54,6 +54,8 @@ pub struct TradingBot {
|
||||
new_positions_this_cycle: usize,
|
||||
/// Rolling list of day trade dates for PDT tracking.
|
||||
day_trades: Vec<NaiveDate>,
|
||||
/// Current portfolio value (updated each cycle), used for PDT exemption check.
|
||||
current_portfolio_value: f64,
|
||||
}
|
||||
|
||||
impl TradingBot {
|
||||
@@ -78,6 +80,7 @@ impl TradingBot {
|
||||
cooldown_timers: HashMap::new(),
|
||||
new_positions_this_cycle: 0,
|
||||
day_trades: Vec::new(),
|
||||
current_portfolio_value: 0.0,
|
||||
};
|
||||
|
||||
// Load persisted state
|
||||
@@ -273,7 +276,11 @@ impl TradingBot {
|
||||
}
|
||||
|
||||
/// Check if a day trade is allowed (under PDT limit).
|
||||
/// PDT rule only applies to accounts under $25,000.
|
||||
fn can_day_trade(&self) -> bool {
|
||||
if self.current_portfolio_value >= 25_000.0 {
|
||||
return true;
|
||||
}
|
||||
self.day_trades_in_window() < PDT_MAX_DAY_TRADES
|
||||
}
|
||||
|
||||
@@ -359,12 +366,17 @@ impl TradingBot {
|
||||
if let Some(halt_start) = self.drawdown_halt_start {
|
||||
if self.trading_cycle_count >= halt_start + DRAWDOWN_HALT_BARS {
|
||||
tracing::info!(
|
||||
"Drawdown halt expired after {} cycles. Resuming trading at {:.2}% drawdown.",
|
||||
"Drawdown halt expired after {} cycles. Resuming trading. \
|
||||
Peak reset from ${:.2} to ${:.2} (was {:.2}% drawdown).",
|
||||
DRAWDOWN_HALT_BARS,
|
||||
self.peak_portfolio_value,
|
||||
portfolio_value,
|
||||
drawdown_pct * 100.0
|
||||
);
|
||||
self.drawdown_halt = false;
|
||||
self.drawdown_halt_start = None;
|
||||
// Reset peak to current value to prevent cascading re-triggers.
|
||||
self.peak_portfolio_value = portfolio_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -409,13 +421,15 @@ impl TradingBot {
|
||||
|
||||
// ── Account helpers ──────────────────────────────────────────────
|
||||
|
||||
async fn log_account_info(&self) {
|
||||
async fn log_account_info(&mut self) {
|
||||
match self.client.get_account().await {
|
||||
Ok(account) => {
|
||||
let portfolio_value: f64 = account.portfolio_value.parse().unwrap_or(0.0);
|
||||
let buying_power: f64 = account.buying_power.parse().unwrap_or(0.0);
|
||||
let cash: f64 = account.cash.parse().unwrap_or(0.0);
|
||||
|
||||
self.current_portfolio_value = portfolio_value;
|
||||
|
||||
tracing::info!("Account Status: {}", account.status);
|
||||
tracing::info!("Buying Power: ${:.2}", buying_power);
|
||||
tracing::info!("Portfolio Value: ${:.2}", portfolio_value);
|
||||
@@ -738,12 +752,17 @@ impl TradingBot {
|
||||
self.prune_old_day_trades();
|
||||
tracing::info!("{}", "=".repeat(60));
|
||||
tracing::info!("Starting trading cycle #{}...", self.trading_cycle_count);
|
||||
tracing::info!(
|
||||
"PDT status: {}/{} day trades in rolling 5-business-day window",
|
||||
self.day_trades_in_window(),
|
||||
PDT_MAX_DAY_TRADES
|
||||
);
|
||||
self.log_account_info().await;
|
||||
if self.current_portfolio_value >= 25_000.0 {
|
||||
tracing::info!("PDT status: EXEMPT (portfolio ${:.2} >= $25,000)", self.current_portfolio_value);
|
||||
} else {
|
||||
tracing::info!(
|
||||
"PDT status: {}/{} day trades in rolling 5-business-day window (portfolio ${:.2} < $25,000)",
|
||||
self.day_trades_in_window(),
|
||||
PDT_MAX_DAY_TRADES,
|
||||
self.current_portfolio_value,
|
||||
);
|
||||
}
|
||||
|
||||
// Increment bars_held once per trading cycle (matches backtester's per-bar increment)
|
||||
for meta in self.position_meta.values_mut() {
|
||||
|
||||
Reference in New Issue
Block a user