Portfolio Build
Combines the winning slot from each feature set into one book, re-simulates everything at the full budget, and — the part that actually matters — lets you see whether the nine slots are nine edges or one edge wearing nine names.
What this stage does
build_allstar.py --engine lr --symbol XAUUSD --tf M5 --all9 --cores 14
<set>/summary.json and configs.json. A set
with no output is skipped with a message — not an error, but it means the book
will be smaller than you asked for.
max_iter = 2000, so the portfolio's
numbers describe the same models the EA will contain — not the 600-iteration
versions the search ranked.
Modes
| Flag | Folder | What it selects |
|---|---|---|
--all9 |
all9 |
The canonical nine: base9, momentum,
volatility, price_action, trend,
full15, then micro, voltrend,
meanrev. One slot each. |
--all6 |
all6 |
The first six of those only — the "original" sets, before the three experimental additions. |
| (no flag) | allstar |
The effective default. Ranks all slots from a preferred set list and takes the top 5, with at most one slot per set. |
--topN |
topN |
The N best-scoring sets found on disk, one slot each. |
--sets a b c |
custom |
An explicit set list. Overrides the mode flags. |
--exclude x y |
best5 |
Drops the named sets and takes the rest. |
Resolution order is first-match-wins:
--topN → --sets → --exclude →
--all9 → --all6 → otherwise allstar.
all6
Running build_allstar.py with no mode flag produces an
allstar build — five slots, one per preferred set. The GUI always
passes an explicit flag, so this only bites when driving the script by hand.
How allstar differs from all9
all9 is a fixed roster: whatever each of those nine sets produced, take
its best slot. allstar instead pools all slots from a preferred
list of sets, ranks them by score, and takes the top 5 — but never two from the same
set.
allstar's filter is implemented as "at most one slot per feature set",
which is a reasonable stand-in for diversification but is not the same thing as the
equity-correlation test the search applies within a set. Two slots from
different sets can still be highly correlated, and the one-per-set rule
will not catch it. This is exactly why the portfolio page shows per-slot curves.
Equity alignment — the part with the actual subtlety
Different slots can have different warmups, because training_bars is
itself a searched parameter. A slot with training_bars = 1500 produces
its first trade far later than one with training_bars = 500. Their
equity curves therefore start at different bar indices.
Naively summing them would misalign every subsequent bar and produce a combined curve that is not any portfolio at all. So each slot's curve is offset by its own warmup before being added:
warmup = training_bars + 1
offset = warmup - 1 # the bar its curve actually starts on
combined = zeros(max_offset + longest_curve)
for each slot:
combined[offset : offset + len(curve)] += (curve - initial_balance)
Note what is being summed: the curve minus the initial balance, so each slot contributes only its own P&L rather than re-adding a $10,000 notional nine times.
The combined drawdown is then recomputed from the summed curve against its own running
peak. Per-slot drawdowns and net profits are likewise recomputed from the raw equity
arrays rather than trusted from summary.json — so the portfolio's numbers
are internally consistent rather than a mixture of two computations.
Outputs
Under strategies_lr_m5/<folder>/, where folder is
all9, all6, allstar, best5,
custom or topN:
| File | Contents |
|---|---|
summary.json |
The same shape as a per-set summary, plus a combined block with np and max_dd. |
configs.json |
One parameter dict per slot with its magic number — the generator's input. |
equity_combined.csv |
The combined portfolio curve. |
equity_<magic>.csv |
Each slot's own curve, for the per-slot charts. |
Progress output
mode=all9 slots selected: base9(magic 401), momentum(magic 411), volatility(magic 421), ...
re-simulating 9 slots @ max_iter=2000 ...
magic= 401 base9 PF=1.062 NP=+9 T=142 (B70/S72) WR=... DD=-0.12% | sl=2.0 rr=1.5 la=3 tb=1000 ri=500 lr=0.01 th=0.55
magic= 411 momentum PF=1.048 NP=+7 T=131 (B64/S67) WR=... DD=-0.19% | ...
...
COMBINED (all9): NP=+57 MaxDD=-0.41% final_balance=10057
wrote strategies_lr_m5/all9/ (summary.json configs.json equity_*.csv)
What to actually look at
Three things worth checking, in order:
The Portfolio page
Checkpoint
- The slot count matches what you asked for. Nine for ALL9 — unless a set produced nothing, in which case note which one.
- No single slot contributes a majority of the net profit.
- The per-slot curves are visibly different in shape, not scaled copies of one curve.
- The combined drawdown is meaningfully better than the worst individual slot's drawdown.
- Profit factor is above 1.0 for the book as a whole.
| Symptom | Cause | Fix |
|---|---|---|
No per-set outputs under <root>; run feature_search.py first |
Step 2 was never run, or ran into a different output root. | Run the search for this symbol and timeframe. |
skip <set>: missing summary/configs |
That set produced no result — often because the search failed or was interrupted. | Re-run that one set, then rebuild. The portfolio will be short one slot until you do. |
| Portfolio net is much lower than the sum of per-set nets | Expected. Slots are re-simulated at full budget and aligned by warmup, so the arithmetic differs from a naive sum. | Nothing to fix — read the portfolio's numbers as authoritative. |
| Combined drawdown ≈ worst slot drawdown | The slots are highly correlated: they lose at the same time. | Try a different mode, or accept that diversification is not helping on this data. |