Base finite allocation

PortfolioOptimisers.FiniteAllocationInputType
struct FiniteAllocationInput{__T_w, __T_prices, __T_cash, __T_prev_cash, __T_horizon, __T_fees, __T_imsk} <: AbstractEstimator

Problem data fed to a finite allocation optimiser.

FiniteAllocationInput bundles the inputs shared by every finite allocation optimiser — the target continuous weights, current asset prices, cash budget, the cash held before the trade, and an optional time horizon, fee and Investable Mask — into a single value passed as the second argument to optimise. It is consumed by both DiscreteAllocation and GreedyAllocation.

It subtypes AbstractEstimator rather than the FiniteAllocationOptimisationResult tree: it is the input to an allocation, not a computed output, and is deliberately kept clear of the OptimisationResult dispatch surface (plotting, result factory) that its fields cannot honour.

imsk is what lets a reduced optimisation be allocated. An optimisation reduces to its Investable Mask and expands the solved weights back to the caller's universe, so a result pairs a full-length w with a fee on two reduced axes. The mask records that reduction, and allocation_side_fees lifts the fee back onto the axis w and prices already live on with lift_fees, so the forced exit of a delisted asset is charged on the money it traded. The fee carries the mask it was reduced on in its own imsk, and the lift reads that, so the constructor reconciles the two through mark_fees: a stated imsk marks an unmarked fee, a marked fee supplies a missing imsk, and a pair that disagrees is refused.

Fields

  • w: Target (continuous) portfolio weights to be discretised.
  • prices: Current asset prices, in the same order as w.
  • cash: Cash budget available for the allocation.
  • prev_cash: Cash held in the portfolio before the trade. A turnover fee is charged on the money traded, and the money held per asset before the trade is prev_cash * fees.tn.w. Defaults to cash, which is the caller that states no separate figure.
  • horizon: Optional time horizon, in periods. l, s and tn are rates per period, so each of them charges on every one of the horizon periods. Required when fees is provided.
  • fees: Optional fees to charge against the allocation over horizon. A fee an optimisation reduced to its Investable Mask spans two axes and carries that mask in its own imsk, which is what puts it back on the axis w lives on.
  • imsk: Optional Investable Mask the optimisation w came from reduced on, true at every asset it traded. nothing says the weights and the fees are on the full universe already, which is what an unreduced optimisation answers. The constructor reconciles it with the fee's own mark through mark_fees.

Constructors

FiniteAllocationInput(;    w::VecNum,    prices::VecNum,    cash::Number = 1e6,    prev_cash::Number = cash,    horizon::Option{<:Number} = nothing,    fees::Option{<:Fees} = nothing,    imsk::Option{<:BitVector} = nothing) -> FiniteAllocationInput

Keywords correspond to the struct's fields.

FiniteAllocationInput(    res::NonFiniteAllocationOptimisationResult;    prices::VecNum,    cash::Number = 1e6,    prev_cash::Number = cash,    w::Option{<:VecNum} = nothing,    horizon::Option{<:Number} = nothing,    fees::Option{<:Fees} = nothing,    imsk::Option{<:BitVector} = nothing) -> FiniteAllocationInput

Reads from a fitted optimisation everything an allocation can take from it, so a caller states the prices and the cash alone. A stated keyword always wins, and every derivation falls back to nothing on a result that carries no answer, so a family holding fewer objects than another is allocated by the same call:

  • w from res.w, which every optimisation result carries on the full universe.
  • fees through extract_fees, from the fees property when the result exposes one.
  • imsk through result_investable_mask, which answers nothing when the optimisation reduced on nothing.
  • horizon through allocation_horizon, the observation count of the result's prior. An equal weighted optimisation built without a prior derives none, and the rule below then asks the caller for one, and only when the input also carries a fee.

Validation

  • !isempty(w), !isempty(prices).
  • length(w) == length(prices).
  • cash > 0.
  • prev_cash >= 0.
  • horizon must not be nothing when fees is provided.
  • fees and imsk are reconciled through mark_fees, which refuses a marked fee beside a different imsk.
  • imsk, when stated or read off the fee: length(imsk) == length(w) and any(imsk).

Examples

julia> FiniteAllocationInput(; w = [0.6, 0.4], prices = [10.0, 20.0], cash = 1000.0)FiniteAllocationInput          w ┼ Vector{Float64}: [0.6, 0.4]     prices ┼ Vector{Float64}: [10.0, 20.0]       cash ┼ Float64: 1000.0  prev_cash ┼ Float64: 1000.0    horizon ┼ nothing       fees ┼ nothing       imsk ┴ nothing

Related

source
PortfolioOptimisers.factoryMethod
factory(res::FiniteAllocationOptimisationResult, fb::Option{<:FOptE_FOpt_FbChain})

Rebuild a finite allocation result with an updated fallback record fb.

Like the continuous-result generic, every finite allocation result carries fb as its last field, so the rebuild copies all fields unchanged except the trailing fb. Concrete result types may override this method when rebuilding requires more than swapping fb. optimise is the one caller, and it hands in the FbChain it walked.

Related

source