FinanceModels API Reference
FinanceModels.Bond
FinanceModels.Equity
FinanceModels.Option
FinanceModels.Spline
FinanceModels.CashflowProjection
FinanceModels.CommonEquity
FinanceModels.Forward
FinanceModels.NullModel
FinanceModels.Projection
FinanceModels.ProjectionKind
FinanceModels.InterestRateSwap
FinanceModels.__default_optic
FinanceModels.__rewrap
FinanceModels.cashflows_timepoints
FinanceModels.eurocall
FinanceModels.europut
FinanceModels.fit
Exported API
FinanceModels.CashflowProjection
— TypeCashflowProjection()
A concrete subtype of ProjectionKind
which is the projection which returns only a reducible collection of Cashflow
s. Use in conjunction with a Projection
.
FinanceModels.CommonEquity
— TypeFinanceModels.Forward
— TypeForward(time,instrument)
The instrument is relative to the Forward time. e.g. if you have a Forward(1.0, Cashflow(1.0, 3.0))
then the instrument is a cashflow that pays 1.0 at time 4.0
FinanceModels.NullModel
— TypeNullModel()
A singleton type representing a placeholder model for when you don't really need a model. For example: determining nominal cashflows for fixed income contract.
FinanceModels.Projection
— TypeProjection(contract,model,kind)
The set of contract
s and assumptions (model
) to project the kind
of output desired. Some assets require a projection in order to be valued (e.g. a floating rate bond).
If attempting to collect
or otherwise reduce a contract (<:AbstractContract
), by default it will get wrapped into a Projection(contract,NullModel(),CashflowProjection())
FinanceCore.present_value
— Functionpresent_value(model,contract,current_time=0.0)
present_value(model,projection,current_time=0.0)
Return the value of the contract as corresponding with the valuation assumptions embedded in the model
for the given contract or projection with CashflowProjection
kind.
Examples
m = Equity.BlackScholesMerton(0.01, 0.02, 0.15)
a = Option.EuroCall(CommonEquity(), 1.0, 1.0)
pv(m, a) # ≈ 0.05410094201902403
FinanceModels.InterestRateSwap
— MethodInterestRateSwap(curve, tenor; model_key="OIS")
A convenience method for creating an interest rate swap given a curve and a tenor via a Composite
contract consisting of receiving a fixed bond and paying (i.e. the negative of) a floating bond.
The notional is a unit (1.0) amount and assumed to settle four times per period.
A Projection
, with an indexable model_key
is still needed to project a swap. See examples below for what this looks like.
Examples
julia> curve = Yield.Constant(0.05);
julia> swap = InterestRateSwap(curve,10);
julia> Projection(swap,Dict("OIS" => curve),CashflowProjection()) |> collect
80-element Vector{Cashflow{Float64, Float64}}:
Cashflow{Float64, Float64}(0.012272234429039353, 0.25)
Cashflow{Float64, Float64}(0.012272234429039353, 0.5)
⋮
Cashflow{Float64, Float64}(-0.012272234429039353, 9.75)
Cashflow{Float64, Float64}(-1.0122722344290391, 10.0)
FinanceModels.fit
— Methodfit(
model,
quotes,
method=Fit.Loss(x -> x^2);
variables=__default_optic(model),
optimizer=__default_optim(model)
)
Fit a model to a collection of quotes using a loss function and optimization method.
Arguments
model
: The initial model to fit, which is generally an instantiated but un-optimized model.quotes
: A collection of quotes to fit the model to.method::F=Fit.Loss(x -> x^2)
: The loss function to use for fitting the model. Defaults to the squared loss function.method
can also beBootstrap()
. If this is the case,model
should be a spline such asSpline.Linear()
,Spline.Cubic()
...
variables=__default_optic(model)
: The variables to optimize over. This is an optic specifying which parameters of the modle can vary. See extended help for more.optimizer=__default_optim(model)
: The optimization algorithm to use. The default optimization for a given model is ECA from Metahueristics.jl; see extended help for more on customizing the solver including setting the seed.
The optimization routine will then attempt to modify parameters of model
to best fit the quoted prices of the contracts underlying the quotes
by calling present_value(model,contract)
. The optimization will minimize the loss function specified within Fit.Loss(...)
.
Different types of quotes are appropriate for different kinds of models. For example, if you try to value a set of equtiy EuroCall
s with a Yield.Constant
, you will get an error because the present_value(m<:Yield.Constant,o<:EuroCall)
is not defined.
Returns
- The fitted model.
Examples
julia> model = Yield.Constant();
julia> quotes = ZCBPrice([0.9, 0.8, 0.7,0.6]);
julia> fit(model,quotes)
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Yield Curve (FinanceModels.Yield.Constant)⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
┌────────────────────────────────────────────────────────────┐
0.120649 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ Zero rates
│⠀⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⣧⢰⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⣿⣾⠀⣀⣸⠀⢸⢳⣇⢀⣀⣀⣀⣀⣀⠀⡀⣀⣀⣀⡀⡀⣀⢀⣀⡀⡀⣀⢀⡀⣀⡀⢀⣀⡀⢀⡀⢀⣀⡀⢀⡀⠀⣀⡀⢀⡀⢀⣀⡀⢀⣀⠀⣀⡀⢀⣀⠀⢀│
│⢠⢻⡟⡆⣿⡟⣦⠚⠀⢸⣾⠛⠛⠘⠛⠘⢲⡗⠛⠃⠛⠓⠓⠛⠚⠛⠑⠓⠛⠃⠓⠛⠑⠚⡟⠓⢻⡗⠚⠀⠓⠚⠑⠒⠃⠓⠚⠑⠚⠀⠓⠃⠘⠒⠃⠓⠃⠘⠒⠃│
│⢸⢸⡇⢹⡏⠁⠉⠀⠀⠈⠉⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠈⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
Continuous │⢸⢸⡇⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⢸⠀⠁⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⢸⠀⠀⠘⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⡎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
0.120649 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
└────────────────────────────────────────────────────────────┘
⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀time⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀30⠀
Extended help
Customizing the Solver
The default solver is ECA()
from Metahueristics.jl. This is a stochastic global optimizer which will run with a random seed by default.
- To make the seed static, you can specify the kwarg to
fit
with a customized ECA: e.g.fit(...;optimizer=ECA(seed=123))
- A number of options are available for
ECA()
or you may specify a different solver. - More documentation is available from the upstream packages:
Defining the variables
An arbitrarily complex model may be the object we intend to fit - how does fit
know what free variables are able to be solved for within the given model? variables
is a singlular or vector optic argument. What does this mean?
- An optic (or "lens") is a way to define an accessor to a given object. Example:
julia> using Accessors, AccessibleOptimization, IntervalSets
julia> obj = (a = "AA", b = "BB");
julia> lens = @optic _.a
(@optic _.a)
julia> lens(obj)
"AA"
An optic argument is a singular or vector of lenses with an optional range of acceptable parameters. For example, we might have a model as follows where we want fit
to optize parameters a
and b
:
struct MyModel <:FinanceModels.AbstractModel
a
b
end
__default_optic(m::MyModel) = OptArgs([
@optic(_.a) => 0.0 .. 100.0,
@optic(_.b) => -10.0 .. 10.0,
]...)
In this way, fit know which arbitrary parameters in a given object may be modified. Technically, we are not modifying the immutable MyModel
, but instead efficiently creating a new instance. This is enabled by AccessibleOptimization.jl.
Note that not all opitmization algorithms want a bounded interval. In that case, simply leave off the paired range. The prior example would then become:
__default_optic(m::MyModel) = OptArgs([
@optic(_.a),
@optic(_.b),
]...)
```
Additional Examples
See the tutorials in the package documentation for FinanceModels.jl or the docstrings of FinanceModels.jl's avaiable model types.
Unexported API
FinanceModels.ProjectionKind
— Typeabstract type ProjectionKind
An abstract type that controls what gets produced from the model.
Subtypes of ProjectionKind
define the level of detail in the output of the model. For example, if you just want cashflows or you want a full amortization schedule, you might define an AmortizationSchedule
kind which shows principle, interest, etc.
After defining a new ProjectionKind
, you need to define the how the projection works for that new output by extending either:
function Transducers.asfoldable(p::Projection{C,M,K}) where {C<:Cashflow,M,K<:CashflowProjection}
...
end
or
function Transducers.__foldl__(rf, val, p::Projection{C,M,K}) where {C<:Cashflow,M,K<:CashflowProjection}
...
end
There are examples of this in the documentation.
Examples
```julia julia> struct CashflowProjection <: ProjectionKind end CashflowProjection
julia> struct AmortizationSchedule <: ProjectionKind end AmortizationSchedule
FinanceModels.__default_optic
— Method__default_optic(model)
Returns the variables to optimize over for the given model. This is an optic/lens specifying which parameters of the modle can vary. See extended help for more. An optic argument is a singular or vector of lenses with an optional range of acceptable parameters.
Examples
We might have a model as follows where we want fit
to optize parameters a
and b
:
struct MyModel <:FinanceModels.AbstractModel
a
b
end
__default_optic(m::MyModel) = OptArgs([
@optic(_.a) => 0.0 .. 100.0,
@optic(_.b) => -10.0 .. 10.0,
]...)
Extended help
An arbitrarily complex model may be the object we intend to fit - how does fit
know what free variables are able to be solved for within the given model? variables
is a singlular or vector optic argument. What does this mean?
- An optic (or "lens") is a way to define an accessor to a given object. Example:
julia> using Accessors, AccessibleOptimization, IntervalSets
julia> obj = (a = "AA", b = "BB");
julia> lens = @optic _.a
(@optic _.a)
julia> lens(obj)
"AA"
An optic argument is a singular or vector of lenses with an optional range of acceptable parameters. For example, we might have a model as follows where we want fit
to optize parameters a
and b
:
struct MyModel <:FinanceModels.AbstractModel
a
b
end
__default_optic(m::MyModel) = OptArgs([
@optic(_.a) => 0.0 .. 100.0,
@optic(_.b) => -10.0 .. 10.0,
]...)
In this way, fit know which arbitrary parameters in a given object may be modified. Technically, we are not modifying the immutable MyModel
, but instead efficiently creating a new instance. This is enabled by AccessibleOptimization.jl.
Note that not all opitmization algorithms want a bounded interval. In that case, simply leave off the paired range. The prior example would then become:
__default_optic(m::MyModel) = OptArgs([
@optic(_.a),
@optic(_.b),
]...)
```
FinanceModels.__rewrap
— Method__rewrap(from::Transducers.Reduction, to)
__rewrap(from, to)
Used to unwrap a Reduction which is a composition of contracts and a transducer and apply the transducers to the associated projection instead of the transducer.
For example, on its own a contract is not project-able, but wrapped in a (default) Projection
it can be. But it may also be a lot more convienent to construct contracts which have scaling or negated modifications and let that flow into a projection.
Examples
julia> Bond.Fixed(0.05,Periodic(1),3) |> collect
3-element Vector{Cashflow{Float64, Float64}}:
Cashflow{Float64, Float64}(0.05, 1.0)
Cashflow{Float64, Float64}(0.05, 2.0)
Cashflow{Float64, Float64}(1.05, 3.0)
julia> Bond.Fixed(0.05,Periodic(1),3) |> Map(-) |> collect
3-element Vector{Cashflow{Float64, Float64}}:
Cashflow{Float64, Float64}(-0.05, 1.0)
Cashflow{Float64, Float64}(-0.05, 2.0)
Cashflow{Float64, Float64}(-1.05, 3.0)
julia> Bond.Fixed(0.05,Periodic(1),3) |> Map(-) |> Map(x->x*2) |> collect
3-element Vector{Cashflow{Float64, Float64}}:
Cashflow{Float64, Float64}(-0.1, 1.0)
Cashflow{Float64, Float64}(-0.1, 2.0)
Cashflow{Float64, Float64}(-2.1, 3.0)
FinanceModels.cashflows_timepoints
— Methodcashflows_timepoints(contracts)
cashflows_timepoints(quotes)
Create a matrix of cashflows and a vector of timepoints for a collection of quotes or contracts. Timepoints need not be spaced evenly.
This is used when constructing SmithWilson yield curves.
Arguments
contracts
orquotes
: A collection of<:AbstractContract
s orQuotes
.
Returns
- A tuple
(m, times)
wherem
is a matrix of cashflows andtimes
is a vector of timepoints.
Examples
julia> FinanceModels.cashflows_timepoints(ParYield.([0.04,0.02,0.04],[1,4,4]))
([0.02 0.01 0.02; 1.02 0.01 0.02; … ; 0.0 0.01 0.02; 0.0 1.01 1.02], [0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0])
FinanceModels.eurocall
— Methodeurocall(;S=1.,K=1.,τ=1,r,σ,q=0.)
Calculate the Black-Scholes implied option price for a european call, where:
S
is the current asset priceK
is the strike or exercise priceτ
is the time remaining to maturity (can be typed with \tau[tab])r
is the continuously compounded risk free rateσ
is the (implied) volatility (can be typed with \sigma[tab])q
is the continuously paid dividend rate
Rates should be input as rates (not percentages), e.g.: 0.05
instead of 5
for a rate of five percent.
!!! Experimental: this function is well-tested, but the derivatives functionality (API) may change in a future version of ActuaryUtilities.
Extended Help
This is the same as the formulation presented in the dividend extension of the BS model in Wikipedia.
Other general comments:
- Swap/OIS curves are generally better sources for
r
than government debt (e.g. US Treasury) due to the collateralized nature of swap instruments. - (Implied) volatility is characterized by a curve that is a function of the strike price (among other things), so take care when using
- Yields.jl can assist with converting rates to continuously compounded if you need to perform conversions.
FinanceModels.europut
— Methodeuroput(;S=1.,K=1.,τ=1,r,σ,q=0.)
Calculate the Black-Scholes implied option price for a european call, where:
S
is the current asset priceK
is the strike or exercise priceτ
is the time remaining to maturity (can be typed with \tau[tab])r
is the continuously compounded risk free rateσ
is the (implied) volatility (can be typed with \sigma[tab])q
is the continuously paid dividend rate
Rates should be input as rates (not percentages), e.g.: 0.05
instead of 5
for a rate of five percent.
!!! Experimental: this function is well-tested, but the derivatives functionality (API) may change in a future version of ActuaryUtilities.
Extended Help
This is the same as the formulation presented in the dividend extension of the BS model in Wikipedia.
Other general comments:
- Swap/OIS curves are generally better sources for
r
than government debt (e.g. US Treasury) due to the collateralized nature of swap instruments. - (Implied) volatility is characterized by a curve that is a function of the strike price (among other things), so take care when using
- Yields.jl can assist with converting rates to continuously compounded if you need to perform conversions.
Please open an issue if you encounter any issues or confusion with the package.