# analyze_diagnostics.ps1 # Cross-symbol AI Diagnostics aggregator for The Impossible Prop EA. # # Reads every tip_diag__.jsonl file written by the EA's # diagnostics layer and produces a deduped, priority-ranked table to drive # the next single-variable tuning phase. # # Default scan locations (auto-detected, no setup needed): # - %APPDATA%\MetaQuotes\Terminal\Common\Files (live / demo, FILE_COMMON) # - %APPDATA%\MetaQuotes\Terminal\\MQL5\Files (per-terminal install) # # Usage: # pwsh .\analyze_diagnostics.ps1 # pwsh .\analyze_diagnostics.ps1 -Symbol GBPUSD -MaxPriority 2 # pwsh .\analyze_diagnostics.ps1 -Path 'D:\MT5_Portable\MQL5\Files' # portable / custom # # Output: console table, plus .\diagnostics_summary.csv in caller's CWD. [CmdletBinding()] param( [string[]] $Path, [string] $Symbol = '*', [int] $MaxPriority = 4, [int] $TopN = 30, [string] $CsvOut = (Join-Path (Get-Location) 'diagnostics_summary.csv') ) $ErrorActionPreference = 'Stop' # Build default scan list if caller did not supply -Path: # 1. The shared Common\Files folder (where FILE_COMMON writes) # 2. Every per-terminal MQL5\Files folder under %APPDATA%\MetaQuotes\Terminal if (-not $Path -or $Path.Count -eq 0) { $defaultPaths = @() $commonFiles = Join-Path $env:APPDATA 'MetaQuotes\Terminal\Common\Files' if (Test-Path -LiteralPath $commonFiles) { $defaultPaths += $commonFiles } $terminalRoot = Join-Path $env:APPDATA 'MetaQuotes\Terminal' if (Test-Path -LiteralPath $terminalRoot) { Get-ChildItem -LiteralPath $terminalRoot -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne 'Common' } | ForEach-Object { $tFiles = Join-Path $_.FullName 'MQL5\Files' if (Test-Path -LiteralPath $tFiles) { $defaultPaths += $tFiles } } } $Path = $defaultPaths } # 1. Discover JSONL files $pattern = "tip_diag_$Symbol*.jsonl" $files = foreach ($p in $Path) { if (Test-Path -LiteralPath $p) { Get-ChildItem -LiteralPath $p -Filter $pattern -File -ErrorAction SilentlyContinue } } if (-not $files -or $files.Count -eq 0) { Write-Warning "No diagnostic files matching '$pattern' under: $($Path -join ', ')" return } Write-Host ("Reading {0} diagnostic file(s)..." -f $files.Count) -ForegroundColor Cyan # 2. Parse + accumulate (dedupe on symbol|magic|category|key|current->suggested) $bucket = @{} $totalRows = 0 foreach ($f in $files) { foreach ($line in (Get-Content -LiteralPath $f.FullName -ErrorAction SilentlyContinue)) { if ([string]::IsNullOrWhiteSpace($line)) { continue } try { $obj = $line | ConvertFrom-Json } catch { continue } $totalRows++ $key = '{0}|{1}|{2}|{3}|{4}->{5}' -f $obj.symbol, $obj.magic, $obj.category, $obj.key, $obj.current, $obj.suggested if ($bucket.ContainsKey($key)) { $row = $bucket[$key] $row.SeenCount += 1 if ($obj.timestamp -gt $row.LastSeen) { $row.LastSeen = $obj.timestamp } if ($obj.timestamp -lt $row.FirstSeen) { $row.FirstSeen = $obj.timestamp } # Take strongest (lowest) priority + highest confidence + latest evidence if ($obj.priority -lt $row.Priority) { $row.Priority = $obj.priority } if ($obj.confidence -gt $row.Confidence) { $row.Confidence = $obj.confidence; $row.Evidence = $obj.evidence; $row.TradeCount = $obj.trade_count } } else { $bucket[$key] = [pscustomobject]@{ Symbol = $obj.symbol Magic = $obj.magic Category = $obj.category Priority = [int]$obj.priority Key = $obj.key Current = $obj.current Suggested = $obj.suggested Evidence = $obj.evidence TradeCount = [int]$obj.trade_count Confidence = [double]$obj.confidence SeenCount = 1 FirstSeen = $obj.timestamp LastSeen = $obj.timestamp } } } } # 3. Filter + rank $rows = $bucket.Values | Where-Object { $_.Priority -le $MaxPriority } | Sort-Object Priority, @{Expression='Confidence';Descending=$true}, @{Expression='SeenCount';Descending=$true} if (-not $rows -or $rows.Count -eq 0) { Write-Warning ("Parsed {0} JSONL row(s) but none matched -MaxPriority {1}" -f $totalRows, $MaxPriority) return } $top = $rows | Select-Object -First $TopN # 4. Console table Write-Host "" Write-Host ("AI DIAGNOSTICS - top {0} of {1} unique recommendations ({2} raw rows)" -f $top.Count, $rows.Count, $totalRows) -ForegroundColor Yellow $top | Select-Object Symbol, Priority, Category, Key, Current, Suggested, @{n='Conf%'; e={ '{0:N0}' -f ($_.Confidence * 100) }}, @{n='Trades'; e={ $_.TradeCount }}, @{n='Seen'; e={ $_.SeenCount }}, @{n='Evidence'; e={ if ($_.Evidence.Length -gt 60) { $_.Evidence.Substring(0,57) + '...' } else { $_.Evidence } } } | Format-Table -AutoSize -Wrap # 5. CSV export (full deduped set, not just TopN) $rows | Export-Csv -LiteralPath $CsvOut -NoTypeInformation -Encoding UTF8 Write-Host ("Saved full deduped list to: {0}" -f $CsvOut) -ForegroundColor Green # 6. Phase decision hint - report the single highest-priority symbol/key per category Write-Host "" Write-Host "NEXT-PHASE CANDIDATE (top P1/P2 per category):" -ForegroundColor Magenta $rows | Where-Object { $_.Priority -le 2 } | Group-Object Category | ForEach-Object { $best = $_.Group | Sort-Object Priority, @{Expression='Confidence';Descending=$true} | Select-Object -First 1 ' {0,-12} {1,-8} P{2} {3,-26} {4} -> {5} ({6} trades, {7:N0}% conf, x{8})' -f ` $best.Category, $best.Symbol, $best.Priority, $best.Key, $best.Current, $best.Suggested, $best.TradeCount, ($best.Confidence * 100), $best.SeenCount }