Log-wealth regret against a comparator: private API
PortfolioOptimisers.regret_series — Function
regret_series(pred::PredictionResult)
regret_series(pred::MultiPeriodPredictionResult)The realised return series and the timestamps a prediction result was scored on, as log_wealth_regret reads them.
The series is the one performance_summary reads: the portfolio returns that predict stored, net of the fee the fold settled, and drifted where a Weight Drift ran. A population of paths gives its first path. A multi-period result gives its stacked returns and timestamps.
Arguments
pred: The prediction result.
Returns
ret::VecNum: The realised return series.ts::Option{<:AbstractVector}: The timestamps of the rows, ornothingwhen the fold carried none.
Related
PortfolioOptimisers.first_member — Function
first_member(w::VecNum)
first_member(w::VecVecNum)The one weight vector of a fold, or the first member's under a population.
A population result carries one vector per member, and the path readers of the regret take the first, as regret_series and performance_summary take the first path. A single vector is its own first member.
Arguments
w: Weights of a fold, one vector or one per member.
Returns
w::VecNum: The vector read.
Related
PortfolioOptimisers.fold_target — Function
fold_target(pred::PredictionResult)The weights a fold started from, and, through fold_held, the weights it held after its last observation, on the fold's own asset names.
On a fold with no Held Weights record, fold_target is the fold's target. On a fold with one, it is the record's w0, the start that held_start_weights names: the fold's own target when it solved, and the weights it was handed when it failed. fold_held is the target on a fold with no record, because a fold without a drift holds its target to the end. On a fold with a record it is the record's w, the drifted holding that the next fold trades from.
Both read the first member of a population. Both are viewed at the fold's Investable Mask, so they sit on pred.rd.nx, the names of the fold's own universe, which stacked_fold_weights embeds by.
Arguments
pred: One fold's prediction result.
Returns
w::VecNum: The weights, one entry per name inpred.rd.nx.
Related
PortfolioOptimisers.fold_held — Function
fold_held(pred::PredictionResult)The weights a fold held after its last observation, on the fold's own asset names. fold_target documents the pair.
Related
PortfolioOptimisers.stacked_fold_weights — Function
stacked_fold_weights(pred::MultiPeriodPredictionResult, read) -> MatNumOne weight vector per fold, read by read and embedded by asset name on the union of the folds' universes.
The folds of a multi-period result need not share a universe. A Pipeline with an Asset Selector fits each fold on the assets it selected, so the fold of a top-1 selector carries one name and one weight. A path over the folds is stated on one axis, so each fold's weights go into the columns of its own names on the union axis, and every other entry of its row is zero.
Algorithm
- Read each fold's weights through
read, givingws. - Take the union of the folds'
rd.nxin order of first appearance, givingnames, and map each name to its column, givingpos. - Promote the element types of
ws, givingTf, and allocateW, afolds × assetsmatrix of zeros of typeTf. - For each fold
i, check the length ofws[i]against itsrd.nx, and write each weight into rowiofW, at the column thatposgives its name.
Arguments
pred: The multi-period prediction result.read: The per-fold reader,fold_targetorfold_held.
Validation
- Every fold's weights have one entry per name of its
rd.nx. ADimensionMismatchis thrown otherwise, because the embedding would misplace them.
Returns
W::MatNum:folds × assetsweights on the union universe, one row per fold in split order.
Related
PortfolioOptimisers.comparator_path_length — Function
comparator_path_length(b::PredictionResult, ::Type{Tf})
comparator_path_length(b::MultiPeriodPredictionResult, ::Type{Tf})The path length of a comparator's targets, as log_wealth_regret reports it.
A multi-period result has one target per fold, so the path is over the folds. At test_size = 1 a fold is a row, and $\boldsymbol{u}_t$ is the comparator's target on row $t$. A single prediction result holds one target and no path, and so does a multi-period result of one fold. Both answer NaN, in the number type Tf of the regret.
Mathematical definition
\[\begin{align} P_T &= \sum_{t=2}^{T} \lVert \boldsymbol{u}_t - \boldsymbol{u}_{t-1} \rVert_2\,. \end{align}\]
Where:
- $P_T = \sum_{t=2}^{T} \lVert \boldsymbol{u}_t - \boldsymbol{u}_{t-1} \rVert_2$: Path length of a comparator sequence $\boldsymbol{u}_1, \ldots, \boldsymbol{u}_T$ in the feasible set.
- $\boldsymbol{u}_t$: Comparator's target on fold $t$, embedded by asset name on the union of the folds' universes, with a zero at every asset outside the fold's own universe.
- $T$: Number of folds.
Algorithm
- Read one target per fold through
fold_target, and embed the targets on one axis throughstacked_fold_weights, givingW, one row per fold. - When
Whas fewer than two rows, returnNaNof typeTf. - Sum the Euclidean norms of the differences of consecutive rows of
W.
Arguments
b: The comparator's prediction result.Tf: Number type of the answer when the comparator has no path.
Returns
P::Number: The path length, orNaN.
Related
PortfolioOptimisers.path_norm_epigraph! — Function
path_norm_epigraph!(model::JuMP.Model, t, x, p::Number)Writes the epigraph $t \geq \lVert \boldsymbol{x} \rVert_p$ of one step of a comparator path into a bare model.
The cone is the norm's own at p = 2, p = 1 and p = Inf. Every other order takes the power-cone form, one row per entry. It is the epigraph that norm_ball_dual_norm_epigraph! writes, without the model registry, which a bare programme does not use.
JuMP formulation
Variables
t: read. It is the caller's epigraph variable.r: created at an order other than1,2andInf, an anonymous vector of one variable per entry of $\boldsymbol{x}$.
Constraints
Every row is registered under no name.
- At $p = 2$, the second-order cone row $t \geq \lVert \boldsymbol{x} \rVert_2$.
- At $p = 1$, the norm-one cone row $t \geq \lVert \boldsymbol{x} \rVert_1$.
- At $p = \infty$, the norm-infinity cone row $t \geq \lVert \boldsymbol{x} \rVert_\infty$.
- At any other $p$, one power cone row per entry, $r_j^{1/p}\, t^{1 - 1/p} \geq \lvert x_j \rvert$ with $r_j \geq 0$ and $t \geq 0$, and the row $\sum_j r_j - t = 0$.
Where:
- $t$: Epigraph variable of the step.
- $\boldsymbol{x}$: Affine expression whose norm is bounded, with entries $x_j$.
- $p$: Norm order.
- $r_j$: Auxiliary variable of entry $j$.
The power-cone rows are exact. Each row gives $r_j \geq \lvert x_j \rvert^p / t^{p-1}$, and the sum of the rows gives $t^p \geq \sum_j \lvert x_j \rvert^p$, which is $t \geq \lVert \boldsymbol{x} \rVert_p$.
Arguments
model::JuMP.Model: The JuMP optimisation model.t: The epigraph variable.x: The affine expression whose norm is bounded, one entry per asset.p: The norm order,1 <= p.
Returns
nothing.
Related
PortfolioOptimisers.row_bound_view — Function
row_bound_view(b::Number, m::AbstractVector{Bool})
row_bound_view(b::VecNum, m::AbstractVector{Bool})One side of a resolved weight bound on the investable assets of a row.
A scalar bound applies to every asset, so it passes through. A vector bound is viewed at the row's mask.
Arguments
b: One side of the resolved bound, a number or one entry per asset.m: The row's Investable Mask.
Returns
b: The scalar bound, or the view of the vector bound atm.
Related
PortfolioOptimisers.path_row_constraints! — Function
path_row_constraints!(model::JuMP.Model, u, z, x, m::AbstractVector{Bool}, wb::WeightBounds)Writes one row of the budgeted path programme on the row's investable assets.
The budget, the finite bounds and the log wealth of the row read the assets that m keeps. The allocation of every other asset is fixed at zero, because a row with no price relative for an asset cannot hold it.
JuMP formulation
Variables
u: read. It is the row's allocations, one per asset. Every entry outsidemis fixed at zero withJuMP.fix, which sets the variable's bounds and adds no row.z: read. It is the row's log-wealth variable.
Constraints
Every row is registered under no name, and each reads the assets in $m$ alone.
- $\sum_{i \in m} u_i = 1$.
- $u_i - l_i \geq 0$ for each $i \in m$, when an entry of $\boldsymbol{l}$ is finite.
- $u_i - h_i \leq 0$ for each $i \in m$, when an entry of $\boldsymbol{h}$ is finite.
- The exponential cone row $\left(z, 1, \sum_{i \in m} x_i u_i\right) \in \mathcal{K}_{\exp}$, which holds when $z \leq \log \sum_{i \in m} x_i u_i$.
Where:
- $u_i$: Allocation of asset $i$ on the row.
- $z$: Log-wealth variable of the row.
- $x_i$: Price relative of asset $i$ on the row, one plus its return.
- $m$: Set of the assets in the row's Investable Mask.
- $l_i$, $h_i$: Resolved lower and upper weight bounds of asset $i$, the entries of $\boldsymbol{l}$ and $\boldsymbol{h}$.
- $\mathcal{K}_{\exp} = \mathrm{cl}\,\{(a, b, c) : b\, e^{a / b} \leq c,\, b > 0\}$: Exponential cone.
Arguments
model::JuMP.Model: The JuMP optimisation model.u: The row's allocation variables, one per asset.z: The row's log-wealth variable.x: The row's price relatives, finite wheremholds.m: The row's Investable Mask, the Coverage Universe of the one-row window.wb: Weight bounds.
Returns
nothing.
Related
PortfolioOptimisers.path_budget_constraint! — Function
path_budget_constraint!(model::JuMP.Model, u, L::Number, p::Number)Writes the path-length budget of the budgeted path programme.
Each step of the path takes one epigraph variable through path_norm_epigraph!, and the sum of these variables is at most L. A path of one row has no step, so the function writes nothing.
JuMP formulation
Variables
u: read. It is theT × Nallocation variables, one row per period.s: created, an anonymous vector of $T - 1$ step lengths.d: created, an anonymous $(T - 1) \times N$ matrix of steps.
Constraints
Every row is registered under no name.
- $\boldsymbol{d}_{t-1} = \boldsymbol{u}_t - \boldsymbol{u}_{t-1}$, for $t = 2, \ldots, T$, one row per entry.
- The rows of
path_norm_epigraph!on $s_{t-1} \geq \lVert \boldsymbol{d}_{t-1} \rVert_p$, for $t = 2, \ldots, T$. - $\sum_{t=1}^{T-1} s_t \leq L$.
Where:
- $\boldsymbol{u}_t$: Allocation of period $t$, one entry per asset.
- $\boldsymbol{d}_t$: Step from period $t$ to period $t + 1$.
- $s_t$: Length of step $t$ in the norm of order $p$.
- $L$: Path-length budget.
- $p$: Norm order.
- $T$: Number of observations.
- $N$: Number of assets.
Arguments
model::JuMP.Model: The JuMP optimisation model.u: TheT × Nallocation variables, one row per period.L: The path-length budget.p: The norm order.
Returns
nothing.
Related
PortfolioOptimisers.row_coverage_mask — Function
row_coverage_mask(rd::ReturnsResult, t::Integer) -> Option{BitVector}The Coverage Universe of row t of rd alone, through coverage_mask on the one-row view.
Arguments
rd: The returns result to use.t: The row.
Validation
- The row has at least one asset in its Coverage Universe. An
IsEmptyErrorthat names the row is thrown otherwise, throughrow_universe_error. Any other error ofcoverage_maskpasses through as it is.
Returns
msk::Option{BitVector}: The row's mask, one entry per asset, ornothingwhen the row covers every asset.
Related
PortfolioOptimisers.row_universe_error — Function
row_universe_error(err::IsEmptyError, t::Integer) -> IsEmptyError
row_universe_error(err::Exception, t::Integer) -> ExceptionThe error that row_coverage_mask throws for row t.
The IsEmptyError of an empty Coverage Universe is restated to name the row. Any other error is returned as it is.
Related
PortfolioOptimisers.path_row_masks — Function
path_row_masks(rd::ReturnsResult) -> Option{BitMatrix}The Investable Mask of every row of a budgeted path.
Row t is the Coverage Universe of the one-row window t: true at every asset whose return is finite and whose Asset Panel active mask is true on that row. A delisted or unlisted asset is therefore out of the row, as it is out of the fit of a HindsightSplit(; prefix = false) fold.
Algorithm
- Start from
msk, arows × assetsmatrix oftrue. - For each row
t, derive the row's Coverage Universe throughrow_coverage_mask, givingcm, and write it into rowtofmskwhen it is notnothing. - Return
nothingwhen every entry ofmskistrue, andmskotherwise.
Arguments
rd: The returns result to use.
Validation
- Every row has at least one asset in its Coverage Universe. An
IsEmptyErrornaming the row is thrown otherwise, because the row's budget of one cannot be met.
Returns
msk::Option{BitMatrix}: The masks,rows × assets, ornothing.
Related
PortfolioOptimisers.assert_path_rows — Function
assert_path_rows(res::BudgetedHindsightPathResult, rd::ReturnsResult)Refuse a returns result that is not the panel a budgeted path was solved over: the names, the clock and the row count must be the fit's, because the path is bound to its rows. An ArgumentError is thrown otherwise.
Related
PortfolioOptimisers.path_row_fold — Function
path_row_fold(res::BudgetedHindsightPathResult, rd::ReturnsResult, t::Integer) -> PredictionResultOne fold of a budgeted path's prediction result: row t's allocation as a NaiveOptimisationResult on the resolved bounds, predicted over row t of rd alone.
A row with a gap carries its Investable Mask, so predict views the row and the weights at the mask and never reads the gap. A row with no gap carries nothing, as a fit on the full universe does.
Related