# Combining return streams

A set of legs carries as many bets as its correlations allow. The allocation readings weight the columns of one run, and the columns are settings of one rule.

## Compare tested configurations by risk and return

The display below compares configurations from a parameter search. Each point represents a tested configuration; it does not certify an optimized allocation across strategies.

[Screenshot: Efficient frontier in Stochastly, Parameter search · 24 configs, light theme.](https://stochastly.com/screenshots-current/docs-guide-portfolios--efficient-frontier--search.png)

Risk and return across the configurations of a recorded parameter search. The input data are generated for demonstration.

## What a combination buys, and what it repeats

A combination pays when the errors of its legs land on different dates. Equal-weighting a set of legs drives the variance of the set toward the average covariance among them, so the idiosyncratic part of the risk shrinks with the count and the common part stays where it was. The count of legs sets a ceiling on what can shrink; the correlations set the level reached.

The measurement that settles a claim of diversification is therefore the correlation among the legs, taken before their number. One rule applied across many markets, many timeframes and many parameter settings produces legs that carry the same signal, and such a set holds close to a single bet under several labels while paying a cost for each label.

This is the reading the portfolio nodes are built around, and it is available on a run you have already produced. What follows states which part of it the shipped build computes, over which columns, and where the boundary of that computation lies.

- what a combination reduces: the risk that is specific to a leg
- what it leaves in place: the exposure the legs hold in common
- what settles a diversification claim: the correlation among the legs, read before their count

## The matrix a swept run produces

A run that sweeps a parameter space produces one P&L series per configuration that traded. Those series are stacked into a matrix with one column per configuration, truncated to the common length they share, and sampled down to a declared cap on the number of columns. The portfolio readings take that matrix as their input. The sampling flag travels with the multiplicity reading of the same run, and an allocation result carries no flag of its own for it, so a run wide enough to be sampled is checked there.

The columns are settings of one strategy. A graph carries one strategy slot per build, so a second strategy node placed on the canvas is left unwired and named as such in the note the build returns. What the allocators weight is a family of settings of a single rule, measured over one window, on the instruments that run loaded.

Below a declared minimum of bars and of finished configurations, an allocation reading comes back as insufficient, carrying the shape of the matrix it received and the two minima it required. A column whose series cannot be read as finite numbers leaves the pool on its own, so a single unreadable configuration leaves the others measurable.

- one column: one configuration that traded, over the window the columns share
- strategy nodes per build: one; a second is left unwired and named in the note
- under the declared minima: the reading returns insufficient, with the shape it received

## Why the covariance is the fragile input here

Weights proportional to the inverse covariance load on the legs with high estimated return, low estimated variance and negative estimated correlation, which is where the estimation error is largest. As the number of columns approaches the number of observations, the sample covariance becomes ill-conditioned and the inversion amplifies its smallest and least reliable directions.

Neighbouring settings of one grid are close to collinear, so this is the ordinary case for the matrix described above. The shipped allocators add a ridge proportional to the trace before any inversion, and each result names it. Without that term, a minimum-variance solve on near-collinear columns returns large weights of opposite signs, which are exact figures that would ruin an account.

The eigenvalue band of a pure-noise correlation matrix gives a null model for how many modes carry structure. It assumes independent entries with finite variance, and returns are fat-tailed, heteroskedastic and serially dependent, so a count of eigenvalues above the upper edge reads as a lower bound on the modes that carry something.

The reference arm for any optimiser is equal weighting. Work across several datasets found that estimation error can swamp the theoretical gain, with no optimiser consistently ahead of equal weights out of sample, so an equal-weight arm belongs beside a weighted one before the weighted one is believed.

- what the inversion amplifies: the smallest and least reliable directions of the covariance
- what the shipped allocators add: a ridge proportional to the trace, named in each result
- the arm to keep beside a weighted one: equal weighting, on the same columns

[Screenshot: Correlation dendrogram in Stochastly, Full desk · 155 nodes, light theme.](https://stochastly.com/screenshots-current/docs-guide-portfolios--correlation-dendrogram--desk.png)

The instrument correlation matrix is reordered by similarity to expose overlapping exposures.

## What is solved, and what is refused

The optimisation and portfolio family ships 44 nodes, of which 33 are validated by executable checks, and 11 are counted as roadmap. Minimum variance, the tangency portfolio, mean-variance, the efficient frontier, equal risk contribution, hierarchical risk parity, the correlation matrix of the columns and the risk contributions of a weight vector are among the validated set.

Minimum variance and tangency are closed-form solves in linear algebra, with no search and no draw in the path. The tangency solve is refused when the resulting weights sum to a non-positive number, since renormalising there would flip the sign of the entire vector and return a short book that no one entered. What the solve constrains is that sum, and an accepted vector can carry negative weights on individual columns, which the published weights and the largest-weight figure make visible. A mean-variance node asked for weights with no return target uses the tangency solution where it exists and falls back on minimum variance where it does not, stating which of the two produced the figures.

The efficient frontier is swept without a solver. Any convex combination of the minimum-variance and tangency portfolios lies on the frontier, so the node walks that segment and publishes the return and the volatility of each point. The curvature of the resulting line is what the diversification is worth on those columns.

Equal risk contribution is solved by a damped fixed point. The two updates found in textbooks were measured on this data and both diverged, one exploding on a near-zero contribution and the other oscillating until a single column held the weight; the damped form converges in a small number of passes with the dispersion of contributions driven to zero. The node reports the passes performed against the cap read from your setting, the dispersion reached, and a statement that convergence is unproven where the cap binds.

Hierarchical risk parity takes the correlation distance among the columns, builds the tree, reorders the covariance so that similar columns become adjacent, then splits top-down and allocates between two sub-clusters in inverse proportion to their cluster variance. It performs no matrix inversion and requires no positive-definiteness, which is what lets it stand on the near-collinear columns where minimum variance becomes unstable.

- the closed-form solves: minimum variance and tangency — linear algebra, no search, no draw
- when tangency is refused: weights summing to a non-positive number, which would return a short book
- what the fixed point publishes: passes performed, the cap they ran against, and the dispersion reached

[the nodes themselves](https://stochastly.com/docs/nodes): Node catalogue

## The columns a weight vector publishes

Each allocator publishes the same reading columns, so two of them are comparable on one run: the weights, the volatility of the weighted combination, the dispersion of risk contributions, the largest single weight, the sum of the weights, and the effective number of positions computed as the inverse of the sum of squared weights. The regularisation that was applied travels with the figures.

Total risk splits additively across the legs, which is what makes a risk contribution a quantity and a capital weight a different quantity. Under equal capital, the highest-volatility leg carries most of the risk, and an allocation that equalises contributions moves capital toward the quieter legs. Publishing both figures beside each other is what keeps the two readings distinguishable on a screen.

The catalogue declares an iteration count and a seed on the allocation nodes. The closed-form ones report both as carrying no effect on their calculation, with the reason stated, and the fixed-point ones report where the iteration value came from. A field on a screen with no reader behind it would suggest a setting that reaches no calculation.

These weights are a reading. They exclude no configuration, they replace no gate, and the verdict of the run comes from the gates you wired. A reading whose figure comes back non-finite is published as absent, since a value that does not exist and a value of zero read differently.

- the effective number of positions: the inverse of the sum of squared weights
- risk contribution against capital weight: two quantities, published beside each other
- what an allocation reading changes in the verdict: none of it; the wired gates settle the run

## Choosing the legs before weighting them

A decorrelated selection starts from the column with the best mean and adds, at each turn, the candidate whose highest correlation to the already-chosen set is lowest. The correlation is signed, so an anti-correlated leg ranks ahead of an uncorrelated one, and taking absolute values there would erase the information that matters. No basket size is imposed: the output is a curve over sizes, with a basket picked by mean alone at the same size published beside it as a control.

The effective number of bets is the quantity that curve reports. Computed from the eigenvalues of the basket correlation, it is exact at both ends: identical columns return a single bet, independent columns return their count. A basket holding more lines than bets pays several costs for one idea, and that gap is the figure to look at before the mean return of the basket.

A Pareto front is available over mean return, deepest trough and volatility, naming which configuration is dominated by which. Turnover is declared absent from the objectives, with the reason: the run publishes no position journal into that module, and volatility takes its place under its own name in the output.

A greedy hybridisation adds a leg while the Sharpe of the equally weighted mixture improves strictly, and it stops on a comparison with a declared numerical tolerance, with no performance level required anywhere. A path that retains a single leg is a result: the remaining columns carry no component the first one lacks. The mixture is equally weighted, and weighting it is the work of the allocation nodes described above.

A behavioural archive offers the third route. The columns are placed on a grid of behavioural cells whose axes are the pair covering the most cells on your data, one elite is kept per occupied cell, and the resulting basket is compared with a basket picked by mean alone at the same size on cells covered and on effective bets. Where the two baskets coincide, the mean-picked one was already spread out, which is a result as well.

- what the greedy selection minimises: the highest correlation to the set already chosen, signed
- what a basket of identical columns returns: a single effective bet
- turnover in the Pareto objectives: declared absent, with volatility named as the replacement

## A composition picked on the window before it

Holding a fixed basket across an entire sample assumes the choice was available at the start. A walk-forward composition scheduler removes that assumption: what a window holds is picked using the window that preceded it, the composition of each window is published, and the count of changes is reported beside it.

Three controls travel in the same output: the composition frozen from the first window, equal weighting, and a retrospective pick named as unreachable. The test behind the node is built on a world where the leader of a window becomes the laggard of the next, so a scheduler reading ahead would win there and this one loses, which is what makes the absence of forward reading measurable from outside the module.

- what a window's composition is picked on: the window that preceded it, with no later bar in the path
- what is published per window: the composition itself, so a forward read would be visible
- the third control: a retrospective pick, named as unreachable

## Which names carried the curve

For a graph loading more than one instrument, the best configuration is re-run per symbol and the result carries the P&L each name contributed, ordered by size and capped at a declared count. Where the index carries dates, the contribution is split by year, so the question of which name carried which year is answerable. The re-run has two requirements: the backend that ran the graph has to expose the per-symbol path, and the kernel has to be one that path covers, so a run outside those two returns the result with the breakdown absent.

That split is omitted where the index has no dates, and its absence is left absent, since a missing breakdown and a flat year would read the same if the missing one were filled with zeros. This reading covers concentration across instruments for the configuration the run selected, and it covers the configurations of one rule.

- what the attribution covers: the best configuration of that run, per symbol
- when the yearly split appears: where the loaded index carries dates

[Screenshot: Instrument attribution in Stochastly, Full desk · 155 nodes, light theme.](https://stochastly.com/screenshots-current/docs-guide-portfolios--instrument-attribution--desk.png)

The instruments that added to and detracted from the recorded strategy result.

## What a book across separate strategies would still require

The readings above operate inside one run, over the settings of one rule. Combining two different rules into one book requires an input the shipped catalogue does not offer: a node accepting several finished series as the columns of one matrix, and a store that outlives the run that produced them. Those two are the condition under which this part stops describing a boundary.

Two consequences follow for a reader, and both are readable today. A correlation measured among the configurations of one rule carries no information about the correlation between two different rules, so a low figure there leaves the correlation of a book unmeasured. And the price of the search is computed per run, so a program spread over several runs is priced by each of them separately.

What is available in the meantime is a procedure. Run each rule as its own graph, with its own cost nodes, its own wired gates and its own selection price, and read each result on its own terms first. Export the series each run produced, then combine outside the harness, keeping the window, the cost model and the risk unit matched across the arms; an unmatched window is the difference that would otherwise be read as a diversification benefit.

One measurement stays out of reach in this build. A factor bet held inside one leg appears nowhere in the matrix of correlations between legs, so legs that correlate weakly with each other can carry a large common exposure. The measurement that settles that question is a regression of the combined series on tradable factor returns, read with its coefficients, their t-statistics and the share of variance left unexplained, and the shipped catalogue carries no node emitting it.

- what a book would require: a node taking several finished series as columns, and a store outliving one run
- what a low correlation among configurations covers: that one rule's settings, and no pair of different rules

[the domain over which a result holds](https://stochastly.com/research/gaps): Validity domain

## The portfolio nodes carrying a badge, and what stops each one

A roadmap badge in the catalogue and a proof are two separate facts, and the count above takes the proof first. Equal risk contribution, the risk-contribution bars and the weights allocation each carry the badge in the shipped catalogue and a test that names them, so they are counted among the validated set and the badge on them is behind the code.

For the portfolio nodes counted as roadmap, two kinds of blocker are recorded. One is a general convex solver, which this build does not carry: constraints on turnover, leverage and cardinality, robust optimisation over an uncertainty set, a tail-risk objective solved as a linear program, and the general solver node itself stand behind that dependency.

The other is an input the canvas has no field for. Blending equilibrium weights with your own views requires those views to be entered somewhere, and a risk budget per leg requires a place to declare the budget. Wiring either with invented values would impose a decision that no node on the graph declares, which is the reason recorded for leaving them badged.

Those reasons are recorded by the calculation but absent from the node descriptions. A reader opening one of them sees the badge without the missing input named beside it.

- the first blocker: a general convex solver, absent from this build
- the second blocker: an input the canvas has no field for: views, or a per-leg risk budget
- where each reason appears: in the calculation status, not in the node description

## What is covered elsewhere in this guide

The size of one position is a separate question from the combination of several, and it is covered in its own part: the risk unit a run reports in, the growth-optimal fraction and the ceiling it is treated as, a drawdown cap, and the control that separates an aligned size from a size that moves.

The route from a first idea to a result carrying its own conditions of validity is written once and holds across domains, including the sweep that produces the matrix these readings consume.

[the size of one bet](https://stochastly.com/docs/guide/risk-sizing): Position size as a research variable

[the route, step by step](https://stochastly.com/docs/find-alpha): Finding alpha, and pricing the search you did

[a target and a floor, in order](https://stochastly.com/docs/guide/prop-firms): What a prop-firm evaluation actually measures

## What is being claimed, and what is left out

### The portfolio readings weight the configurations of one run, and they move no verdict.

Scope: The columns are the configurations of a single strategy that traded, truncated to the window they share and sampled above a declared cap, on the instruments that run loaded, in the risk unit the run reports in.
Effect: Declared simplifications travel with each figure: a ridge added to the covariance before any inversion, means and covariances estimated on the same window that judges the weights, and turnover absent from the objectives.
Control: Each allocator publishes the same reading columns, so two of them are compared on one run; the decorrelated and archive baskets each carry a mean-picked basket at the same size as a control.

The production package embeds the strategy engine; missing engine source stops the build. The explicit non-deliverable demo can use a labelled generic cross-sectional fallback. Portfolio claims require an engine-backed run.

No figure described above is a statement about future performance, and the harness carries no signal to trade and no recommended allocation. A result concerns the series that was submitted.

---
Source: https://stochastly.com/docs/guide/portfolios
