The online portfolio selection head: private API
PortfolioOptimisers.online_selection_seed — Function
online_selection_seed(
opt::OnlinePortfolioSelection,
rd::ReturnsResult,
set::AbstractAllocationSet
) -> OnlinePortfolioSelectionState{Int64, __T_w, __T_st, __T_X, __T_nx, __T_pnl, Nothing, Nothing, Nothing} where {__T_w, __T_st, __T_X, __T_nx, __T_pnl}
Seeds the head's state on its first row, before the first update.
The uniform start and a given w0 meet the set in the same way. So the allocation held during the first period lies in the set wherever the set can be formed without rows. A set that reads the head's rows, such as a programme set with a fitted risk ceiling or a tracking error, has no constraints before the first row. The seed then holds the start as given, and the first Online Update projects it. That update holds every step until the head has two rows. A programme that fails at the start holds the start as given and warns, as the Held Step of a row does.
Algorithm
- Form
start, which is1/Nat each of theNpinned assets whenw0isnothing, andw0otherwise. - Project
startonce ontosetin the rule's geometry throughproject_start, givingw0. A set that reads rows returnsstartunchanged. - Seed the rule's carrier on
w0andsetthroughrule_state_seed, givingst. Steps 2 and 3 run inside onewith_projection_stepunder the head'sstrict, which collects the holds inheld. - Warn on a hold through
report_held_steps. - Size the rows buffer
Xfromrows_needed. A count ofnothinggives an uncapped buffer, a count of zero gives no buffer, and any other count caps the buffer at that count. - Keep the carrier's panel as
pnlwhen it is static, andnothingotherwise. - Return the state with no row folded, the allocation
w0, the carrierst, the bufferX, the names andpnl.
Arguments
opt: The head.rd: The carrier of the first block.set: The Allocation Set, resolved over the pinned universe.
Validation
length(opt.w0) == size(rd.X, 2), whenw0is given. ADimensionMismatchis thrown otherwise.
Returns
state::OnlinePortfolioSelectionState: The state before the first update.
Related
PortfolioOptimisers.fold_online_selection — Function
fold_online_selection(
opt::OnlinePortfolioSelection,
cache::Union{Nothing, OnlinePortfolioSelectionState},
rd::ReturnsResult
) -> OnlinePortfolioSelectionState{__T_n, __T_w, _A, __T_X, __T_nx, __T_pnl, __T_amsk, __T_ts, __T_hold} where {__T_n<:Integer, __T_w<:(AbstractVector), _A, __T_X<:Union{Nothing, SampleBufferState}, __T_nx<:Union{Nothing, AbstractVector{<:AbstractString}}, __T_pnl<:Union{Nothing, AssetPanel}, __T_amsk<:Union{Nothing, AbstractVector{<:Bool}}, __T_ts<:Union{Nothing, AbstractVector}, __T_hold<:Union{Nothing, HeldStep}}
fold_online_selection(
opt::OnlinePortfolioSelection,
cache::Union{Nothing, OnlinePortfolioSelectionState},
rd::ReturnsResult,
set::AbstractAllocationSet
) -> OnlinePortfolioSelectionState{__T_n, __T_w, _A, __T_X, __T_nx, __T_pnl, __T_amsk, __T_ts, __T_hold} where {__T_n<:Integer, __T_w<:(AbstractVector), _A, __T_X<:Union{Nothing, SampleBufferState}, __T_nx<:Union{Nothing, AbstractVector{<:AbstractString}}, __T_pnl<:Union{Nothing, AssetPanel}, __T_amsk<:Union{Nothing, AbstractVector{<:Bool}}, __T_ts<:Union{Nothing, AbstractVector}, __T_hold<:Union{Nothing, HeldStep}}
Folds every row of a carrier into the head's state, in order.
This is the Block Step, and a fold of the whole carrier from no state is the Causal Pass.
Algorithm
- Read the active mask of the carrier through
step_active_mask, givingamsk. - Resolve the Allocation Set over the pinned universe through
resolve_allocation_set, givingset. - Seed the state on the first block, or pin and check the carried state, through
online_selection_pin, givingstate. - Fold each row in order through
online_selection_row!, under the timestamp thatrow_timestampgives it. Each row updates the carrierst, the allocationw, the bufferXand the hold recordhold, and adds one to the row countn. - Return the state with the new
n,w,st,Xandhold, the active mask of the last row, and the timestamps folded so far.
Arguments
opt: The head.cache: The state, ornothingbefore the first row.rd: The carrier of the block,observations × assets.set: The block's Allocation Set, before resolution over the pinned universe. It defaults to the head's own, and the fold loop's online arm passes the fold's entry of a schedule (seeonline_step_fold).
Validation
rd.Xis notnothing. AnIsNothingErroris thrown otherwise.- Everything
step_active_maskandassert_pinned_contextrefuse. - A non-finite cell at an active asset, under
strict. AnArgumentErroris thrown.
Returns
state::OnlinePortfolioSelectionState: The state after the last row.
Related
PortfolioOptimisers.online_selection_pin — Function
online_selection_pin(
opt::OnlinePortfolioSelection,
_::Nothing,
rd::ReturnsResult,
set::AbstractAllocationSet
) -> OnlinePortfolioSelectionState{Int64, __T_w, __T_st, __T_X, __T_nx, __T_pnl, Nothing, Nothing, Nothing} where {__T_w, __T_st, __T_X, __T_nx, __T_pnl}
Returns the state that a block folds into.
On the first block the method seeds the state through online_selection_seed. On every later block it returns the state that the head carries, after the pin-and-check that every host runs. The check compares the names and the static panel with those of the first step, and the width with that of the state. The timestamps must be present at every block or at none.
Validation
length(cache.w) == size(rd.X, 2). ADimensionMismatchis thrown otherwise.- Everything
assert_pinned_contextandassert_column_presencerefuse.
Related
PortfolioOptimisers.online_selection_row! — Function
online_selection_row!(
opt::OnlinePortfolioSelection,
st,
w::AbstractVector,
X::Union{Nothing, SampleBufferState},
row::NamedTuple,
nx::Union{Nothing, AbstractVector{<:AbstractString}},
set::AbstractAllocationSet
) -> Tuple{Any, Any, Any, Union{Nothing, HeldStep}}
Takes one row of the recursion, inside a ProjectionStep that gives every projection of the row the rows it reads and a log for its holds.
The row reads a gap in two ways, and each reader gets the reading that the rest of the library gives it. The Online Update and every kernel over the price relatives read one at a gap, as if the leg held cash, which is the reading of a Held Gap. So the recursion stays over the full pinned universe and never carries a forced zero. Every statistic over the rows reads the carrier as a batch verb reads one, with NaN where there was no return and the active mask beside it. Such a statistic is the mean of a forecaster, the prior of a Risk Loss or of a programme set, or the re-solve of a leader. It reduces to its own Coverage Universe. So a window over an unlisted span never meets a constant column, and returns that never happened never dilute the statistic of a relisted asset.
A row with a held projection warns once, with the row's timestamp and each hold, and returns the first HeldStep record. A row whose projections all solved returns nothing.
Algorithm
- Name the Held Gaps of the returns
rat the row's indexithroughreport_row_gaps. - Push
rverbatim, with its active maskamsk, into the rows bufferX, when the tree keeps one. - Form the price relative
xthroughprice_relative, which is one at a gap. - Read the buffer out as the carrier
rowsthroughrows_carrier. - Take the Online Update through
online_update!, inside a projection step overrowsand the timestamptsthatwith_projection_stepopens. This gives the carrierst, the allocationwand the log of holdsheld. - Warn on a hold through
report_held_steps, which gives the row's hold record.
Arguments
opt: The head.st: The rule's carrier.w: The allocation held during the row's period.X: The rows buffer, ornothing.row: The row, as a named tuple of four fields.rholds its returns verbatim,amskholds its active mask ornothing,tsholds its timestamp or its index in the fold, andiholds its index in the fold.nx: The asset names, for the Held Gap message.set: The Allocation Set, resolved.
Returns
(st', w', X', hold)::Tuple: The carrier, the allocation for the next period, the buffer after the row, and the row's hold record ornothing.
Related
PortfolioOptimisers.row_timestamp — Function
row_timestamp(ts::Nothing, t::Integer, n::Integer)
row_timestamp(ts::AbstractVector, t::Integer, n::Integer)Returns the timestamp under which a row of a block folds.
It is the carrier's timestamp. When the carrier holds none, it is the row's index in the whole fold, n + 1 after n rows.
Related
PortfolioOptimisers.report_held_steps — Function
report_held_steps(
held::AbstractVector{<:HeldStep},
ts
) -> Any
Warns once for a row with a held projection, and names the row's timestamp and every hold.
It returns the first HeldStep record, or nothing when every projection of the row solved.
Related
PortfolioOptimisers.report_row_gaps — Function
report_row_gaps(
r::AbstractVector,
w::AbstractVector,
amsk::Union{Nothing, AbstractVector{<:Bool}},
nx::Union{Nothing, AbstractVector{<:AbstractString}},
strict::Bool,
obs::Integer
)
Names the Held Gaps of one row of returns, and writes nothing.
The function passes over a non-finite cell that the row's active mask marks inactive, because an inactive asset has no return by definition. It also passes over a non-finite cell at which the recursion's weight is zero. Every other non-finite cell is a Held Gap, and strict_diagnostic reports them all in one held_gap_msg. The report is a warning by default and a refusal under strict. The function does not fill the row. The buffer keeps the cell as it is, and the Online Update reads it as one through price_relative.
Arguments
r: The row.w: The allocation held during the row's period.amsk: The row's active mask, ornothing.nx: The asset names, for the message, ornothing.strict: Whether a Held Gap is an error.obs: The row's index in the fold, which the message names as the observation of each Held Gap.
Validation
- Under
strict, the row holds no Held Gap. AnArgumentErroris thrown otherwise.
Returns
nothing.
Related
PortfolioOptimisers.rows_carrier — Function
rows_carrier(X::Nothing, nx)
rows_carrier(X::SampleBufferState, nx::VecStr)
rows_carrier(X::SampleBufferState, nx::Nothing)Reads the rows buffer out as the carrier that the Online Update gets.
The carrier is a ReturnsResult of the buffer's rows verbatim, under the pinned names. When the buffer records active masks, buffer_panel makes them a time-varying Asset Panel on the carrier. The method returns nothing when the tree keeps no rows.
Every statistic over the rows reads this carrier, and it is the carrier that the batch verbs read. So prior(pe, rd), mean(me, rd.X, rd.pnl) and optimise(opt, rd) reduce to the Coverage Universe of the window exactly as they do on a carrier that the ingestion layer built. The method takes no copy, because the carrier views the valid region of the buffer. A buffer with no pinned names is refused by name. A Returns Result that carries rows carries their names by its own contract, so the head never meets that pair.
Validation
nxis notnothingwhen the head keeps rows. AnIsNothingErroris thrown otherwise.
Related
PortfolioOptimisers.buffer_panel — Function
buffer_panel(X::SampleBufferState)Returns the active masks of a rows buffer as the AssetPanel of a carrier, or nothing when the buffer records none, which is the static panel.
The panel uses the active mask as its estimation mask too, because step_active_mask admits only that panel.
Related
PortfolioOptimisers.online_selection_readout — Function
online_selection_readout(
opt::OnlinePortfolioSelection,
state::OnlinePortfolioSelectionState
) -> NaiveOptimisationResult{Nothing, __T_wb, __T_fees, __T_retcode, __T_w, __T_imsk, Nothing} where {__T_wb, __T_fees, __T_retcode, __T_w, __T_imsk}
Returns the Recursion Read-out, the allocation of the state as a NaiveOptimisationResult over the assets active at the last folded row.
The read-out reads the state and writes nothing, so every call on one state returns the same Result. Its retcode is an OptimisationSuccess. Its res is the HeldStep record of the last folded row when that row was held, and nothing otherwise. A reduced allocation with no mass is the one failure from which a rule cannot recover. It happens when every held asset is inactive at the last row. The read-out then returns an OptimisationFailure with NaN weights, so that a fallback chain continues.
Mathematical definition
\[\begin{align} \bar{w}_i &= \frac{w_{T+1,i}}{\sum_{j \in \mathcal{I}} w_{T+1,j}}\,, \quad i \in \mathcal{I}\,. \end{align}\]
Where:
- $\bar{w}_i$: Weight of asset $i$ in the Result.
- $w_{T+1,i}$: Weight of asset $i$ in the allocation of the state, the Next-Period Allocation after $T$ rows.
- $\mathcal{I}$: Investable Mask of the read-out, the assets active at the last folded row, or every asset under a static panel.
- $T$: Number of observations.
The Result expands $\bar{\boldsymbol{w}}$ back over the pinned universe with a zero at every asset outside $\mathcal{I}$. The weights are defined when the denominator is positive and every $w_{T+1,i}$ is finite.
Algorithm
- Read the active mask
imskof the last folded row, and formidx, the indices of the active assets, or every index whenimskisnothing. - View the head's set at
idx, givingset, and slice the allocation tow. - Resolve the head's fee against the full set, and view it at the Investable Mask through
investable_fees_view, givingfees. - Sum
wtos. When no asset is active,sis not positive, or an entry ofwis not finite, return anOptimisationFailurewithNaNweights and no bounds. - Resolve the weight bounds of
setover the active assets, givingwb. - Return
w ./ swithwb,feesand anOptimisationSuccesswhoseresis the hold record of the state.
Arguments
opt: The head.state: The state to read out.
Returns
res::NaiveOptimisationResult: The Next-Period Allocation,pr = nothing.
Related
PortfolioOptimisers.online_readout — Method
online_readout(opt::OnlinePortfolioSelection)Refuses by name, because the head has no batch estimator to return.
A Recursion Read-out rebuilds no carrier and runs no batch path. optimise(opt) reads the state directly.
Related
PortfolioOptimisers.held_timestamps — Method
held_timestamps(opt::OnlinePortfolioSelection)Returns every timestamp that the head's state holds, or nothing before the first step.
Related
PortfolioOptimisers.fees_carry_turnover — Function
fees_carry_turnover(fees::Nothing)
fees_carry_turnover(fees::FeesE_Fees)
fees_carry_turnover(v::AbstractVector)
fees_carry_turnover(td::TimeDependent)
fees_carry_turnover(::Any)Returns whether a fee, or any fee that a per-fold schedule visibly holds, carries a turnover term.
A static fee answers for its own tn. A TimeDependent schedule answers for every entry of a vector value, including the entries of a nested vector, and for its explicit default. The output of a callable does not exist before its fold, so a callable answers false. Every other value answers false too, as it does for needs_previous_weights.
Related
PortfolioOptimisers.assert_online_fee_source — Method
assert_online_fee_source(opt::OnlinePortfolioSelection, pws)Refuse, at the entry of the fold loop's online arm, an OnlinePortfolioSelection head whose fees carry a turnover term while the walk-forward threads no Previous-Weights Source.
The recursion reads its own allocation, so the fund's held book is the one base against which a turnover fee on this family can measure a trade. Without a Previous-Weights Source, the fee prices the distance between two consecutive targets. That distance counts buy-and-hold as trading and constant rebalancing as free. The head and the walk-forward first meet at this check, so the check runs as soon as the pair exists. A head with no tn fee passes, and so does every other estimator. fees_carry_turnover reads a per-fold schedule on fees. It checks every entry that the schedule visibly holds, and it does not check the output of a callable, which does not exist before its fold.
Arguments
opt: The estimator handed to the loop.pws: The scheme's Previous-Weights Source, ornothing.
Validation
pwsis notnothingwhenopt.feescarries atnterm, in any entry that a schedule visibly holds. AnArgumentErroris thrown otherwise.
Related
PortfolioOptimisers.online_portfolio_selection_td_defaults — Function
online_portfolio_selection_td_defaults(
) -> @NamedTuple{set::BoundedAllocationSet{WeightBounds{Float64, Float64}, Nothing}}
Return the static defaults of the OnlinePortfolioSelection fields that may hold a TimeDependent.
The constructor's test-substitution pass and time_dependent_field_defaults share it, so the fold-less value of each field is declared once. fees and fb default to nothing and are left out. set has a default, so a fold-less solve runs the default Allocation Set and not an absent set.
Related
PortfolioOptimisers.static_allocation_set — Function
static_allocation_set(opt::OnlinePortfolioSelection) -> Any
Returns the head's Allocation Set outside every fold loop, which is its own set or the fold-less value of a schedule on set.
A schedule is defined over the folds of a cross-validation scheme. So a partial_fit! that a caller takes by hand steps inside the default of the schedule, or inside BoundedAllocationSet when the schedule has no default. The Causal Pass steps inside the same set, because its reset of the schedules has already run.
Related
PortfolioOptimisers.online_step_fold — Method
online_step_fold(opt::OnlinePortfolioSelection, ctx::TimeDependentContext, rd::ReturnsResult)Folds the fold's rows into the head inside the fold's own Allocation Set.
The head is the one family whose online step is the optimisation. The Constrained Update projects the raw step of every row onto set, so the step reads a schedule on set, and not only the read-out. So the method resolves the entry here, in the same fold and before the read-out resolves the other schedules. The head that the loop threads on keeps the schedule, so fold i + 1 resolves from the schedule and not from entry i. The step writes no field but the state, so the method returns the head with its cache rebound.
Arguments
opt: The head the loop threads, with its schedules unresolved.ctx: The fold's context.rd: The carrier of the rows the fold has gained.
Returns
opt: The head, with itscacherebound and its schedules unresolved.
Related