Fees Constraints: private API

PortfolioOptimisers.add_to_fees!Function
add_to_fees!(
    model::Model,
    expr::Union{Number, AbstractJuMPScalar}
)

Accumulate a JuMP expression into the :fees expression of the optimisation model.

Creates the :fees expression if it does not yet exist; otherwise adds expr to it in place.

Arguments

  • model::JuMP.Model: The JuMP optimisation model.
  • expr: The fee expression to accumulate. A plain number is accepted beside a JuMP scalar, because a charge that does not depend on the decision variables — the forced liquidation of set_liquidation_fees! — is a constant under any objective whose k is not a variable.

Returns

  • nothing.

Related

source
PortfolioOptimisers.add_to_one_time_fees!Function
add_to_one_time_fees!(
    model::Model,
    expr::Union{Number, AbstractJuMPScalar}
)

Accumulate a one-off fee expression into the model's :one_time_fees expression.

The twin of add_to_fees!, for the terms that are charged one time for the whole holding period rather than on every observation. Only the two fixed fees reach it, because l, s and tn are rates per period. set_net_portfolio_returns! subtracts this expression from the first observation alone, and add_fees_to_ret! divides it by the observation count, because an expected return is a per period number.

Arguments

  • model::JuMP.Model: The JuMP optimisation model.
  • expr: The fee expression to accumulate.

Returns

  • nothing.

Related

source
PortfolioOptimisers.charge_one_time_feesFunction
charge_one_time_fees(model::JuMP.Model, net, one_time, T::Number,
                     fa::Option{<:AbstractFeeAmortisation})

Lay the model's one-off fee expression onto a net return series, on the clock the fee states.

The model's twin of charge_fees, and it states the same rule. The two fixed fees are charged one time for the whole holding period, so a nothing or FirstObservationFees clock subtracts them from the first observation alone, and an AmortisedFees spreads them evenly over T, the observation count of the fit.

Algorithm

  1. On a nothing or FirstObservationFees fa, subtract one_time from the first entry of net and leave the rest.
  2. On an AmortisedFees fa, build the share one_time / T once and subtract it from every entry of net.

Arguments

  • model::JuMP.Model: The JuMP optimisation model.
  • net: The net return expression, already charged the per period terms.
  • one_time: The model's :one_time_fees expression.
  • T: Observation count of the fit, from get_T.
  • fa: The fee's clock, from :fee_fa.

Returns

  • The net return expression, charged the one-off terms.

Related

source
PortfolioOptimisers.set_turnover_fees!Function
set_turnover_fees!(args...)

Add a turnover-based transaction fee expression to the JuMP optimisation model.

The fall-through method does nothing. The concrete method computes val' * |w - wt| via NormOneCone constraints and accumulates the result into the model's :fees expression via add_to_fees!.

Mathematical definition

\[\begin{align} t_{ftn,i} &\geq |w_i - w_{t,i}\, k|\,, \\ f_{tn} &= \boldsymbol{v}^\intercal \boldsymbol{t}_{ftn}\,. \end{align}\]

Where:

  • $w_i$: Portfolio weight for asset $i$.
  • $w_{t,i}$: Benchmark weight for asset $i$.
  • $k$: Budget scaling / homogenisation variable.
  • $\boldsymbol{v}$: Per-asset fee rate vector.
  • $\boldsymbol{t}_{ftn}$: Auxiliary absolute-deviation variable vector.
  • $f_{tn}$: Total turnover fee.

Arguments

  • model::JuMP.Model: The JuMP optimisation model.
  • tn::Turnover: Turnover specification containing benchmark weights w and per-unit fee val.

Returns

  • nothing.

Related

source
PortfolioOptimisers.set_non_fixed_fees!Function
set_non_fixed_fees!(args...)

Add all non-fixed (proportional and turnover) fee expressions to the JuMP optimisation model.

The fall-through method does nothing. The concrete method delegates to set_long_non_fixed_fees!, set_short_non_fixed_fees!, and set_turnover_fees!.

Arguments

  • model::JuMP.Model: The JuMP optimisation model.
  • fees::Fees: Fee specification containing long, short, and turnover fee rates.

Returns

  • nothing.

Related

source
PortfolioOptimisers.set_long_non_fixed_fees!Function
set_long_non_fixed_fees!(args...)

Add proportional long-side fee expression to the JuMP optimisation model.

The fall-through method does nothing. The concrete method adds fl' * lw to the model's :fees expression via add_to_fees!.

Mathematical definition

\[\begin{align} f_l &= \boldsymbol{f}_l^\intercal \boldsymbol{lw}\,. \end{align}\]

Where:

  • $f_l$: Total long-side fee.
  • $\boldsymbol{f}_l$: Per-asset long-side fee rate vector.
  • $\boldsymbol{lw}$: Long-weight vector.

Arguments

  • model::JuMP.Model: The JuMP optimisation model.
  • fl: Long-side fee rate(s). Accepts a scalar Number or a VecNum.

Returns

  • nothing.

Related

source
PortfolioOptimisers.set_short_non_fixed_fees!Function
set_short_non_fixed_fees!(args...)

Add proportional short-side fee expression to the JuMP optimisation model.

The fall-through method does nothing. The concrete method adds fs' * sw to the model's :fees expression via add_to_fees!. Does nothing when no short-weight variable :sw exists in the model.

Mathematical definition

\[\begin{align} f_s &= \boldsymbol{f}_s^\intercal \boldsymbol{sw}\,. \end{align}\]

Where:

  • $f_s$: Total short-side fee.
  • $\boldsymbol{f}_s$: Per-asset short-side fee rate vector.
  • $\boldsymbol{sw}$: Short-weight vector.

Arguments

  • model::JuMP.Model: The JuMP optimisation model.
  • fs: Short-side fee rate(s). Accepts a scalar Number or a VecNum.

Returns

  • nothing.

Related

source
PortfolioOptimisers.set_fixed_fees!Function
set_fixed_fees!(
    model::Model,
    sp::AbstractMIPSpace,
    ind::AbstractMIPIndicators,
    ffl::Union{Nothing, Number, AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}},
    ffs::Union{Nothing, Number, AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}},
    ffl_flag::Bool,
    ffs_flag::Bool
)

Add fixed-fee expressions to the JuMP optimisation model.

A fixed fee is charged per position held, whatever its size, so unlike the proportional fees above it cannot be written against the weights — it needs a binary saying whether the position is there at all. That is the only reason this one takes an indicator bundle, and the only reason a MIP builder has to run before it.

Mathematical definition

\[\begin{align} f_{fl} &= \boldsymbol{f}_{fl}^\intercal \boldsymbol{b}^l\,, & f_{fs} &= \boldsymbol{f}_{fs}^\intercal \boldsymbol{b}^s\,. \end{align}\]

Where:

  • $\boldsymbol{b}^l$, $\boldsymbol{b}^s$: Long and short binaries (long_bin, short_bin). These are the binaries themselves, never the gates: a fee is incurred by the decision to hold, which is what the bit records, and the gates relax to continuous variables when the budget is free.
  • $\boldsymbol{f}_{fl}$, $\boldsymbol{f}_{fs}$: Long and short fixed-fee rates.

Under a long-only builder the held bit is the long bit (HeldIndicators), and there is no short side to charge.

Arguments

  • model::JuMP.Model: The JuMP optimisation model.
  • sp::AbstractMIPSpace: Weight space the fees are charged in.
  • ind::AbstractMIPIndicators: Indicator bundle supplying the binaries.
  • ffl::Option{<:Num_VecNum}: Long-side fixed fee rate(s).
  • ffs::Option{<:Num_VecNum}: Short-side fixed fee rate(s).
  • ffl_flag::Bool: Whether to add the long fixed-fee expression.
  • ffs_flag::Bool: Whether to add the short fixed-fee expression.

Returns

  • nothing.

Related

source
PortfolioOptimisers.set_liquidation_fees!Function
set_liquidation_fees!(::JuMP.Model, ::Nothing)
set_liquidation_fees!(model::JuMP.Model, lq::Turnover)

Add the proportional cost of a forced exit to the model's :fees expression.

lq prices the positions that leave the Investable Mask, and those assets are not in the model's w: the optimisation reduced them away at its entry. The charge is therefore a constant, not a function of the decision variables, and it needs no auxiliary variable and no norm constraint — which is what separates it from set_turnover_fees!, whose |w - wt * k| does depend on w.

The constant is multiplied by the homogenising variable k, exactly as the turnover term is, so a ratio objective sees the charge in the same units as every other fee and the exit moves the argmin rather than riding outside the programme.

lq is a rate per period, so the charge joins :fees beside l, s and tn through add_to_fees!, and no clock reaches it.

Algorithm

  1. On a nothing lq, do nothing. No asset left the universe.
  2. Otherwise read k, the homogenising variable.
  3. Compute the constant through calc_liquidation_fees, which reads the carrier alone: a forced exit trades to zero, so the charge is the rate times abs.(lq.w).
  4. Register constant * k and add it to :fees through add_to_fees!.

Arguments

  • model: JuMP model.
  • lq: The proportional liquidation carrier, or nothing.

Returns

  • nothing: The model is modified in place.

Related

source
PortfolioOptimisers.set_fixed_liquidation_fees!Function
set_fixed_liquidation_fees!(::JuMP.Model, ::Nothing, ::NamedTuple)
set_fixed_liquidation_fees!(model::JuMP.Model, flq::Turnover, kwargs::NamedTuple)

Add the fixed cost of a forced exit to the model's :one_time_fees expression.

The fixed twin of set_liquidation_fees!, and a constant for the same reason: the liquidated assets are not in w. Unlike set_fixed_fees! it therefore needs no binary indicator, because whether each position is held is already known from flq.w rather than decided by the programme.

flq is a currency amount charged one time for the whole holding period, so it joins :one_time_fees beside fl and fs through add_to_one_time_fees!, and charge_one_time_fees then lands it on the clock fees.fa names.

Algorithm

  1. On a nothing flq, do nothing.
  2. Otherwise read k, the homogenising variable.
  3. Compute the constant through calc_fixed_liquidation_fees, which charges both the liquidated long and the liquidated short side.
  4. Register constant * k and add it to :one_time_fees through add_to_one_time_fees!.

Arguments

  • model: JuMP model.
  • flq: The fixed liquidation carrier, or nothing.
  • kwargs: Forwarded to isapprox to decide how near zero counts as zero.

Returns

  • nothing: The model is modified in place.

Related

source