-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathopt_parser.ps1
More file actions
111 lines (99 loc) · 4.5 KB
/
Copy pathopt_parser.ps1
File metadata and controls
111 lines (99 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
param(
[Parameter(Mandatory=$true)][string]$OptPath,
[string]$InputsPath = "",
[string]$OutDir = "",
[string]$EAName = "",
[string]$Symbol = "",
[string]$TF = "",
[switch]$Strict
)
$ErrorActionPreference = "Stop"
function Get-TextViews {
param([byte[]]$Bytes)
return @(
[PSCustomObject]@{ Encoding = 'ASCII'; Text = [System.Text.Encoding]::ASCII.GetString($Bytes) },
[PSCustomObject]@{ Encoding = 'UTF-8'; Text = [System.Text.Encoding]::UTF8.GetString($Bytes) },
[PSCustomObject]@{ Encoding = 'UTF-16LE'; Text = [System.Text.Encoding]::Unicode.GetString($Bytes) }
)
}
function Normalize-HeaderName {
param([string]$Name)
$n = $Name.Trim().TrimStart([char]0xFEFF).Trim('"')
switch -Regex ($n) {
'^(Pass|#)$' { 'Pass'; break }
'^(Result|Profit|Net Profit|Total Net Profit)$' { 'TotalNetProfit'; break }
'^(PF|Profit Factor)$' { 'ProfitFactor'; break }
'^(Expected Payoff|Payoff)$' { 'ExpectedPayoff'; break }
'^(Recovery Factor|RF)$' { 'RecoveryFactor'; break }
'^(Sharpe|Sharpe Ratio)$' { 'SharpeRatio'; break }
'^(Trades|Total Trades)$' { 'TotalTrades'; break }
'^(Equity DD %|Drawdown %|Max Drawdown %|MaxDrawdownPct)$' { 'MaxDrawdownPct'; break }
'^(Equity DD|Drawdown|Max Drawdown|MaxDrawdownMoney)$' { 'MaxDrawdownMoney'; break }
default { $n }
}
}
function Try-ParseDelimitedTable {
param([string]$Text, [string[]]$InputNames)
$lines = @($Text -split "`r?`n" | ForEach-Object { $_.Trim([char]0).Trim() } | Where-Object { $_ })
$delimiters = @("`t", ';', ',')
foreach ($delimiter in $delimiters) {
for ($i = 0; $i -lt $lines.Count; $i++) {
$line = $lines[$i]
if ($line -notlike "*$delimiter*") { continue }
if ($line -notmatch 'Pass|Result|Profit|Balance|Trades|Drawdown') { continue }
$headers = @($line -split [regex]::Escape($delimiter) | ForEach-Object { Normalize-HeaderName $_ })
if ($headers.Count -lt 4 -or ($headers -notcontains 'Pass')) { continue }
$rows = @()
for ($j = $i + 1; $j -lt $lines.Count; $j++) {
$parts = @($lines[$j] -split [regex]::Escape($delimiter))
if ($parts.Count -ne $headers.Count) { continue }
if ($parts[0] -notmatch '^-?\d+(\.\d+)?$') { continue }
$obj = [ordered]@{}
for ($k = 0; $k -lt $headers.Count; $k++) {
$name = $headers[$k]
if (-not $name) { $name = "Column$k" }
$obj[$name] = $parts[$k].Trim().Trim('"')
}
if ($EAName) { $obj['EA'] = $EAName }
if ($Symbol) { $obj['Symbol'] = $Symbol }
if ($TF) { $obj['Period'] = $TF }
$rows += [PSCustomObject]$obj
}
if ($rows.Count -gt 0) { return $rows }
}
}
return @()
}
if (-not (Test-Path $OptPath)) { Write-Error "OPT file not found: $OptPath" }
if (-not $OutDir) { $OutDir = Split-Path $OptPath -Parent }
if (-not (Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir -Force | Out-Null }
$inspection = & "$PSScriptRoot\opt_inspector.ps1" -OptPath $OptPath -InputsPath $InputsPath -EAName $EAName -Symbol $Symbol -TF $TF -OutDir $OutDir
if ($inspection.ParseConfidence -eq 'None') {
$message = "OPT cache does not contain reliable text markers for pass extraction: $OptPath"
if ($Strict) { Write-Error $message }
Write-Warning " [OPT] $message"
return $null
}
$inputNames = @()
if ($InputsPath -and (Test-Path $InputsPath)) {
$inputNames = @(& "$PSScriptRoot\tester_inputs_parser.ps1" -InputPath $InputsPath | Where-Object { $_.Optimize } | ForEach-Object { $_.Name })
}
$bytes = [System.IO.File]::ReadAllBytes($OptPath)
$rows = @()
foreach ($view in Get-TextViews -Bytes $bytes) {
$rows = @(Try-ParseDelimitedTable -Text $view.Text -InputNames $inputNames)
if ($rows.Count -gt 0) {
Write-Host " [OPT] Parsed $($rows.Count) passes from $($view.Encoding) text table" -ForegroundColor Green
break
}
}
if ($rows.Count -eq 0) {
$message = "No reliable optimization pass table found in .opt cache. Diagnostics saved to opt_inspection.json."
if ($Strict) { Write-Error $message }
Write-Warning " [OPT] $message"
return $null
}
$out = Join-Path $OutDir 'optimization_passes.csv'
$rows | Export-Csv $out -NoTypeInformation -Encoding UTF8
Write-Host " [OPT] Passes: $out" -ForegroundColor Green
Get-Item $out