[CmdletBinding()] param( [int]$MinReplayTrades = 8, [int]$MaxAttempts = 0, [string]$Symbols = "BTCUSDT,ETHUSDT,SOLUSDT,LTCUSDT", [int]$Limit = 3000, [switch]$DeployToPi, [string]$PiHost = "192.168.0.185", [string]$PiUser = "sevenhill", [string]$PiRoot = "/mnt/data/tradebot", [string]$PiSshKeyPath = "", [int]$SeedStart = 0 ) $ErrorActionPreference = "Stop" $RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path $RuntimeDir = Join-Path $RepoRoot "runtime" $LoopLog = Join-Path $RuntimeDir "torch_retrain_until_replay8.log" $GuardReport = Join-Path $RuntimeDir "torch_retrain_guard.json" $ActiveCalibration = Join-Path $RuntimeDir "torch_threshold_calibration.json" $Runner = Join-Path $RepoRoot "tools\run_torch_retrain.ps1" New-Item -ItemType Directory -Force -Path $RuntimeDir | Out-Null function Write-LoopLog { param([string]$Message) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ssK" "[$timestamp] $Message" | Tee-Object -FilePath $LoopLog -Append } function ConvertTo-IntOrZero { param($Value) try { if ($null -eq $Value) { return 0 } return [int]$Value } catch { return 0 } } function Read-GuardSummary { if (-not (Test-Path $GuardReport)) { return [pscustomobject]@{ Accepted = $false Reason = "guard_report_missing" CandidateReplayTrades = 0 CurrentReplayTrades = 0 WalkForwardTrades = 0 } } try { $payload = Get-Content -Raw -LiteralPath $GuardReport | ConvertFrom-Json return [pscustomobject]@{ Accepted = [bool]$payload.accepted Reason = [string]$payload.reason CandidateReplayTrades = ConvertTo-IntOrZero $payload.candidate.full_replay.trades CurrentReplayTrades = ConvertTo-IntOrZero $payload.current.full_replay.trades WalkForwardTrades = ConvertTo-IntOrZero $payload.candidate.walk_forward_summary.trades } } catch { return [pscustomobject]@{ Accepted = $false Reason = "guard_report_unreadable" CandidateReplayTrades = 0 CurrentReplayTrades = 0 WalkForwardTrades = 0 } } } function Read-ActiveReplayTrades { if (-not (Test-Path $ActiveCalibration)) { return 0 } try { $payload = Get-Content -Raw -LiteralPath $ActiveCalibration | ConvertFrom-Json return ConvertTo-IntOrZero $payload.full_replay.trades } catch { return 0 } } $attempt = 0 while ($true) { $activeReplayTrades = Read-ActiveReplayTrades if ($activeReplayTrades -ge $MinReplayTrades) { Write-LoopLog "Stop condition reached: active calibration full_replay.trades=$activeReplayTrades >= $MinReplayTrades." exit 0 } $attempt += 1 if ($SeedStart -gt 0) { $attemptSeed = $SeedStart + $attempt - 1 } else { $attemptSeed = Get-Random -Minimum 1 -Maximum 2147483647 } Write-LoopLog "Attempt $attempt started; seed=$attemptSeed; target full_replay.trades >= $MinReplayTrades." $runnerArgs = @( "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $Runner, "-Symbols", $Symbols, "-Limit", $Limit.ToString(), "-Seed", $attemptSeed.ToString() ) if ($DeployToPi) { $runnerArgs += "-DeployToPi" if ($PiHost) { $runnerArgs += @("-PiHost", $PiHost) } if ($PiUser) { $runnerArgs += @("-PiUser", $PiUser) } if ($PiRoot) { $runnerArgs += @("-PiRoot", $PiRoot) } if ($PiSshKeyPath) { $runnerArgs += @("-PiSshKeyPath", $PiSshKeyPath) } } & powershell.exe @runnerArgs 2>&1 | Tee-Object -FilePath $LoopLog -Append $runnerExit = $LASTEXITCODE $summary = Read-GuardSummary Write-LoopLog "Attempt $attempt finished; runner_exit=$runnerExit accepted=$($summary.Accepted) reason=$($summary.Reason) candidate_full_replay.trades=$($summary.CandidateReplayTrades) current_full_replay.trades=$($summary.CurrentReplayTrades) walk_forward.trades=$($summary.WalkForwardTrades)." if ($summary.Accepted -and $summary.CandidateReplayTrades -ge $MinReplayTrades) { Write-LoopLog "Stop condition reached: accepted candidate full_replay.trades=$($summary.CandidateReplayTrades) >= $MinReplayTrades." exit 0 } if ($summary.CurrentReplayTrades -ge $MinReplayTrades) { Write-LoopLog "Stop condition reached: current artifact full_replay.trades=$($summary.CurrentReplayTrades) >= $MinReplayTrades." exit 0 } if ($MaxAttempts -gt 0 -and $attempt -ge $MaxAttempts) { Write-LoopLog "MaxAttempts=$MaxAttempts reached before replay target." exit 2 } Start-Sleep -Seconds 10 }