Reference

Portfolios

Run several assets from one shared capital pool: rosters, contention, rebalancing, risk controls, deposits and withdrawals, the book report, and the known limits behind a surprising zero.

A portfolio runs several assets from one shared pool of capital as a single book. Each asset carries its own strategy, and a contention rule decides who gets the cash when more than one asset wants to enter on the same bar. Where a single backtest is one symbol, one strategy and its own balance, a portfolio is a roster of assets competing for one pool, with a shared equity curve, per-asset attribution, and a record of every signal that could not be filled.

Spot crypto, v1

The v1 portfolio path is spot crypto only. Symbols resolve to Binance USDT pairs (BTC becomes BTCUSDT). A book holds up to 20 assets.

Building a book#

There are three ways in, and they all land on the same review then run flow. For a step by step walkthrough see Build a portfolio.

PathHow
One promptDescribe every asset in a single sentence. A multi-asset prompt is split into one parsed strategy per asset, and the terminal switches to Portfolio mode for you.
Visual builderFlip the sidebar toggle from Single asset to Portfolio, open the Visual tab, and add assets by hand. Each asset opens the normal strategy builder canvas.
API / MCPparse_portfolio then run_portfolio, see the MCP server.
text
Buy BTCUSDT and ETHUSDT on 1d when price closes above the 20 EMA; exit when it closes below. $50k, prorata.

Each asset shows up as a review card with the clause the splitter assigned to it ("Split as"), its parsed logic, and its market. Before you run, you can edit any asset, copy one asset's rules to the whole roster, or remove it.

Shared capital & contention#

A book trades from one initial capital amount, not one balance per asset. The terminal starts a new book at $30,000; the API and MCP default to $100,000.

When two or more assets signal an entry on the same bar and there is not enough free cash for all of them, the contention rule resolves the conflict:

RuleBehaviour
rank (default)Priority order wins. Priority follows roster order unless you set it, say "prioritise BTC over ETH" to pin it.
prorataThe contested cash is split proportionally across the competing assets.
strengthThe strongest signal fills first. Ask for it with "strongest signal fills first".

A signal that cannot be funded is never dropped silently. It is written to the skip ledger with a reason, see Reading the book report.

Rebalancing#

Off by default. You turn it on by naming target weights; percentage stops and take-profits are never mistaken for weights.

SettingValues
Scheduledaily, weekly, monthly, quarterly, yearly, or never (default monthly)
Overlay moderesizes open positions toward the target weights on each boundary, while entry signals still fire
Allocation modeholds the whole book to the target weights with no entry signals, a long-only hold-to-weight book
Targetsper-asset weights that sum to 100% or less; a cash remainder is allowed
Cash sleevestate the remainder explicitly: "hold 40% BTC, 30% ETH and 30% cash"
Drift bandrebalance off-calendar whenever a sleeve drifts this far from target. Quote it in percentage points or in percent: a band is a difference between two percentages, so "5 points off target" and "a 5% drift band" are the same rule
Minimum tradeskip corrective trades below a dollar amount, so a tight band stops generating $12 trades
text
Rebalance monthly to 40% BTC, 30% ETH, 30% SOL.
Hold 60% BTCUSDT and 40% ETHUSDT, rebalance quarterly.
Allocate 50% BTCUSDT and 50% ETHUSDT once and never rebalance.
Hold 60% BTCUSDT and 40% ETHUSDT, rebalance monthly but skip rebalance trades under $500.
Equal weight BTCUSDT, ETHUSDT and SOLUSDT, rebalance monthly and also whenever a position drifts more than 5 points from its target.
A longer cadence is the cheapest way to cut rebalance costs

Every rebalance is turnover you pay for. Quarterly tracks the targets more loosely than monthly and trades about a third as often; never allocates once on the first bar and then lets the winners run, which is the buy-and-hold baseline every other schedule should be measured against.

Rotation#

Instead of fixed weights, rank the universe each rebalance and hold only the leaders, or the laggards.

text
Buy the top 3 by momentum over 30 days, rebalance weekly.
Hold the 2 lowest volatility coins, rebalance monthly.
Rotate into the best 2 by 30-day return and short the worst 2.

Rank by momentum, return, rate of change, RSI, Sharpe or volatility. A rotation is always an allocation book, the held set and the weights are both chosen by rank, so entry signals do not run.

Ranking is relative: it answers which of these is best, never is any of them any good. In a market where everything is falling, a top-N rotation dutifully buys the best of the losers and stays fully invested all the way down. Add the absolute test and the book goes to cash instead when nothing clears it:

text
Hold the top 2 by 90 day momentum but only while their momentum is positive, rebalance monthly.
Rotate into the top 3 by momentum, cash if none are positive.

That second test is what makes it dual momentum. The floor gates the LONG side only: it says which names are worth owning, not which are worth shorting, so a long/short rotation still takes its short sleeve from the worst-ranked names. When nothing clears the floor the run says so explicitly, so a book that deliberately sat out a bear market is never mistaken for a broken rotation.

Risk controls#

All optional, and all off unless you ask for them. State them once, anywhere in the prompt, a control that talks about the whole book never has to be repeated per asset. Percentages that belong to a leg ("stop loss 3%") are never mistaken for a book knob.

Every control below can be typed in the prompt or edited in the Book settings panel on the review page: including the ones whose value is a ladder, a schedule, a list of days or a session window. Clearing an editor turns that family off completely; there is no "set but inert" state. An edit you make by hand is authoritative: re-parsing the prompt afterwards will not overwrite it.

Size and concentration#

ControlEffectSay
Book drawdown stopFlatten the book and halt new entries once equity falls this far below its peak. Deliberately permanent for the rest of the run"stop the book at 20%"
Book take-profitThe profit-side twin: close everything and stop once the account is up past a target"close the whole book at +30%"
Max concurrent positionsCap how many assets can be open at once"at most 3 open positions"
Total exposure capCeiling on total open notional versus book equity"cap exposure at 80% total"
Per-asset capLargest share of the book any one asset can hold"max 20% per asset"
Per-sleeve loss stopForce-close any position that falls this far below its own entry, whatever the strategy's own exit says. It can re-enter later"stop each position that falls 12% below its entry"
Sector exposure capBound a whole group's share of the book, by naming the group's members"cap memecoins (DOGEUSDT, SHIBUSDT) at 15%"
Positions per sectorBound how many names a group may hold at once"max 2 positions per sector"
Cash reserveNever spend the book below this much cash"always keep 20% in cash"
Correlation capSkip a new entry whose recent returns move too closely with a position already open"avoid holding two positions correlated above 0.8"
Volatility targetScale every new position so the book's realized volatility tracks a target"target 15% annualized volatility"
Sleeve drawdown haltRetire an asset for the rest of the run once its own running P&L is this far below its peak"stop trading any coin that is down 20%"
Drawdown-scaled sizingMake every new position smaller while the book is in a drawdown, restoring full size on recovery"halve position size while the book is in a 10% drawdown"
Open risk budgetBound the total distance to stop × size across every open position, ten positions each risking 1% is a 10% book risk"never have more than 6% of the book at risk"
Correlation clustersGroup everything that moves together and hold at most N names per cluster, the transitive answer where the correlation cap is the pairwise one"at most one position per correlation cluster"
Positions per symbolOn a book with several strategies on the same coin, bound how many of them may be open at once"only one position per symbol", "BTC gets 3 positions max"
Sectors by nameTag your sectors in plain English once, then cap them by name"BTC and ETH are majors, DOGE and SHIB are memecoins. Max 60% in majors, at most 2 memecoins"
Minimum position sizeSkip a fill that clears the venue minimum but is too small to be worth the commission"skip any position under $1000"
One sizing ruleReplace whatever the individual legs said with a single book-wide rule"risk 1% of the book per trade", "size every position at 10% of equity"
Per-position volatility targetEven out the sleeves so a wild coin and a calm one carry comparable risk"target 20% volatility per position"
Top-N concentration capBound what the biggest holdings add up to together. Four names at 24% each break this while breaking no single-name limit"cap the top 3 names at 60% of equity", "no more than 60% of the book in the top 3 holdings"
Every sector, one numberBound each sector without enumerating them, the way a mandate is written. Untagged sleeves are never capped by it"never put more than half the book in one sector", "max 40% per sector"
Liquidity floorSkip an entry on any bar whose traded value was below a dollar figure, so the book never fills where the tape could not have"require at least $10m of daily volume", "skip anything trading under $1m"
Two different per-sleeve stops

The per-sleeve loss stop asks is this open position underwater, it closes anything trading below its own entry. The sleeve drawdown halt asks has this sleeve given back its gains, a coin that ran up 30% and round-tripped the lot never triggers the first one, because no single position was ever deeply below entry. Use the loss stop as a safety net on a leg with no stop of its own; use the drawdown halt to stop feeding an asset that has stopped working.

A count cap and a dollar cap say different things

"Cap memecoins at 15%" and "max 2 positions per sector" are not the same instruction. One oversized name can consume a whole notional cap on its own, while two small ones fit comfortably inside it. Use the notional cap to bound risk, the count cap to force breadth.

Timing and pacing#

ControlEffectSay
New positions per periodHowever many signals fire, only this many new positions open per bar, day, week or month. The strongest get the slots"open at most 1 new position per day"
Daily / weekly loss limitStop opening for the rest of the period once the book is down this much from the period's opening equity, in percent or in dollars, then resume next period"stop trading for the day after a 3% loss", "cap the daily loss at $500"
Quit while aheadThe profit mirror: stop opening once the period has banked its target. Entry-side: open positions keep managing themselves, so the banked number can still drift"stop for the day after making $1000", "done for the day once we're up 2%"
Re-entry cooldownAfter a sleeve closes, that asset waits this many of its own bars before it can be bought again"no re-entry for 5 bars"
Minimum holding periodA signal exit cannot close a position before it has been held this many bars"hold every position for at least 5 bars"
Scheduled flattenClose every open position on a calendar boundary, then carry on trading"close everything on Friday", "no positions over the weekend"
Trading calendarOnly open positions on these days or months"only trade Monday to Thursday", "don't trade in December"
QuartersOnly open in certain quarters"only trade in Q4"
Days of the monthSit out particular dates, or the days around month end"never trade on the 1st", "no trading around month end"
Trading hoursOnly open inside a UTC window, the intraday version of the calendar"only trade between 08:00 and 16:00 UTC"
One-off blackoutsSit out a named date range"don't trade between 2024-12-20 and 2025-01-05"
Book warm-upLet the book settle before it commits capital"wait 50 bars before trading", "skip the first month"
Total trade budgetA hard ceiling on trades for the whole run"no more than 100 trades in total"
Trades per periodThe same ceiling, per day, week or month"no more than 5 trades a week"
Entry spacingRequire a gap between any two entries, so the book cannot go on all at once"leave at least 3 bars between any two entries"
Turnover capBound annualized turnover as a share of equity, counting both sides of a round trip"keep annual turnover under 200%"
Breadth confirmationFund nothing unless this many sleeves signal on the same bar"only enter when at least 2 assets signal together"
Pacing is not the same as a position cap

"At most 3 open positions" bounds how much the book holds. "One new position a day" bounds how fast it gets there, a book allowed three names can still be told to leg into them one per day. And the daily loss limit is the recoverable twin of the book drawdown stop: that one halts for the rest of the run, this one sits out the session and starts again tomorrow.

Direction and regime#

ControlEffectSay
Gross long / short capsBound each side of a long/short book separately"max 60% long and max 40% short"
Positions per directionBound how many names each side may hold at once"at most 2 shorts at a time"
Net exposure capBound how far the book may lean either way"keep net exposure under 20%", or "run it market-neutral"
Equity-curve filterWhile book equity is below the average of its own recent equity, stop opening, or go fully to cash, and resume when the curve recovers above it"stop trading when the equity curve drops below its 50-day average"
Market regime gateNothing in the book opens unless a condition on another symbol holds"only trade when BTC is above its 200 day EMA"

A total exposure cap cannot express a market-neutral book: it reads a 100%-long book and a 50/50 long-short book as the same number. The net cap is judged across the whole bar, so a hedged pair is never refused for being "too long" on its first leg, only a lopsided bar loses its weakest name on the heavy side.

A minimum hold never gates your stop

It defers signal exits only, the indicator or comparison rule you wrote as your exit. A stop loss, take profit, trailing stop, liquidation and an explicit "exit after N bars" always fire, at any age. A minimum hold that swallowed a stop would be a risk, not a risk control.

A scheduled flatten also cuts your winners

Closing out every Friday removes weekend gap risk and removes every trend that would have run straight through the flush. It is a real trade-off, not a free safety measure, run the same book with and without it before keeping it.

An equity-curve filter cuts both ways

It damps long drawdowns, and it also guarantees you miss the first leg of every recovery, the curve has to climb back above its own average before the book will trade again. Judge it on the whole equity curve, not on max drawdown alone.

The regime gate can also act rather than merely pause, and it speaks plain words:

InstructionEffect
"go to cash when BTC drops below its 200 day MA"A regime break CLOSES what the book holds, not just new entries; positions re-open on their own signals when the regime returns
"go to cash in a bear market"Read as BTC below its 200-day SMA, flattening, both halves flagged as inferred
"avoid trading when BTC is dropping fast"BTC's 7-day rate of change staying above −10%, flagged as inferred
"only trade alts when BTC is stable"BTC's NATR(14) below 5%, flagged as inferred
"go to cash when @regime-score drops below 40"Your own uploaded series decides risk-on or risk-off for the whole book
The regime gate reads closed bars only

A daily regime filter on a 4h book reads the last completed daily bar, so there is no look-ahead. During the warm-up, before the regime series has enough history, the gate is closed a filter that has not resolved yet is not permission to trade.

Entry filters on each leg's own chart#

The regime gate above judges ONE symbol for the whole book. These ask the same question of EVERY chart separately, which is the shape most trader filters take: "only trade when ADX is above 25" means each leg's own ADX.

ControlEffectSay
Indicator filterEntries only while an indicator condition holds on that chart"only trade when ADX is above 25", "only enter when RSI is below 70"
Custom filterThe same gate driven by your own uploaded indicator"only trade when @trend-score is above 70"
Price vs its own averageThe per-chart trend filter"only go long when price is above the 200 day moving average"
Trend alignmentLongs above the average, shorts below it: one instruction, two mirrored conditions"only trade in the direction of the 200 EMA"
Chop avoidanceADX above 20, the conventional trend floor, flagged as inferred"avoid choppy markets"
Blocked entries are ledgered; exits never are

The signal still fires and lands in the skip ledger with its own reason, so the report shows how much the filter discarded. An open position always exits by its own rules, even when the filter has turned against it. And the filter fails CLOSED, a condition that cannot be evaluated blocks the entry rather than silently opening the book.

Sessions and day boundaries#

ControlEffectSay
Named sessionsAn approximate UTC window (London 08:00-16:00, New York 13:00-21:00, Tokyo 00:00-08:00) flagged as inferred"only trade the London session"
Start every day flatFlush the book on each UTC day's last bar; re-enter on signals next morning"start every day flat", "don't hold overnight"
Avoid the open / closeThe crypto day opens at 00:00 UTC"avoid the first hour after the open", "no new positions in the last hour"
First hours onlyThe mirror: only the day's opening burst"only trade the first two hours"

Costs and execution#

A backtest with no fees and instant fills is a brochure, not a result. Both are stated once for the whole book.

ControlEffectSay
Fees and slippageApply the same cost assumption to every leg"use 0.1% fees and 0.05% slippage across the book"
Fill delayModel the gap between a signal and a fill by entering N bars later"assume a 1 bar delay on every entry"
Next-open fillsFill every entry at the NEXT bar's open instead of the signal bar's close, removing a free fill at the very price the signal was computed from"assume I get filled at the open of the following day"
Short borrowCharge the annual borrow rate as a per-bar carry on every open short. Name the book's timeframe: an annual rate cannot be converted without it, and the run declines rather than guessing"shorts cost 6% a year to borrow"
Cash yieldCredit interest on idle cash, so a defensive book is not silently punished for being defensive"earn 5% on the cash we are not using"
The two assumptions that flatter a book most

A signal computed at a bar's close cannot also be filled at that close: next-open fills remove that free fill, and they will make almost any result worse. That is the point. The mirror case is cash yield: with idle cash earning exactly 0%, a book that correctly sat out a bad quarter still loses to a benchmark that compounded through it, and the comparison says nothing about the strategy. Turn both on before you compare two books.

Zero fees is a choice, not a default you can ignore

A frictionless run draws an honesty flag for a reason: at a few trades a month it barely matters, and at several a day it is the difference between a strategy and a fee generator. Run your real cost assumption before you believe a high-turnover book.

One stop and one target for every position#

The most-used trader instruction of all, stated once for the whole book instead of repeated on every leg. An exit is added only where the leg does not already carry one of that type, the leg's own rule wins, and the result reports which legs took the book's exits and which kept their own.

ControlEffectSay
Book stopA percentage stop on every position"put a 2% stop on every position"
Book targetA percentage target on every position"take profit at 8% on every trade"
Book trailing stopTrail each position behind its own peak"trail every position 3%"
ATR stopA volatility-sized stop, a calm coin and a wild one get different distances from the same instruction"use a 1.5 ATR stop on every position"
ATR trailThe trailing version of the same idea"trail every position with a 2 ATR stop"
Indicator exitClose each position when its own chart says so"close every position when RSI is above 80"
Time stopClose a position that has run out of time rather than price. Lowest priority: a trade that worked has already left by its own exit"time stop after 20 bars", "exit if the trade has not worked in 10 bars"
Max holding timeThe calendar phrasing of the time stop, the ceiling that pairs with the minimum-hold floor"only hold trades for a maximum of 5 days"
Book exits need book scope

"Put a 2% stop on every position" is a book instruction; a bare "stop loss 2%" belongs to the leg that says it. That anchoring is what lets both live in one prompt without stealing from each other. An ATR exit on a series where ATR genuinely cannot be computed is refused and reported, never silently added, a stop the engine can never fire would leave the position unprotected while the config says otherwise.

The risk unit#

Traders think in R: what a trade risks, and what it pays if it works.

ControlEffectSay
Reward-to-riskEvery leg with a percentage stop gets a target at stop × R"risk 1% per trade with a 2 to 1 reward to risk", "target 2R on every trade"
Fixed dollar riskSize so a stop-out costs a stated amount. Does NOT compound, that is the point of stating it in dollars"size every position so it risks $500"
Per-trade ceilingA cap, not a sizing rule: a leg asking for less keeps its size, one asking for more is trimmed"never let one trade lose more than 1% of the account"
Portfolio heatThe open-risk budget, under the name traders use: distance-to-stop × size summed across open positions"keep total heat under 6%"
Risk in wordsSub-1% risk written the way people write it"risk half a percent per trade"
An R target that cannot compile is reported, never skipped silently

R is a ratio, so it needs a percentage stop to multiply. A leg with an ATR or swing stop, or one that already states its own target, is listed in the result as skipped, "target 2R" that quietly did nothing on half the book is worse than an error.

Scaling out#

ControlEffectSay
LadderTake profit in pieces; whatever the rungs don't add up to keeps running"sell a third at 5%, a third at 10%, and hold the rest"
R-denominated rungA rung at a multiple of the leg's own stop"scale out half at 2R and let the rest run"
Partial then fullHalf at the first level, everything left at the second"partial exit at 5% and full exit at 10%"

Sizes are shares of the ORIGINAL position: "a third, then a third" really closes a third each time, with the remaining-quantity arithmetic handled for you. Slices appear on the closed trade as partial exits, the same shape the single-asset report already renders.

Pyramiding discipline#

ControlEffectSay
Never average downRefuse any add while the position is at or below its blended entry"add to winners only", "never average down"
Pyramid capTotal entries per position, the opener included"pyramid up to 3 entries"
…counted in addsThe same cap stated the way people actually say it. Two adds is three entries, because the opener counts"add to a winner at most twice"

A refused add leaves the position exactly as it was and is counted in the result, a disciplined book shows what it declined rather than looking like the adds never fired.

Protecting a profit#

ControlEffectSay
Book profit lockA ratchet: once the book is up past a trigger, defend a floor. The floor only ever moves up, so a give-back cannot unwind a lock already earned"once the book is up 20%, never let it go below breakeven"
One-number profit lockThe same ratchet with only the trigger stated, the floor is inferred at half the trigger, and the result says so"lock in profits above 20%", "protect gains once up 15%"
Give-back fractionThe book trailing stop as a fraction of the peak"give back no more than a third of the peak"
Book trailing stopTrail the whole book a fixed distance behind its own peak"trail the book 10% off its peak"
Stop managementMove every position's stop to breakeven, or start trailing it, once it is far enough in profit"move every stop to breakeven after +5%"

Sizing that responds to something#

All of these are multipliers on the size you asked for, and they compose: with a ceiling, so several cannot conspire into a position nobody asked for.

ControlEffectSay
Size by recent recordCut size after a losing streak, press after a winning one"halve size after two losses", "double size after two winning trades"
Ease into full sizeRamp from a starting exposure to full size over a period"start at 25% exposure and scale to 100% over 3 months"
Kelly fractionSize from the book's own measured edge"use half Kelly sizing"
Market-state rulesA multiplier gated on a condition, judged on each leg's own chart at entry"halve size when ADX is below 20", "reduce size in high volatility"
Custom convictionThe same rule driven by your own uploaded indicator"double size when @conviction is above 80"
Kelly on five trades is noise wearing a formula

The Kelly size is computed from the book's own closed trades and stays inert below 20 of them. A bare "Kelly sizing" is read as half Kelly and the result says so, full Kelly is far too volatile to run, and a measured edge that turns out to be negative sizes to zero rather than short.

Circuit breakers#

The count-based cousins of the daily loss limit: that one counts percent lost, these count events.

ControlEffectSay
Losing-streak haltStop opening for the rest of the run after a run of losing trades"stop the book after 5 consecutive losing trades"
Losing-streak pauseStand down for a number of bars, then come back"pause for 5 bars after 2 losses"
Done for the dayStand down for the rest of the day, week or month"stop trading for the rest of the day after 2 losses"
Losing periodsStop after a run of losing days, weeks or months"stop trading after 3 losing days in a row", "halt after 3 losing weeks"
Performance floorStop once the measured win rate or profit factor falls through a floor"stop if the win rate drops below 40%"
Rolling Sharpe floorStop opening while the risk-adjusted record is under a floor, the drawdown-blind twin of an equity-curve filter. State no window and it is read over the last 60 equity points, and the run tells you it assumed that"stop trading if the rolling sharpe drops below 0.5", "stop opening while our 90-day Sharpe is negative"
Behind the benchmarkA RELATIVE drawdown stop: the book can be UP and still trip this, because what it measures is the gap to buy-and-hold"benchmark against BTCUSDT buy and hold and stop trading if we underperform the benchmark by 15%"
A breaker stops you opening, it never liquidates

"Stop trading" means take no new risk. Anything already open still manages itself by its own exits, because closing a book at whatever the market happens to be showing is a different instruction from the one you gave. A performance floor is also inert below 20 closed trades: halting a book on noise is worse than not halting it.

Aiming a control at one coin#

Almost every control above can name a single asset instead of the whole book. The more specific statement always wins.

text
Cap BTCUSDT at 40% and ETHUSDT at 20%.
Risk 2% on BTCUSDT and 1% on ETHUSDT.
Stop BTCUSDT at 10% and cut ETHUSDT if it's down 8%.
Hold ETHUSDT for at least 5 bars.
Wait 10 bars before re-entering BTCUSDT.
A per-coin control must name a coin the book holds

Aiming a cap at an asset that is not in the portfolio is refused rather than quietly dropped, a cap that silently is not there reads exactly like a cap that is.

Custom indicators at the book level#

Anywhere a built-in indicator works in a book-level control, a custom (@-named) indicator you have uploaded works too. The series is loaded per leg through the same resolver a leg's own custom condition uses, so an unknown name fails the run loudly instead of gating on a column that is not there.

SurfaceSay
Entry gate"only trade when @trend-score is above 70"
Position sizing"double size when @conviction is above 80"
Book regime, and go to cash on it"go to cash when @regime-score drops below 40"
Rotation ranking"hold the top 2 by @score, rebalance weekly"
Position exits"close everything when @exit-score is above 80"
Two failure postures, on purpose

An entry filter that cannot be evaluated blocks the entry, a gate that is not there must not silently open the book. A sizing rule that cannot be evaluated leaves the size alone, a rule that is not there must not zero a position the strategy asked for. One is permission, the other is adjustment, and each fails in the direction that does less damage.

Capital deployment and signal selection#

InstructionEffect
"only take the strongest signal each day"Strength contention picks WHICH signal wins the capital; a one-per-day allowance decides HOW OFTEN
"rank the signals and take the best two"When five sleeves fire together, the two best-ranked open and the rest are ledgered
"trade with 50% of capital and keep the rest in reserve"The cash-reserve floor, stated from the deployed side
"deploy capital gradually over the first month"An exposure ramp from 0% to 100% of the stated size, flagged as inferred
"withdraw profits monthly"ALL of the gain out each month: flagged as inferred, because it turns off compounding and you should see that stated

What the book is measured against#

Every portfolio is compared to a benchmark, and by default that is an equal-weight buy-and-hold of the book's own constituents. That is often not the comparison you meant, so you can say which one you want.

BenchmarkSay
Buy and hold one asset, including one the book does not trade"compare it against BTC buy and hold"
A stated mix, bought once and left to drift"compare to a 60/40 BTC ETH portfolio"
The same mix, systematically rebalanced"compare to a 60/40 BTC ETH portfolio rebalanced monthly"
Cash, a flat line at your starting capital"compare against sitting in cash"

Whatever you pick becomes the denominator for the numbers that actually answer "was this worth it": outperformance, beta, correlation, annualized alpha, tracking error, information ratio, and up/down capture. Add "assume a 4% risk free rate" and the alpha is measured over that hurdle instead of zero.

A blank statistic means unmeasurable, not zero

Beta against cash is not zero, it is undefined, a flat benchmark has no variance to regress against. The report leaves those fields empty rather than printing a number it cannot justify. Against cash, the outperformance figure is the whole story.

A rebalanced benchmark is a harder bar

"A 60/40 portfolio" normally means one bought 60/40 and left alone, so that is the default. Saying "rebalanced monthly" makes it systematically rebalanced, which harvests the mean reversion between its legs and is materially harder to beat in a choppy market.

Deposits and withdrawals#

A book can also move money across the account boundary on a schedule: pay in every month, or take a share of the profits out.

InstructionEffect
"add $1000 to the account every month"Cash is added to the pool; the strategy then puts it to work on its own signals
"withdraw 20% of profits every month"A share of the gain above the starting capital is taken out
"take out $2000 each month"A fixed amount is taken out

This is not the same instruction as DCA. Dollar-cost averaging deploys the pool the book already has, buying a fixed amount on a schedule. A deposit grows the pool and leaves the timing to your rules. A withdrawal only ever comes out of cash the book is actually holding, it never sells a position to fund one, and a profit share never touches the starting capital.

Deposits flatter the raw return

Money you paid in raises the final equity without the strategy earning a cent, so a plain "total return %" on a contributed book is not a performance figure. The report carries a contribution-adjusted return measured against the money actually put in, with withdrawals added back, that is the number to judge the book on. It is reported for every cash flow, however you phrased it.

State each flow once

A book may state each cash flow once. "Withdraw $1,000 a month" is one instruction; saying it twice, once in prose and again as an explicit setting, used to make the book pay out twice, so an overlapping pair is now refused by name rather than applied silently. Deposits, fixed withdrawals and profit shares are each independent, so a book can state all three.

A withdrawal and a profit share are each carried by their own setting at every cadence monthly, quarterly or yearly, so the same instruction never lands on a different key depending on how often it repeats. A deposit is the one flow with a single home, since dollar-cost averaging is a different instruction: it deploys the pool the book already has rather than growing it.

Cross-asset conditions#

One asset's entry can depend on another. Gate a trade on a second symbol and the splitter attaches it as a cross-asset condition on the dependent asset.

text
When BTC RSI crosses above 65 on 1d, if ETH RSI is above 50, buy ETHUSDT.
Entry gating is live, exit gating is not

A cross-asset condition that gates an entry runs at execution time. Cross-asset exit conditions are not live yet: a book that relies on one is refused before it runs, with the note "aux signal exit: pending parity". Rewrite the exit as a stop, a target, or a same-asset condition.

Reading the book report#

A portfolio report shows what a single backtest cannot.

  • Book equity versus its benchmark. The shared equity curve plotted against the benchmark, with a beating or trailing readout. The benchmark is an equal-weight buy and hold of the same assets unless you asked for another one; see What the book is measured against and it carries the relative numbers alongside it: outperformance, beta, correlation, alpha, tracking error, information ratio, and up/down capture.

  • Per-asset results. Either full per-asset panels (grade, equity, trades) or a Per-asset attribution table (realized P&L, trades, win rate, exposure). Per-asset return and Sharpe are drawn on an equal-base display axis, a slice of the pool, not standalone capital.

  • Skip ledger. Every entry signal that did not fill, with its reason. Read it before concluding a strategy did nothing: a book that suddenly trades less is usually a control doing its job.

    ReasonWhat happened
    NO_CAPITALthe signal fired but the shared pool had no cash left for it
    BELOW_MIN_NOTIONALthe affordable size was under the exchange minimum
    GUARDa per-asset gate blocked it (session window, time filter, trading guard)
    PRE_LISTING / STALE_BARthe asset had not listed yet, or had no bar closing on that tick
    PER_ASSET_CAP / MAX_CONCURRENT / EXPOSURE_CAPa size or count cap was already reached
    CORRELATION_LIMITits returns were too correlated with a position already open
    GROUP_CAP / GROUP_POSITION_CAPits sector was at its exposure cap, or already held its maximum number of names
    TRADE_THROTTLEthe book had already opened its allowance of new positions for the period
    LOSS_LIMIT_PAUSEthe book was paused for the rest of the period after hitting its loss limit
    REENTRY_COOLDOWNthe sleeve was still inside its post-exit cooldown
    LONG_EXPOSURE_CAP / SHORT_EXPOSURE_CAP / NET_EXPOSURE_CAPit would have pushed exposure past a directional cap
    CASH_RESERVEfunding it would have spent the book below its cash reserve floor
    EQUITY_CURVE_FILTERthe book's own equity was below its moving average, so it was standing down
    REGIME_OFFthe book-wide regime filter was risk-off on that bar
    DIRECTION_MAX_POSITIONSthe book was already holding its maximum number of positions on that side
    SLEEVE_HALTEDthat asset was retired for the rest of the run by the sleeve drawdown halt
    BOOK_TIME_FILTER / DATE_BLACKOUTthe book does not open on that day, hour or month, or the date fell inside a blackout window
    DIRECTION_BIASthe book is restricted to one side and that signal was on the other
    WARMUPthe book was still inside its settle period
    TRADE_BUDGET / TRADE_PERIOD_BUDGETthe trade allowance for the run, or for this period, was spent
    ENTRY_SPACINGit came too soon after the previous entry
    TURNOVER_CAPannualized turnover was already at its ceiling
    CONFIRMATIONfewer sleeves signalled together than the book requires
    BELOW_BOOK_MIN_NOTIONALit would have been smaller than the book's own minimum position size
    OPEN_RISK_CAPfunding it would have pushed total open risk past the book's budget
    GROUP_MAX_POSITIONSits sector/group was already holding its maximum number of positions
    ASSET_TRADE_THROTTLEthat sleeve had already opened its allowance of positions for the period
    PER_ASSET_NOTIONAL_CAPthe sleeve was already at its dollar cap for open notional
    PERIOD_LOSS_LIMITthe book was stopped for the rest of the period after hitting its loss limit
    LOSS_STREAK_PAUSEthe loss-streak breaker had paused new entries
    DAILY_GIVEBACK_STOPthe book had given back too much from the day's peak and stopped for the day
    OUTSIDE_TRADING_DAYSthe bar fell outside the weekdays the book may open on
    OUTSIDE_TRADING_HOURSthe bar fell outside the session window the book may open in
    BLACKOUT_DATEthe bar fell inside a date range the book sits out
    DIRECTION_NOT_ALLOWEDthe book is restricted to the other side (long-only or short-only)
    BELOW_MIN_VOLUMEthe bar traded less value than the book's liquidity floor
    BELOW_MIN_TRADE_NOTIONALthe final size, after every cap, was under the book's minimum trade size
    BELOW_MIN_SIGNAL_MARGINthe signal did not clear its own threshold by the required margin
    BENCHMARK_LAGGINGthe asset had not outperformed the benchmark over the lookback
    INSUFFICIENT_HISTORYthe asset did not yet have the minimum bars of history behind it
    ROLLING_SHARPE_FLOORthe book's rolling Sharpe was below its floor
    TOP_N_CONCENTRATIONthe fill would have pushed the largest N positions past their combined cap
    ASSET_RETIREDthe sleeve had lost too much and stopped taking new signals
    WIN_STREAK_BREAKERthe book was standing down after a run of winning trades
    ASSET_ATTEMPT_CAPthat coin had already used up its allowance of entry attempts
    OPEN_LOSS_GATEa position the book already held was too far underwater to take new risk
    DRAWDOWN_PAUSEthe book was too far below its high to open anything new, and had not recovered yet
    BIG_LOSS_COOLOFFthe book was cooling off after a single trade lost more than its limit
    BAR_ENTRY_CAPthe book had already opened its allowance of positions on that bar
    SIGNAL_EXPIREDa signal the book could not fund waited too long and was dropped
    SIGNAL_NOT_HELDthe entry condition fired but had not held for long enough
    SIGNAL_TOO_WEAKit cleared its own threshold by less than the other signals on that bar
    BETA_CAPthe book's beta to its benchmark was already at its ceiling
    BELOW_MIN_PRICEthe asset was trading below the minimum price the book will touch
    VOLATILITY_STANDDOWNthe book's own realised volatility was above its ceiling
    CLUSTER_CAP / SYMBOL_POSITION_CAPits correlation cluster, or that symbol, was already full
    LOSS_STREAK_BREAKER / LOSING_PERIOD_BREAKERthe book was standing down after a run of losing trades, or of losing days
    PERFORMANCE_FLOORthe book was halted because its win rate or profit factor fell through its floor
    ENTRY_FILTERthe book's entry filter was not satisfied on that leg's own chart
    PROFIT_LIMIT_PAUSEthe book had banked its profit target for the period and was done trading it

    Some controls act on exits or on the account rather than on an entry signal, so they never appear in this ledger. They are counted separately, under the book's risk controls: a minimum hold deferring an exit, a scheduled flatten, a sleeve being retired, positions being sized down or up by a responsive or market-state sizing rule, a position resized to a stated dollar risk or trimmed to its per-trade ceiling, an R target added to a leg, a time stop firing, an add refused by the pyramiding discipline, the book sent to cash by a regime break, a delayed fill, the book's profit floor closing it out, and each deposit or withdrawal.

    Three entries in that ledger are not a control turning a signal away, and the report marks them as such: ENTRY_FILTER_UNREADABLE means the filter could not be measured on that asset it did not fail the filter; NO_NEXT_BAR means the signal fired on the last bar of the data and a next-open fill needs a bar after it; and LIMIT_NOT_FILLED means the bar never traded through your limit, an execution miss rather than a rule. No fill is ever invented to hide one.

  • Run warnings. What the engine decided, said out loud. Three of them mean the run's numbers are not comparable with a default run and are styled to say so: BOOK_COSTS_APPLIED (one cost model replaced every leg's own), FILL_TIMING_NEXT_OPEN (entries filled at the next open, not the signal close) and COMPOUNDING_OFF (every position sized off the starting capital). AVERAGED_DOWN is styled as a warning of its own, it is the only family that adds risk to a losing position.

  • Money that moved outside trading. Withdrawals, profit shares and interest on idle cash all change what final equity means, so the header names them beside it. A shortfall count means a scheduled payout could not be funded in full.

  • Retired sleeves. If the sleeve-retirement rule fired, the report names which asset the book gave up on and what it cost, usually the most actionable line in the whole thing.

  • Book grade. One letter grade for the whole book, from the same grader as a single backtest, alongside book-level Monte Carlo and walk-forward robustness.

You can share a book as a read-only /sp/<token> page, and export the merged trades as CSV or the full result as JSON.

Known limits#

These are behaviours that are correct but surprising, the ones most likely to make a run look broken when it is doing exactly what it was told.

  • Spacing between entries is measured across bars, not within one. "Leave 3 bars between any two entries" stops the book opening on bar 3 and again on bar 4. It does not stop three sleeves that all signal on the same bar from all opening at once, zero bars have passed between them. To bound a single bar's burst, say "at most one new position per bar"; the two rules compose.
  • A total trade budget can finish slightly over. "No more than 100 trades" stops the book opening once 100 have booked, but positions already open still run to their own exits and book as they go. The overshoot is at most the number of positions open when the budget was reached; cap concurrent positions (or new positions per bar) to bound it.
  • "Require the signal to hold for N bars" cannot be met by a crossover. A crossover is true on exactly one bar by construction, so asking it to hold for two blocks every entry and the book takes no trades. That is the rule being unsatisfiable, not an absence of edge, the run says so in its warnings. Use a threshold-style entry ("RSI is below 30") for a signal that can persist.
  • A stand-down phrasing names the side you sit out. "Stop trading when the equity curve drops below its 50-day average" means trade while above it. Both readings are supported, "only trade while equity is below its average" is a valid, if unusual, instruction, so the wording decides, and the report echoes the side the book actually traded on.
  • A rotation that holds cash is the momentum floor working. "Only while their momentum is positive" is an instruction to sit out, so a flat stretch with no trades in a falling market is the control doing its job, not a rotation that failed to rank. The run distinguishes the two: one warning says nothing cleared the floor, a different one says nothing could be ranked at all.
  • A minimum number of holdings cannot be honoured. "Always hold at least 3 positions" is declined out loud. A signal-driven book can decline exposure but never manufacture it: there is no entry to take when nothing has signalled. State it as an allocation instead ("equal weight the book, rebalance monthly"), which holds targets rather than waiting for signals.
  • A liquidity floor filters bars; it does not pick names. "Require $10m of daily volume" skips entries on thin bars for the assets you named. Choosing which assets to trade by liquidity or market cap is refused: it needs a point-in-time constituent list, and ranking today's names over history would put survivorship bias into every bar.
  • Spot crypto only in v1; equities are rejected. A book holds up to 20 assets.
  • Mixed timeframes are allowed. The book merges assets on absolute close time and reports the equity curve on the coarsest timeframe in the roster.
  • Per-asset return and Sharpe use an equal-base display axis, not standalone capital. Win rate, profit factor and trade counts are each asset's real numbers.
  • If the book hits the equity floor it halts early and flags ruin.
  • Futures books are not supported yet.
  • Starting capital stated in the prompt ("a $250k book") is carried into the run. If you drive the API or the MCP tools yourself, pass the settings object parse_portfolio returns straight to run_portfolio, it holds every book-level control the prompt stated, and a book run without it is a book without your risk limits.

Next: Build a portfolio step by step, or the MCP tools to run one programmatically.