[CmdletBinding()] param( [ValidateSet("torch", "reservoir")] [string]$Trainer = "torch", [string]$Symbols = "", [int]$Limit = 0, [string]$Lookbacks = "", [string]$Units = "", [string]$Ridges = "", [string]$Architectures = "", [string]$HiddenSizes = "", [string]$Layers = "", [string]$Dropouts = "", [int]$Epochs = 0, [int]$Patience = 0, [string]$Interval = "", [string]$EnvFile = "" ) $ErrorActionPreference = "Stop" $RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path $RuntimeDir = Join-Path $RepoRoot "runtime" $LogFile = Join-Path $RuntimeDir "lstm_retrain.log" New-Item -ItemType Directory -Force -Path $RuntimeDir | Out-Null function Write-RetrainLog { param([string]$Message) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ssK" "[$timestamp] $Message" | Tee-Object -FilePath $LogFile -Append } function Resolve-Python { $venvPython = Join-Path $RepoRoot ".venv\Scripts\python.exe" if (Test-Path $venvPython) { return $venvPython } $userPython = Join-Path $env:LOCALAPPDATA "Programs\TradeBotPython312\python.exe" if (Test-Path $userPython) { return $userPython } foreach ($candidate in @("python.exe", "python")) { $command = Get-Command $candidate -ErrorAction SilentlyContinue if (-not $command) { continue } return $command.Source } throw "Python was not found. Create .venv or install Python 3.12." } if (-not $Symbols -and $env:LSTM_RETRAIN_SYMBOLS) { $Symbols = $env:LSTM_RETRAIN_SYMBOLS } if ($Limit -le 0) { $Limit = if ($env:LSTM_RETRAIN_LIMIT) { [int]$env:LSTM_RETRAIN_LIMIT } else { 1000 } } if (-not $Lookbacks) { $Lookbacks = if ($env:LSTM_RETRAIN_LOOKBACKS) { $env:LSTM_RETRAIN_LOOKBACKS } else { "32,64" } } if (-not $Units) { $Units = if ($env:LSTM_RETRAIN_UNITS) { $env:LSTM_RETRAIN_UNITS } else { "4,6" } } if (-not $Ridges) { $Ridges = if ($env:LSTM_RETRAIN_RIDGES) { $env:LSTM_RETRAIN_RIDGES } else { "0.001" } } if (-not $Architectures) { $Architectures = if ($env:LSTM_RETRAIN_ARCHITECTURES) { $env:LSTM_RETRAIN_ARCHITECTURES } else { "lstm,gru" } } if (-not $HiddenSizes) { $HiddenSizes = if ($env:LSTM_RETRAIN_HIDDEN_SIZES) { $env:LSTM_RETRAIN_HIDDEN_SIZES } else { "16,32" } } if (-not $Layers) { $Layers = if ($env:LSTM_RETRAIN_LAYERS) { $env:LSTM_RETRAIN_LAYERS } else { "1" } } if (-not $Dropouts) { $Dropouts = if ($env:LSTM_RETRAIN_DROPOUTS) { $env:LSTM_RETRAIN_DROPOUTS } else { "0.0" } } if ($Epochs -le 0) { $Epochs = if ($env:LSTM_RETRAIN_EPOCHS) { [int]$env:LSTM_RETRAIN_EPOCHS } else { 60 } } if ($Patience -le 0) { $Patience = if ($env:LSTM_RETRAIN_PATIENCE) { [int]$env:LSTM_RETRAIN_PATIENCE } else { 10 } } if (-not $Interval -and $env:LSTM_RETRAIN_INTERVAL) { $Interval = $env:LSTM_RETRAIN_INTERVAL } if (-not $EnvFile -and $env:LSTM_RETRAIN_ENV) { $EnvFile = $env:LSTM_RETRAIN_ENV } if (-not $EnvFile -and (Test-Path (Join-Path $RepoRoot ".env"))) { $EnvFile = Join-Path $RepoRoot ".env" } $mutex = New-Object System.Threading.Mutex($false, "TradeBotLstmRetrainer") $hasLock = $false $pushedLocation = $false try { $hasLock = $mutex.WaitOne(0) if (-not $hasLock) { Write-RetrainLog "Another LSTM retrain is already running; skipping." exit 0 } $python = Resolve-Python if ($Trainer -eq "torch") { $trainerArgs = @( "-u", "tools\train_torch_recurrent_forecaster.py", "--limit", $Limit.ToString(), "--lookbacks", $Lookbacks, "--architectures", $Architectures, "--hidden-sizes", $HiddenSizes, "--layers", $Layers, "--dropouts", $Dropouts, "--epochs", $Epochs.ToString(), "--patience", $Patience.ToString() ) } else { $trainerArgs = @( "-u", "tools\train_lstm_forecaster.py", "--limit", $Limit.ToString(), "--lookbacks", $Lookbacks, "--units", $Units, "--ridges", $Ridges ) } if ($Symbols) { $trainerArgs += @("--symbols", $Symbols) } if ($Interval) { $trainerArgs += @("--interval", $Interval) } if ($EnvFile) { $trainerArgs += @("--env", $EnvFile) } Push-Location $RepoRoot $pushedLocation = $true Write-RetrainLog "Starting LSTM retrain: $python $($trainerArgs -join ' ')" & $python @trainerArgs 2>&1 | Tee-Object -FilePath $LogFile -Append if ($LASTEXITCODE -ne 0) { throw "Trainer failed with exit code $LASTEXITCODE." } Write-RetrainLog "Finished LSTM retrain." } catch { Write-RetrainLog "ERROR: $($_.Exception.Message)" exit 1 } finally { if ($pushedLocation) { Pop-Location -ErrorAction SilentlyContinue } if ($hasLock) { $mutex.ReleaseMutex() } $mutex.Dispose() }