The Optimizer
The optimizer runs the same Pine script over many different parameter values, evaluates each one, and shows you where the results get good.
It is the reason the rest of the product exists. A backtest answers “did this work?”. The optimizer answers “is there a region of this strategy that works, or was that one run a coincidence?” — which is the only question worth asking before you spend any more time on a strategy.
Screenshot pending
awaiting screenshots/optimizer-config.png in public/
The idea in one paragraph
Every input.* declaration in your Pine source becomes a dimension. Four parameters means
a four-dimensional space. The optimizer proposes parameter sets, the worker pool runs each one
against your bars, a scoring function turns the trade list into a number, and the algorithm
uses those numbers to decide what to try next. Repeat until the budget runs out or the search
converges. Then you look at the distribution of results and decide whether the good region
is real.
Three moving parts
Keeping these separate is what makes the feature trustworthy, and it is why a new algorithm is a small change rather than a rewrite.
| Part | Responsibility | Knows about |
|---|---|---|
| TrialManager | Owns the queue, calls suggest() and report() | Nothing about any algorithm |
| Algorithm | Decides the next candidate set | Its own internal state only |
| BacktestAdapter | Runs Pine and computes metrics | Nothing about any algorithm |
The seven algorithms
| Algorithm | Use it when | Cost profile |
|---|---|---|
| Grid | The space is small enough to test exhaustively | Every combination, once |
| Brute | Same intent as Grid; a separate cap and label | Every combination, once |
| Random | You want a baseline to judge the others against | Flat cost, no learning |
| SA | The landscape is smooth and you expect a broad basin | Cooling schedule, single trajectory |
| TPE | The default, and the right answer almost always | Learns a model; converges fast |
| GA | Large populations and long budgets are affordable | Slowest to show a result |
| NSGA-II | Two objectives you genuinely cannot trade off | Whole generations, in parallel |
How to choose, honestly
Use TPE unless you have a specific reason not to. It is the default because it is the best general-purpose answer: it builds a model of where good results live and samples from that model, so it spends its budget where the signal is.
Use Grid when the space is small. If the product can enumerate every combination, exhaustive search beats every heuristic. You need roughly 10⁴ combinations or fewer.
Use Random as a control. Random is a meaningful baseline: if Random finds the optimum as often as TPE does, your parameter space is not doing much work and you should question the strategy rather than the algorithm.
Use SA when you believe the landscape is smooth. It is a hill-climber with an escape hatch, not a population method.
Use GA only with a large budget. It is manual-select for a reason — it is the slowest to produce a visible improvement on the small spaces most people actually try.
The full mechanism of each is documented in Algorithms — the acceptance rule, the exact default values, what happens when the space is degenerate, and where each one fails.
What every trial is measured on
Every completed trial is scored on the same set of metrics, starting from a capital of 10 000.
| Group | Metrics |
|---|---|
| Capital | netProfit, pnl, pnlPercent, openPnl |
| Quality | profitFactor, winRate, sharpe, avgPnl |
| Totals | grossProfit, grossLoss, wins, losses, total |
| Risk | maxDD, maxDDPct |
| Sides | longs, shorts, and their win counts and net P&L |
| Series | equitySeries, pairs, rangeStart, rangeEnd |
Round trips are formed before anything is computed
Metrics are derived from paired trades, not from individual fills. Entry and exit are paired into round trips first; only then are profit, win rate and drawdown calculated.
Two consequences follow. A still-open position is not counted as a win or a loss, so win rate is honest. And a metric that cannot be computed is reported as undefined rather than as zero — a missing profit factor does not silently become “no profit”.
Running a run
Launch, watch, stop. The guarantees here are deliberate:
| Action | Behaviour |
|---|---|
| Launch | Locks the configuration and captures the source, bars and search space |
| Pause / Resume | Suspends and continues the same run |
| Stop | Keeps every completed trial; discards only the in-flight evaluation |
| Run while running | Ignored — never spawns a second pool |
| Storage failure | Results stay usable in memory |
Screenshot pending
awaiting screenshots/optimizer-results.png in public/
The two things that bite people
Where to go next
| Page | Contents |
|---|---|
| Algorithms | The mechanism behind each of the seven, in detail |
| Search space | How parameters become dimensions, and how the space is sized |
| Execution | Worker-pool sizing, backpressure, cancellation |
| Analysis | Reading a finished run |
| Workflow | The complete judgement loop, start to decision |