Skip to content

API Reference

Pricing

QuantNova.Instruments.black_scholes Function
julia
black_scholes(S, K, T, r, σ, optiontype)

Black-Scholes option pricing formula.

Arguments

  • S - Current price of underlying

  • K - Strike price

  • T - Time to expiration (years)

  • r - Risk-free rate

  • σ - Volatility

  • optiontype - :call or :put

source
QuantNova.Instruments.price Function
julia
price(instrument, market_state)

Compute the current price of an instrument given market state.

source

Greeks

QuantNova.Instruments.compute_greeks Function
julia
compute_greeks(option, market_state; backend=current_backend())

Compute option Greeks. Uses analytical formulas when available (preferred), falls back to AD for exotic options without closed-form solutions.

Arguments

  • option - The option to compute Greeks for

  • market_state - Current market conditions

  • backend - AD backend to use for fallback computation (default: current_backend())

source
QuantNova.Instruments.GreeksResult Type
julia
GreeksResult

Container for option Greeks including first-order, second-order, and cross-derivatives.

First-order Greeks

  • delta - dV/dS (sensitivity to underlying price)

  • vega - dV/dσ (sensitivity to volatility, scaled per 1% move)

  • theta - -dV/dT (time decay per year)

  • rho - dV/dr (sensitivity to rates, scaled per 1% move)

Second-order Greeks

  • gamma - d²V/dS² (rate of change of delta)

  • vanna - d²V/dSdσ (sensitivity of delta to volatility)

  • volga - d²V/dσ² (sensitivity of vega to volatility, a.k.a. vomma)

  • charm - d²V/dSdT (sensitivity of delta to time, a.k.a. delta decay)

source

Instruments

QuantNova.Instruments.Stock Type
julia
Stock <: AbstractEquity

A simple equity instrument.

Fields

  • symbol::String - Ticker symbol
source
QuantNova.Instruments.EuropeanOption Type
julia
EuropeanOption <: AbstractOption

A European-style option (exercise only at expiry).

Fields

  • underlying::String - Symbol of underlying asset

  • strike::Float64 - Strike price

  • expiry::Float64 - Time to expiration (in years)

  • optiontype::Symbol - :call or :put

source
QuantNova.PortfolioModule.Portfolio Type
julia
Portfolio{I<:AbstractInstrument} <: AbstractPortfolio

A collection of financial instruments with associated position weights.

Fields

  • instruments::Vector{I} - The instruments in the portfolio

  • weights::Vector{Float64} - Position sizes (can be shares, contracts, or notional amounts)

Constructors

  • Portfolio(instruments, weights) - Create from vectors (type inferred)

  • Portfolio{I}(instruments, weights) - Create with explicit instrument type

Example

julia
# Create a portfolio of options
call = EuropeanOption("AAPL", 150.0, 1.0, :call)
put = EuropeanOption("AAPL", 140.0, 1.0, :put)
portfolio = Portfolio([call, put], [100.0, -50.0])  # Long 100 calls, short 50 puts

# Price the portfolio
state = MarketState(
    prices=Dict("AAPL" => 150.0),
    rates=Dict("USD" => 0.05),
    volatilities=Dict("AAPL" => 0.2),
    timestamp=0.0
)
total_value = value(portfolio, state)

See also: value, portfolio_greeks

source

Missing docstring.

Missing docstring for value. Check Documenter's build log for details.

QuantNova.PortfolioModule.portfolio_greeks Function
julia
portfolio_greeks(portfolio, market_state)

Compute aggregated Greeks for the portfolio. Only includes instruments that have Greeks (options).

source
QuantNova.Core.MarketState Type
julia
MarketState{P,R,V,T}

Immutable snapshot of market conditions.

Fields

  • prices::P - Current prices by symbol

  • rates::R - Interest rates by currency

  • volatilities::V - Implied volatilities by symbol

  • timestamp::T - Time of snapshot

source

AD System

QuantNova.AD.gradient Function
julia
gradient(f, x; backend=current_backend())

Compute the gradient of f at x using the specified backend. Validates input for NaN/Inf values before computing.

source
QuantNova.AD.hessian Function
julia
hessian(f, x; backend=current_backend())

Compute the Hessian of f at x using the specified backend.

source
QuantNova.AD.jacobian Function
julia
jacobian(f, x; backend=current_backend())

Compute the Jacobian of f at x using the specified backend.

source
QuantNova.AD.value_and_gradient Function
julia
value_and_gradient(f, x; backend=current_backend())

Compute the value and gradient of f at x in a single pass. Returns (f(x), ∇f(x)).

source
QuantNova.AD.current_backend Function
julia
current_backend()

Return the currently active AD backend.

source
QuantNova.AD.set_backend! Function
julia
set_backend!(backend::ADBackend)

Set the global AD backend.

source
QuantNova.AD.with_backend Function
julia
with_backend(f, backend::ADBackend)

Execute f with backend as the active backend, then restore the original.

Example

julia
with_backend(EnzymeBackend()) do
    gradient(loss, params)
end
source

Backends

QuantNova.AD.ForwardDiffBackend Type
julia
ForwardDiffBackend <: ADBackend

CPU-based forward-mode AD using ForwardDiff.jl. Best for low-dimensional problems and nested derivatives (Greeks).

source
QuantNova.AD.PureJuliaBackend Type
julia
PureJuliaBackend <: ADBackend

Reference implementation using finite differences. Slow but always works. Useful for debugging and testing.

source
QuantNova.AD.EnzymeBackend Type
julia
EnzymeBackend <: ADBackend

CPU/GPU AD using Enzyme.jl (LLVM-based differentiation). Supports both forward and reverse mode.

source
QuantNova.AD.ReactantBackend Type
julia
ReactantBackend <: ADBackend

GPU-accelerated AD using Reactant.jl + Enzyme. Best for high-dimensional problems (portfolio optimization).

source

Monte Carlo

QuantNova.MonteCarlo.GBMDynamics Type
julia
GBMDynamics(r, σ)

Geometric Brownian Motion: dS = r_S_dt + σ_S_dW

source
QuantNova.MonteCarlo.HestonDynamics Type
julia
HestonDynamics(r, v0, κ, θ, ξ, ρ)

Heston stochastic volatility model.

source
QuantNova.MonteCarlo.mc_price Function
julia
mc_price(S0, T, payoff, dynamics; npaths=10000, nsteps=252, antithetic=true, rng=nothing)

Price a derivative using Monte Carlo simulation.

Arguments

  • S0 - Initial spot price

  • T - Time to maturity

  • payoff - Payoff structure

  • dynamics - Price dynamics (GBM or Heston)

  • npaths - Number of simulation paths

  • nsteps - Time steps per path

  • antithetic - Use antithetic variates for variance reduction

  • rng - Random number generator (optional)

Returns

MCResult with price, standard error, and confidence interval.

source
QuantNova.MonteCarlo.mc_price_qmc Function
julia
mc_price_qmc(S0, T, payoff, dynamics; npaths=10000, nsteps=252)

Price a derivative using Quasi-Monte Carlo (Sobol sequences).

This is deterministic and differentiable with Enzyme. Better convergence than pseudo-random MC: O(1/N) vs O(1/√N).

source
QuantNova.MonteCarlo.mc_delta Function
julia
mc_delta(S0, T, payoff, dynamics; npaths=10000, nsteps=252, backend=current_backend())

Compute delta using pathwise differentiation with AD.

Automatically uses QMC (Sobol sequences) when backend is EnzymeBackend, since Enzyme cannot differentiate through pseudo-random number generators.

source
QuantNova.MonteCarlo.mc_greeks Function
julia
mc_greeks(S0, T, payoff, dynamics; npaths=10000, nsteps=252, backend=current_backend())

Compute delta and vega using pathwise differentiation.

Automatically uses QMC (Sobol sequences) when backend is EnzymeBackend, since Enzyme cannot differentiate through pseudo-random number generators.

source
QuantNova.MonteCarlo.lsm_price Function

Arguments

  • S0 - Initial spot price

  • T - Time to maturity

  • option - AmericanPut or AmericanCall

  • dynamics - GBMDynamics

  • npaths - Number of simulation paths

  • nsteps - Number of exercise dates

  • rng - Random number generator

Returns

MCResult with American option price and standard error.

Reference

Longstaff & Schwartz (2001), "Valuing American Options by Simulation"

source

Payoffs

QuantNova.MonteCarlo.EuropeanCall Type
julia
EuropeanCall(K)

European call option payoff: max(S_T - K, 0).

Arguments

  • K::Float64 - Strike price

Example

julia
payoff_fn = EuropeanCall(100.0)
result = mc_price(payoff_fn, dynamics, 1.0, 10000)
source
QuantNova.MonteCarlo.EuropeanPut Type
julia
EuropeanPut(K)

European put option payoff: max(K - S_T, 0).

Arguments

  • K::Float64 - Strike price

Example

julia
payoff_fn = EuropeanPut(100.0)
result = mc_price(payoff_fn, dynamics, 1.0, 10000)
source
QuantNova.MonteCarlo.AsianCall Type
julia
AsianCall(K)

Asian call option with arithmetic average: max(avg(S) - K, 0).

The payoff is based on the arithmetic average of the price path, not just the terminal value.

Arguments

  • K::Float64 - Strike price

Example

julia
payoff_fn = AsianCall(100.0)
result = mc_price(payoff_fn, dynamics, 1.0, 10000; nsteps=252)
source
QuantNova.MonteCarlo.AsianPut Type
julia
AsianPut(K)

Asian put option with arithmetic average: max(K - avg(S), 0).

The payoff is based on the arithmetic average of the price path, not just the terminal value.

Arguments

  • K::Float64 - Strike price

Example

julia
payoff_fn = AsianPut(100.0)
result = mc_price(payoff_fn, dynamics, 1.0, 10000; nsteps=252)
source
QuantNova.MonteCarlo.UpAndOutCall Type
julia
UpAndOutCall(K, barrier)

Up-and-out barrier call option.

The option becomes worthless (knocks out) if the underlying price ever touches or exceeds the barrier during the option's life. Otherwise, pays max(S_T - K, 0) at expiry.

Arguments

  • K::Float64 - Strike price

  • barrier::Float64 - Upper barrier level (must be > K for typical usage)

Example

julia
payoff_fn = UpAndOutCall(100.0, 120.0)  # Knocks out if S >= 120
result = mc_price(payoff_fn, dynamics, 1.0, 10000; nsteps=252)
source
QuantNova.MonteCarlo.DownAndOutPut Type
julia
DownAndOutPut(K, barrier)

Down-and-out barrier put option.

The option becomes worthless (knocks out) if the underlying price ever touches or falls below the barrier during the option's life. Otherwise, pays max(K - S_T, 0) at expiry.

Arguments

  • K::Float64 - Strike price

  • barrier::Float64 - Lower barrier level (must be < K for typical usage)

Example

julia
payoff_fn = DownAndOutPut(100.0, 80.0)  # Knocks out if S <= 80
result = mc_price(payoff_fn, dynamics, 1.0, 10000; nsteps=252)
source
QuantNova.MonteCarlo.AmericanPut Type
julia
AmericanPut

American put option for LSM pricing.

source
QuantNova.MonteCarlo.AmericanCall Type
julia
AmericanCall

American call option for LSM pricing.

source

Risk Measures

QuantNova.Risk.VaR Type
julia
VaR <: AbstractRiskMeasure

Value at Risk at specified confidence level.

source
QuantNova.Risk.CVaR Type
julia
CVaR <: AbstractRiskMeasure

Conditional Value at Risk (Expected Shortfall) at specified confidence level.

source
QuantNova.Risk.Volatility Type
julia
Volatility <: AbstractRiskMeasure

Standard deviation of returns.

source
QuantNova.Risk.Sharpe Type
julia
Sharpe <: AbstractRiskMeasure

Sharpe ratio (excess return / volatility).

Fields

  • rf::Float64 - Annualized risk-free rate (e.g., 0.05 for 5%)

  • periods_per_year::Int - Number of return periods per year (252 for daily, 52 for weekly, 12 for monthly)

source
QuantNova.Risk.MaxDrawdown Type
julia
MaxDrawdown <: AbstractRiskMeasure

Maximum peak-to-trough decline.

source
QuantNova.Risk.compute Function
julia
compute(measure::AbstractRiskMeasure, returns)

Compute the risk measure for given returns.

source

Optimization

QuantNova.Optimization.MeanVariance Type
julia
MeanVariance

Mean-variance optimization objective (Markowitz).

source
QuantNova.Optimization.SharpeMaximizer Type
julia
SharpeMaximizer

Maximize Sharpe ratio (non-convex).

source
QuantNova.Optimization.optimize Function
julia
optimize(objective; kwargs...)

Optimize portfolio weights for given objective.

source
QuantNova.Optimization.OptimizationResult Type
julia
OptimizationResult

Result of a portfolio optimization.

Fields

  • weights::Vector{Float64} - Optimal portfolio weights (typically sum to 1)

  • objective::Float64 - Final objective function value (e.g., variance for MVO)

  • converged::Bool - Whether the optimization converged successfully

  • iterations::Int - Number of iterations used

Example

julia
returns = [0.10, 0.08, 0.12]
cov_matrix = [0.04 0.01 0.02;
              0.01 0.03 0.01;
              0.02 0.01 0.05]

result = optimize(MeanVariance(returns, cov_matrix); target_return=0.10)
if result.converged
    println("Optimal weights: ", result.weights)
end

See also: optimize, MeanVariance

source

Planned Features

CVaRObjective and KellyCriterion types are defined but optimize() methods are not yet implemented.

Stochastic Volatility Models

QuantNova.Models.SABRParams Type
julia
SABRParams{T1,T2,T3,T4}

SABR stochastic volatility model parameters.

Fields

  • alpha::T1 - Initial volatility level (α > 0)

  • beta::T2 - CEV exponent (0 ≤ β ≤ 1, often fixed at 0.5 for rates, 1.0 for equities)

  • rho::T3 - Correlation between spot and vol (-1 < ρ < 1)

  • nu::T4 - Vol of vol (ν > 0)

source
QuantNova.Models.sabr_implied_vol Function
julia
sabr_implied_vol(F, K, T, params::SABRParams)

Compute SABR implied volatility using Hagan's approximation formula.

Arguments

  • F - Forward price

  • K - Strike price

  • T - Time to expiry (in years)

  • params - SABR model parameters

Returns

Implied Black volatility for the given strike.

source
QuantNova.Models.sabr_price Function
julia
sabr_price(F, K, T, r, params::SABRParams, optiontype::Symbol)

Price a European option using SABR implied vol + Black-76.

Arguments

  • F - Forward price

  • K - Strike price

  • T - Time to expiry (in years)

  • r - Risk-free rate

  • params - SABR model parameters

  • optiontype - :call or :put

Returns

Option price

source
QuantNova.Models.HestonParams Type
julia
HestonParams{T1,T2,T3,T4,T5}

Heston stochastic volatility model parameters.

Fields

  • v0::T1 - Initial variance (v0 > 0)

  • theta::T2 - Long-term variance / mean reversion level (θ > 0)

  • kappa::T3 - Mean reversion speed (κ > 0)

  • sigma::T4 - Volatility of variance (σ > 0)

  • rho::T5 - Correlation between spot and variance (-1 < ρ < 1)

The Feller condition 2κθ > σ² ensures the variance stays positive.

source
QuantNova.Models.heston_price Function
julia
heston_price(S, K, T, r, q, params::HestonParams, optiontype::Symbol; N=128)

Price a European option under the Heston model using numerical integration.

Arguments

  • S - Spot price

  • K - Strike price

  • T - Time to expiry (in years)

  • r - Risk-free rate

  • q - Continuous dividend yield (default 0.0)

  • params - Heston model parameters

  • optiontype - :call or :put

  • N - Number of integration points (default 128)

Returns

Option price

Notes

Uses the Gil-Pelaez / Carr-Madan approach with trapezoidal integration.

Example

julia
params = HestonParams(0.04, 0.04, 1.5, 0.3, -0.7)
# Without dividends
price = heston_price(100.0, 100.0, 1.0, 0.05, params, :call)
# With 2% dividend yield
price = heston_price(100.0, 100.0, 1.0, 0.05, 0.02, params, :call)
source

Calibration

QuantNova.Calibration.OptionQuote Type
julia
OptionQuote

A single option quote from the market.

Fields

  • strike::Float64 - Strike price

  • expiry::Float64 - Time to expiry (in years)

  • price::Float64 - Market price (can be 0 if only using implied_vol)

  • optiontype::Symbol - :call or :put

  • implied_vol::Float64 - Market implied volatility

source
QuantNova.Calibration.SmileData Type
julia
SmileData

Market data for a single expiry (a volatility smile).

Fields

  • expiry::Float64 - Time to expiry (in years)

  • forward::Float64 - Forward price

  • rate::Float64 - Risk-free interest rate

  • quotes::Vector{OptionQuote} - Option quotes at this expiry

source
QuantNova.Calibration.VolSurface Type
julia
VolSurface

Market data for multiple expiries (full volatility surface).

Fields

  • spot::Float64 - Current spot price

  • rate::Float64 - Risk-free interest rate

  • smiles::Vector{SmileData} - Smile data for each expiry

source
QuantNova.Calibration.calibrate_sabr Function
julia
calibrate_sabr(smile::SmileData; beta=0.5, max_iter=1000, tol=1e-8, lr=0.01, backend=current_backend())

Calibrate SABR model to a single expiry volatility smile.

Uses Adam optimizer with multi-start initialization for robust global optimization. Tries multiple initial values for ν (vol-of-vol) and picks the best fit. β is typically fixed (0.5 for rates, 1.0 for equities).

Arguments

  • smile - Market smile data for a single expiry

  • beta - CEV exponent (fixed during calibration)

  • max_iter - Maximum optimizer iterations (distributed across multi-start runs)

  • tol - Convergence tolerance for gradient norm and loss plateau detection

  • lr - Learning rate for Adam optimizer

  • backend - AD backend for gradient computation (default: current_backend())

Returns

CalibrationResult with fitted SABRParams containing:

  • params - Calibrated SABRParams (α, β, ρ, ν)

  • rmse - Root mean squared error in implied vol terms

  • converged - Whether optimizer converged (gradient norm < tol OR loss plateau for 20 iterations)

  • iterations - Total iterations across all multi-start runs

Example

julia
quotes = [OptionQuote(K, 1.0, 0.0, :call, market_vol) for (K, market_vol) in market_data]
smile = SmileData(1.0, 100.0, 0.05, quotes)
result = calibrate_sabr(smile; beta=0.5)

# Check fit quality
if result.rmse > 0.01
    @warn "Poor fit, RMSE = $(result.rmse)"
end

# With explicit GPU backend
result = calibrate_sabr(smile; backend=ReactantBackend())
source
QuantNova.Calibration.calibrate_heston Function
julia
calibrate_heston(surface::VolSurface; max_iter=2000, tol=1e-8, lr=0.001, backend=current_backend())

Calibrate Heston model to a full volatility surface.

Uses gradient descent with automatic differentiation. Fits a single set of Heston parameters across all expiries in the surface.

Arguments

  • surface - Market volatility surface data

  • max_iter - Maximum gradient descent iterations

  • tol - Convergence tolerance on loss improvement

  • lr - Learning rate

  • backend - AD backend for gradient computation (default: current_backend())

Returns

CalibrationResult with fitted HestonParams.

Example

julia
smiles = [SmileData(T, F, r, quotes) for (T, F, quotes) in market_data]
surface = VolSurface(100.0, 0.05, smiles)
result = calibrate_heston(surface)

# With explicit GPU backend
result = calibrate_heston(surface; backend=ReactantBackend())
source
QuantNova.Calibration.CalibrationResult Type
julia
CalibrationResult{P}

Result of model calibration.

Fields

  • params::P - Fitted model parameters

  • loss::Float64 - Final objective value

  • converged::Bool - Whether optimization converged

  • iterations::Int - Number of iterations taken

  • rmse::Float64 - Root mean squared error (in volatility terms)

source

Interest Rates

Yield Curves

QuantNova.InterestRates.RateCurve Type
julia
RateCurve

Abstract base type for interest rate curves.

All rate curves support the following operations:

  • discount(curve, T) - Get discount factor to time T

  • zero_rate(curve, T) - Get zero rate to time T

  • forward_rate(curve, T1, T2) - Get forward rate between T1 and T2

  • instantaneous_forward(curve, T) - Get instantaneous forward rate at T

Subtypes

Example

julia
# Create a flat 5% curve
curve = ZeroCurve(0.05)

# Get discount factor and zero rate at 2 years
df = discount(curve, 2.0)      # ≈ 0.9048
r = zero_rate(curve, 2.0)      # = 0.05
source
QuantNova.InterestRates.DiscountCurve Type
julia
DiscountCurve(times, discount_factors; interp=LogLinearInterp())

Curve of discount factors P(0,T). Interpolates in log-space by default to ensure discount factors remain positive.

Arguments

  • times::Vector{Float64} - Maturities in years

  • discount_factors::Vector{Float64} - Discount factors (must be positive)

  • interp::InterpolationMethod - Interpolation method (default: LogLinearInterp)

Constructors

  • DiscountCurve(times, dfs) - From vectors

  • DiscountCurve(rate) - Flat curve at given rate

Example

julia
curve = DiscountCurve([0.0, 1.0, 5.0], [1.0, 0.95, 0.78])
df = discount(curve, 2.5)  # Interpolated discount factor
source
QuantNova.InterestRates.ZeroCurve Type
julia
ZeroCurve(times, zero_rates; interp=LinearInterp())

Curve of continuously compounded zero rates.

source
QuantNova.InterestRates.ForwardCurve Type
julia
ForwardCurve(times, forward_rates; interp=LinearInterp())

Curve of instantaneous forward rates.

source
QuantNova.InterestRates.NelsonSiegelCurve Type
julia
NelsonSiegelCurve(β0, β1, β2, τ)

Nelson-Siegel parametric yield curve model.

The zero rate at maturity T is given by:

julia
r(T) = β₀ + β₁ * (1 - exp(-T/τ)) / (T/τ) + β₂ * ((1 - exp(-T/τ)) / (T/τ) - exp(-T/τ))

Parameters

  • β0 - Long-term rate level (asymptotic rate as T → ∞)

  • β1 - Short-term component (controls slope at origin)

  • β2 - Medium-term component (controls curvature/hump)

  • τ - Decay factor (time at which medium-term component reaches maximum)

Example

julia
curve = NelsonSiegelCurve(0.05, -0.02, 0.01, 2.0)
zero_rate(curve, 5.0)  # Get 5-year zero rate
source
QuantNova.InterestRates.SvenssonCurve Type
julia
SvenssonCurve(β0, β1, β2, β3, τ1, τ2)

Svensson extension of Nelson-Siegel with an additional hump component.

The zero rate at maturity T is given by:

julia
r(T) = β₀ + β₁ * g1(T/τ1) + β₂ * h1(T/τ1) + β₃ * h2(T/τ2)

where:

  • g1(x) = (1 - exp(-x)) / x

  • h1(x) = g1(x) - exp(-x)

  • h2(x) = g1(x, τ2) - exp(-T/τ2)

Parameters

  • β0 - Long-term rate level

  • β1 - Short-term component

  • β2 - First medium-term component (hump at τ1)

  • β3 - Second medium-term component (hump at τ2)

  • τ1 - First decay factor

  • τ2 - Second decay factor

Example

julia
curve = SvenssonCurve(0.05, -0.02, 0.01, 0.005, 2.0, 5.0)
zero_rate(curve, 10.0)  # Get 10-year zero rate
source
QuantNova.InterestRates.discount Function
julia
discount(curve, T) -> Float64

Discount factor from time 0 to time T.

source
QuantNova.InterestRates.zero_rate Function
julia
zero_rate(curve, T) -> Float64

Continuously compounded zero rate to time T.

source
QuantNova.InterestRates.forward_rate Function
julia
forward_rate(curve, T1, T2) -> Float64

Simply compounded forward rate between T1 and T2.

source
QuantNova.InterestRates.instantaneous_forward Function
julia
instantaneous_forward(curve, T) -> Float64

Instantaneous forward rate at time T: f(T) = -d/dT ln(P(0,T))

source
QuantNova.InterestRates.fit_nelson_siegel Function
julia
fit_nelson_siegel(maturities, rates; initial_guess=nothing) -> NelsonSiegelCurve

Fit a Nelson-Siegel curve to observed zero rates using least squares.

Arguments

  • maturities - Vector of maturities (in years)

  • rates - Vector of observed zero rates

  • initial_guess - Optional (β0, β1, β2, τ) starting point

Returns

A fitted NelsonSiegelCurve

Example

julia
mats = [0.25, 0.5, 1.0, 2.0, 5.0, 10.0, 30.0]
rates = [0.02, 0.022, 0.025, 0.028, 0.032, 0.035, 0.037]
curve = fit_nelson_siegel(mats, rates)
source
QuantNova.InterestRates.fit_svensson Function
julia
fit_svensson(maturities, rates; initial_guess=nothing) -> SvenssonCurve

Fit a Svensson curve to observed zero rates using least squares.

Arguments

  • maturities - Vector of maturities (in years)

  • rates - Vector of observed zero rates

  • initial_guess - Optional (β0, β1, β2, β3, τ1, τ2) starting point

Returns

A fitted SvenssonCurve

source

Interpolation

QuantNova.InterestRates.LinearInterp Type
julia
LinearInterp <: InterpolationMethod

Linear interpolation between data points.

Simple and stable, but can produce kinks in forward rates. Best for zero rate curves where smoothness is less critical.

Example

julia
curve = ZeroCurve(times, rates; interp=LinearInterp())
source
QuantNova.InterestRates.LogLinearInterp Type
julia
LogLinearInterp <: InterpolationMethod

Log-linear interpolation (linear in log-space).

The default for discount curves. Ensures discount factors remain positive and produces smoother forward rates than linear interpolation.

Example

julia
curve = DiscountCurve(times, dfs; interp=LogLinearInterp())
source
QuantNova.InterestRates.CubicSplineInterp Type
julia
CubicSplineInterp <: InterpolationMethod

Natural cubic spline interpolation.

Produces the smoothest curves with continuous first and second derivatives. Best for applications requiring smooth forward rates (e.g., HJM models).

Fields

  • coeffs::Vector{NTuple{4,Float64}} - Spline coefficients (a, b, c, d) per segment

Example

julia
curve = ZeroCurve(times, rates; interp=CubicSplineInterp())
source

Bootstrapping

QuantNova.InterestRates.DepositRate Type

Deposit rate: simple rate for short maturities

source
QuantNova.InterestRates.FuturesRate Type

Futures rate: convexity-adjusted forward rate

source
QuantNova.InterestRates.SwapRate Type

Swap rate: par swap rate

source
QuantNova.InterestRates.bootstrap Function
julia
bootstrap(instruments; interp=LogLinearInterp()) -> DiscountCurve

Bootstrap a discount curve from market instruments using sequential stripping.

The function iteratively solves for discount factors that reprice each instrument, starting from the shortest maturity. Instruments should be provided in order of increasing maturity.

Arguments

  • instruments::Vector{<:MarketInstrument} - Market quotes (sorted by maturity)

  • interp::InterpolationMethod - Interpolation for intermediate points

Supported Instruments

Returns

A DiscountCurve that reprices all input instruments.

Example

julia
instruments = [
    DepositRate(0.25, 0.02),   # 3-month deposit at 2%
    DepositRate(0.5, 0.022),   # 6-month deposit at 2.2%
    SwapRate(2.0, 0.028),      # 2-year swap at 2.8%
    SwapRate(5.0, 0.032),      # 5-year swap at 3.2%
]
curve = bootstrap(instruments)

See also: DepositRate, FuturesRate, SwapRate

source

Bonds

QuantNova.InterestRates.Bond Type
julia
Bond

Abstract base type for fixed income instruments.

All bonds support the following operations:

  • price(bond, curve) - Present value using a discount curve

  • price(bond, yield) - Present value at a given yield

  • yield_to_maturity(bond, price) - Solve for yield given price

  • duration(bond, yield) - Macaulay duration

  • modified_duration(bond, yield) - Modified duration

  • convexity(bond, yield) - Convexity

  • dv01(bond, yield) - Dollar value of 1 basis point

Subtypes

Example

julia
bond = FixedRateBond(5.0, 0.04, 2)  # 5-year, 4% semi-annual
curve = ZeroCurve(0.05)
pv = price(bond, curve)
ytm = yield_to_maturity(bond, 95.0)
dur = duration(bond, ytm)
source
QuantNova.InterestRates.ZeroCouponBond Type
julia
ZeroCouponBond(maturity, face_value=100.0)

Zero-coupon bond paying face value at maturity.

Arguments

  • maturity::Float64 - Time to maturity in years

  • face_value::Float64 - Face (par) value (default: 100.0)

Example

julia
zcb = ZeroCouponBond(5.0)  # 5-year zero
price(zcb, 0.05)  # ≈ 78.12 at 5% yield
source
QuantNova.InterestRates.FixedRateBond Type
julia
FixedRateBond(maturity, coupon_rate, frequency=2, face_value=100.0)

Fixed-rate coupon bond. Coupon rate is annual, paid at given frequency.

source
QuantNova.InterestRates.FloatingRateBond Type
julia
FloatingRateBond(maturity, spread, frequency=4, face_value=100.0)

Floating-rate bond paying reference rate + spread.

source
QuantNova.InterestRates.yield_to_maturity Function
julia
yield_to_maturity(bond, market_price; tol=1e-10) -> Float64

Solve for yield given market price using Newton-Raphson.

source
QuantNova.InterestRates.duration Function
julia
duration(bond, yield) -> Float64

Macaulay duration: weighted average time to cash flows.

source
QuantNova.InterestRates.modified_duration Function
julia
modified_duration(bond, yield) -> Float64

Modified duration: -1/P * dP/dy

source
QuantNova.InterestRates.convexity Function
julia
convexity(bond, yield) -> Float64

Convexity: 1/P * d²P/dy²

source
QuantNova.InterestRates.dv01 Function
julia
dv01(bond, yield) -> Float64

Dollar value of 1 basis point: price change for 1bp yield move.

source
QuantNova.InterestRates.accrued_interest Function
julia
accrued_interest(bond, settlement_time) -> Float64

Accrued interest from last coupon to settlement.

source
QuantNova.InterestRates.clean_price Function

Clean price = dirty price - accrued interest

source
QuantNova.InterestRates.dirty_price Function

Dirty price = full price including accrued

source

Short-Rate Models

QuantNova.InterestRates.ShortRateModel Type
julia
ShortRateModel

Base type for short-rate interest rate models.

source
QuantNova.InterestRates.Vasicek Type
julia
Vasicek(κ, θ, σ, r0)

Vasicek model: dr = κ(θ - r)dt + σdW

Parameters:

  • κ: mean reversion speed

  • θ: long-term mean rate

  • σ: volatility

  • r0: initial short rate

source
QuantNova.InterestRates.CIR Type
julia
CIR(κ, θ, σ, r0)

Cox-Ingersoll-Ross model: dr = κ(θ - r)dt + σ√r dW

Feller condition: 2κθ > σ² ensures r stays positive.

source
QuantNova.InterestRates.HullWhite Type
julia
HullWhite(κ, σ, curve)

Hull-White model: dr = (θ(t) - κr)dt + σdW

Time-dependent θ(t) calibrated to fit initial term structure.

source
QuantNova.InterestRates.bond_price Function
julia
bond_price(model, T) -> Float64

Zero-coupon bond price P(0,T) under the short rate model.

source
QuantNova.InterestRates.short_rate Function
julia
short_rate(model, t) -> (mean, variance)

Expected short rate and variance at time t.

source
QuantNova.InterestRates.simulate_short_rate Function
julia
simulate_short_rate(model, T, n_steps, n_paths) -> Matrix

Simulate short rate paths. Returns [n_steps+1 × n_paths] matrix.

source

Interest Rate Derivatives

QuantNova.InterestRates.Caplet Type

Caplet: call option on forward rate

source
QuantNova.InterestRates.Floorlet Type

Floorlet: put option on forward rate

source
QuantNova.InterestRates.Cap Type

Cap: portfolio of caplets

source
QuantNova.InterestRates.Floor Type

Floor: portfolio of floorlets

source
QuantNova.InterestRates.Swaption Type
julia
Swaption(expiry, swap_maturity, strike, is_payer, notional)

European swaption - option to enter a swap.

source
QuantNova.InterestRates.black_caplet Function
julia
black_caplet(caplet, curve, volatility) -> Float64

Price a caplet using Black's formula.

source

Missing docstring.

Missing docstring for black_floorlet. Check Documenter's build log for details.

QuantNova.InterestRates.black_cap Function
julia
black_cap(cap, curve, volatilities) -> Float64

Price a cap as sum of caplets. volatilities can be scalar (flat) or vector (per caplet).

source

Missing docstring.

Missing docstring for black_floor. Check Documenter's build log for details.

Market Data

QuantNova.MarketData.AbstractMarketData Type
julia
AbstractMarketData

Base type for all market data containers.

source
QuantNova.MarketData.AbstractPriceHistory Type
julia
AbstractPriceHistory <: AbstractMarketData

Base type for historical price data (OHLCV).

source
QuantNova.MarketData.AbstractDataAdapter Type
julia
AbstractDataAdapter

Base type for data loading adapters.

source
QuantNova.MarketData.PriceHistory Type
julia
PriceHistory <: AbstractPriceHistory

Container for OHLCV (Open, High, Low, Close, Volume) price data.

Fields

  • symbol::String - Ticker symbol

  • timestamps::Vector{DateTime} - Timestamps for each bar

  • open::Vector{Float64} - Opening prices

  • high::Vector{Float64} - High prices

  • low::Vector{Float64} - Low prices

  • close::Vector{Float64} - Closing prices

  • volume::Vector{Float64} - Trading volume

source
QuantNova.MarketData.returns Function
julia
returns(ph::PriceHistory; type=:simple)

Compute returns from price history.

Arguments

  • type - :simple for (P_t - P_{t-1})/P_{t-1}, :log for log(P_t/P_{t-1})
source
QuantNova.MarketData.resample Function
julia
resample(ph::PriceHistory, frequency::Symbol) -> PriceHistory

Resample price history to a different frequency.

Arguments

  • frequency - :daily, :weekly, :monthly
source
QuantNova.MarketData.align Function
julia
align(histories::Vector{PriceHistory}) -> Vector{PriceHistory}

Align multiple price histories to common timestamps (inner join).

source
QuantNova.MarketData.fetch_prices Function
julia
fetch_prices(symbol::String; range="1y", interval="1d",
             startdt=nothing, enddt=nothing, autoadjust=true) -> PriceHistory

Fetch historical price data from Yahoo Finance.

Arguments

  • symbol - Ticker symbol (e.g., "AAPL", "MSFT", "SPY")

  • range - Time range: "1d", "5d", "1mo", "3mo", "6mo", "1y", "2y", "5y", "10y", "ytd", "max"

  • interval - Data interval: "1m", "2m", "5m", "15m", "30m", "60m", "90m", "1h", "1d", "5d", "1wk", "1mo", "3mo"

  • startdt - Start date (overrides range if provided), format: "YYYY-MM-DD" or Date

  • enddt - End date, format: "YYYY-MM-DD" or Date

  • autoadjust - Whether to use adjusted prices (default: true)

Examples

julia
# Get 1 year of daily AAPL data
prices = fetch_prices("AAPL")

# Get 5 years of weekly data
prices = fetch_prices("AAPL", range="5y", interval="1wk")

# Get data for a specific date range
prices = fetch_prices("AAPL", startdt="2020-01-01", enddt="2024-01-01")
source
QuantNova.MarketData.fetch_multiple Function
julia
fetch_multiple(symbols::Vector{String}; align_dates=true, kwargs...) -> Vector{PriceHistory}

Fetch historical price data for multiple symbols.

Arguments

  • symbols - Vector of ticker symbols

  • align_dates - Whether to align all histories to common dates (default: true)

  • kwargs... - Arguments passed to fetch_prices

Examples

julia
# Fetch and align multiple stocks
histories = fetch_multiple(["AAPL", "MSFT", "GOOGL"])

# Access individual histories
aapl, msft, googl = histories
source
QuantNova.MarketData.fetch_returns Function
julia
fetch_returns(symbol::String; type=:simple, kwargs...) -> Vector{Float64}

Convenience function to fetch prices and compute returns directly.

Arguments

  • symbol - Ticker symbol

  • type - :simple or :log returns

  • kwargs... - Arguments passed to fetch_prices

source
QuantNova.MarketData.fetch_return_matrix Function
julia
fetch_return_matrix(symbols::Vector{String}; type=:simple, kwargs...) -> Matrix{Float64}

Fetch aligned returns for multiple symbols as a matrix.

Returns an (n_periods x n_assets) matrix suitable for portfolio optimization.

Examples

julia
# Get return matrix for portfolio optimization
R = fetch_return_matrix(["AAPL", "MSFT", "GOOGL", "AMZN"], range="2y")
# R is (n_days-1) x 4 matrix
source
QuantNova.MarketData.to_backtest_format Function
julia
to_backtest_format(histories::Vector{PriceHistory}) -> (timestamps, price_series)

Convert aligned PriceHistory objects to backtest-compatible format.

Returns a tuple of:

  • timestamps::Vector{DateTime} - Common timestamps

  • price_series::Dict{Symbol,Vector{Float64}} - Close prices keyed by symbol

Example

julia
histories = fetch_multiple(["AAPL", "MSFT", "GOOGL"], range="1y")
timestamps, prices = to_backtest_format(histories)
result = backtest(strategy, timestamps, prices)
source

Simulation

QuantNova.Simulation.SimulationState Type
julia
SimulationState{T}

Point-in-time snapshot of simulation state.

Fields

  • timestamp::DateTime - Current simulation time

  • cash::T - Cash balance

  • positions::Dict{Symbol,T} - Asset positions (symbol => quantity)

  • prices::Dict{Symbol,T} - Current market prices

  • metadata::Dict{Symbol,Any} - Extensible storage for custom data

source
QuantNova.Simulation.MarketSnapshot Type
julia
MarketSnapshot

Market data at a single point in time (yielded by drivers).

source
QuantNova.Simulation.AbstractDriver Type
julia
AbstractDriver

Base type for market data drivers used in simulations.

source
QuantNova.Simulation.HistoricalDriver Type
julia
HistoricalDriver <: AbstractDriver

Driver that replays historical price data.

source
QuantNova.Simulation.Order Type
julia
Order

A trade order to be executed.

source
QuantNova.Simulation.Fill Type
julia
Fill

Result of executing an order.

source
QuantNova.Simulation.AbstractExecutionModel Type
julia
AbstractExecutionModel

Base type for execution models that translate orders into fills.

source
QuantNova.Simulation.InstantFill Type
julia
InstantFill <: AbstractExecutionModel

Instant execution at current market price with no slippage.

source
QuantNova.Simulation.SlippageModel Type
julia
SlippageModel <: AbstractExecutionModel

Linear slippage based on bid-ask spread.

source
QuantNova.Simulation.MarketImpactModel Type
julia
MarketImpactModel <: AbstractExecutionModel

Slippage with additional price impact based on order size.

source
QuantNova.Simulation.execute Function
julia
execute(model, order, prices; timestamp=now())

Execute an order using the given execution model.

source
QuantNova.Simulation.SimulationResult Type
julia
SimulationResult{T}

Complete result of running a simulation.

source
QuantNova.Simulation.simulate Function
julia
simulate(driver, initial_state; execution_model=InstantFill())

Run simulation over the driver's time series.

source

Backtesting

QuantNova.Backtesting.AbstractStrategy Type
julia
AbstractStrategy

Base type for trading strategies used by the backtesting engine.

source
QuantNova.Backtesting.BuyAndHoldStrategy Type
julia
BuyAndHoldStrategy <: AbstractStrategy

Invest in target weights once and hold.

Fields

  • target_weights::Dict{Symbol,Float64} - Target allocation (must sum to 1.0)

  • invested::Base.RefValue{Bool} - Track if initial investment made

Example

julia
strategy = BuyAndHoldStrategy(Dict(:AAPL => 0.6, :GOOGL => 0.4))
orders = generate_orders(strategy, state)
source
QuantNova.Backtesting.RebalancingStrategy Type
julia
RebalancingStrategy <: AbstractStrategy

Periodically rebalance to target weights.

Fields

  • target_weights::Dict{Symbol,Float64} - Target allocation (must sum to 1.0)

  • rebalance_frequency::Symbol - One of :daily, :weekly, :monthly

  • tolerance::Float64 - Rebalance if off by more than this fraction

  • last_rebalance::Base.RefValue{Union{Nothing,DateTime}} - Last rebalance time

Example

julia
strategy = RebalancingStrategy(
    target_weights=Dict(:AAPL => 0.5, :GOOGL => 0.5),
    rebalance_frequency=:monthly,
    tolerance=0.05
)
source
QuantNova.Backtesting.VolatilityTargetStrategy Type
julia
VolatilityTargetStrategy <: AbstractStrategy

Wraps another strategy and scales positions to target a specific volatility level.

Uses exponentially weighted moving average (EWMA) to estimate realized volatility, then scales all positions to hit the target annualized volatility.

Fields

  • base_strategy::AbstractStrategy - The underlying strategy to wrap

  • target_vol::Float64 - Target annualized volatility (e.g., 0.15 for 15%)

  • lookback::Int - Days for volatility estimation (default: 20)

  • decay::Float64 - EWMA decay factor (default: 0.94, ~20-day half-life)

  • max_leverage::Float64 - Maximum leverage allowed (default: 1.0 = no leverage)

  • min_leverage::Float64 - Minimum leverage (default: 0.1 = 10% invested)

  • rebalance_threshold::Float64 - Only rebalance if leverage changes by this much

Example

julia
base = RebalancingStrategy(target_weights=Dict(:AAPL => 0.5, :MSFT => 0.5), ...)
strategy = VolatilityTargetStrategy(base, target_vol=0.15, max_leverage=1.5)
source
QuantNova.Backtesting.SignalStrategy Type
julia
SignalStrategy <: AbstractStrategy

A flexible strategy where users provide a signal function that computes target weights.

The signal function receives the StrategyContext and current SimulationState, and should return a Dict{Symbol,Float64} of target weights.

Fields

  • signal_fn - Function (ctx::StrategyContext, state::SimulationState) -> Dict{Symbol,Float64}

  • symbols::Vector{Symbol} - Assets to trade

  • rebalance_frequency::Symbol - :daily, :weekly, or :monthly

  • min_weight::Float64 - Minimum weight per asset (default: 0.0)

  • max_weight::Float64 - Maximum weight per asset (default: 1.0)

  • lookback::Int - Price history lookback (default: 252)

Example

julia
# Custom momentum signal
function my_signal(ctx, state)
    weights = Dict{Symbol,Float64}()
    for sym in ctx.symbols
        rets = get_returns(ctx, sym, 20)
        if length(rets) >= 20
            momentum = sum(rets)
            weights[sym] = max(0, momentum)  # Long only if positive momentum
        else
            weights[sym] = 0.0
        end
    end
    # Normalize
    total = sum(values(weights))
    if total > 0
        for sym in keys(weights)
            weights[sym] /= total
        end
    end
    return weights
end

strategy = SignalStrategy(my_signal, [:AAPL, :MSFT, :GOOGL])
source
QuantNova.Backtesting.MomentumStrategy Type
julia
MomentumStrategy <: AbstractStrategy

Trend-following strategy that goes long assets with positive momentum.

Uses past returns over a lookback period to rank assets and allocate to top performers.

Fields

  • symbols::Vector{Symbol} - Assets to trade

  • lookback::Int - Lookback period for momentum calculation (default: 20)

  • top_n::Int - Number of top assets to hold (default: all with positive momentum)

  • rebalance_frequency::Symbol - :daily, :weekly, or :monthly

Example

julia
# Hold top 3 momentum stocks, rebalance monthly
strategy = MomentumStrategy(
    [:AAPL, :MSFT, :GOOGL, :AMZN, :META],
    lookback=60,
    top_n=3,
    rebalance_frequency=:monthly
)
source
QuantNova.Backtesting.MeanReversionStrategy Type
julia
MeanReversionStrategy <: AbstractStrategy

Contrarian strategy that buys underperformers and sells outperformers.

Uses z-scores of recent returns to identify assets that have deviated from their mean and are likely to revert.

Fields

  • symbols::Vector{Symbol} - Assets to trade

  • lookback::Int - Lookback for mean/std calculation (default: 20)

  • entry_threshold::Float64 - Z-score threshold for entry (default: 1.5)

  • rebalance_frequency::Symbol - :daily, :weekly, or :monthly

Example

julia
# Mean reversion with 2 std dev entry threshold
strategy = MeanReversionStrategy(
    [:AAPL, :MSFT, :GOOGL],
    lookback=20,
    entry_threshold=2.0,
    rebalance_frequency=:daily
)
source
QuantNova.Backtesting.CompositeStrategy Type
julia
CompositeStrategy <: AbstractStrategy

Combines multiple strategies with specified weights.

Each sub-strategy generates target weights, which are then combined according to the strategy weights.

Fields

  • strategies::Vector{<:AbstractStrategy} - Sub-strategies

  • strategy_weights::Vector{Float64} - Weight for each strategy (must sum to 1.0)

  • symbols::Vector{Symbol} - All symbols across strategies

Example

julia
# 60% momentum, 40% mean reversion
momentum = MomentumStrategy(symbols, lookback=60)
mean_rev = MeanReversionStrategy(symbols, lookback=20)

strategy = CompositeStrategy(
    [momentum, mean_rev],
    [0.6, 0.4]
)
source
QuantNova.Backtesting.generate_orders Function
julia
generate_orders(strategy, state) -> Vector{Order}

Generate orders based on strategy logic and current state.

source
QuantNova.Backtesting.should_rebalance Function
julia
should_rebalance(strategy, state) -> Bool

Check if strategy should rebalance at current state.

source
QuantNova.Backtesting.BacktestResult Type
julia
BacktestResult

Complete results from running a backtest.

source
QuantNova.Backtesting.backtest Function
julia
backtest(strategy, timestamps, price_series; kwargs...)

Run a full backtest simulation.

Arguments

  • strategy::AbstractStrategy - Trading strategy

  • timestamps::Vector{DateTime} - Time series dates

  • price_series::Dict{Symbol,Vector{Float64}} - Price data per asset

  • initial_cash::Float64=100_000.0 - Starting capital

  • execution_model::AbstractExecutionModel=InstantFill() - How orders execute

  • cost_model::Union{Nothing,AbstractCostModel}=nothing - Transaction cost model

  • adv::Dict{Symbol,Float64}=Dict() - Average daily volume by symbol (for market impact)

Returns

BacktestResult with equity curve, trades, and performance metrics.

Example with transaction costs

julia
using QuantNova

# Create cost model
costs = CompositeCostModel([
    ProportionalCostModel(rate_bps=1.0),
    SpreadCostModel(half_spread_bps=5.0)
])

# Run backtest with costs
result = backtest(strategy, timestamps, prices,
    initial_cash=100_000.0,
    cost_model=costs
)

# Check cost impact
println("Gross return: ", result.metrics[:gross_return])
println("Net return: ", result.metrics[:total_return])
println("Total costs: ", result.total_costs)
source
QuantNova.Backtesting.compute_backtest_metrics Function
julia
compute_backtest_metrics(equity_curve, returns)

Compute standard backtest performance metrics.

source
QuantNova.Backtesting.WalkForwardConfig Type
julia
WalkForwardConfig

Configuration for walk-forward backtesting.

Fields

  • train_period::Int - Number of days for training/optimization window

  • test_period::Int - Number of days for out-of-sample testing

  • step_size::Int - Days to advance between windows (default: test_period)

  • min_train_periods::Int - Minimum training periods before first test

  • expanding::Bool - If true, training window expands; if false, it rolls

source
QuantNova.Backtesting.WalkForwardPeriod Type
julia
WalkForwardPeriod

Results from a single walk-forward period.

source
QuantNova.Backtesting.WalkForwardResult Type
julia
WalkForwardResult

Complete results from walk-forward backtesting.

source
QuantNova.Backtesting.walk_forward_backtest Function
julia
walk_forward_backtest(
    optimizer_fn,
    symbols,
    timestamps,
    price_series;
    config=WalkForwardConfig(),
    initial_cash=100_000.0,
    execution_model=InstantFill()
) -> WalkForwardResult

Run walk-forward backtesting with rolling optimization windows.

Arguments

  • optimizer_fn - Function (train_returns::Matrix, symbols::Vector) -> Dict{Symbol,Float64} that takes training returns and returns optimal weights

  • symbols::Vector{String} - Asset symbols in order

  • timestamps::Vector{DateTime} - Full timestamp series

  • price_series::Dict{Symbol,Vector{Float64}} - Price data per asset

  • config::WalkForwardConfig - Walk-forward configuration

  • initial_cash::Float64 - Starting capital

  • execution_model - Execution model for backtesting

Example

julia
# Define optimizer function
function my_optimizer(returns, symbols)
    μ = vec(mean(returns, dims=1))
    Σ = cov(returns)
    result = optimize(MinimumVariance(Σ))
    return Dict(Symbol(symbols[i]) => result.weights[i] for i in eachindex(symbols))
end

# Run walk-forward
result = walk_forward_backtest(
    my_optimizer,
    ["AAPL", "MSFT", "GOOGL"],
    timestamps,
    prices,
    config=WalkForwardConfig(train_period=252, test_period=21)
)
source
QuantNova.Backtesting.compute_extended_metrics Function
julia
compute_extended_metrics(returns; rf=0.0, benchmark_returns=nothing)

Compute extended performance metrics including Sortino, Information Ratio, etc.

source

Transaction Costs

QuantNova.TransactionCosts.AbstractCostModel Type
julia
AbstractCostModel

Base type for transaction cost models.

source
QuantNova.TransactionCosts.FixedCostModel Type
julia
FixedCostModel <: AbstractCostModel

Flat fee per trade regardless of size.

Fields

  • cost_per_trade::Float64 - Fixed cost per trade (e.g., 5.0)

Example

julia
model = FixedCostModel(5.0)  # $5 per trade
cost = compute_cost(model, 10000.0, 150.0, 1e6)  # Returns 5.0
source
QuantNova.TransactionCosts.ProportionalCostModel Type
julia
ProportionalCostModel <: AbstractCostModel

Commission as a percentage of trade value.

Fields

  • rate_bps::Float64 - Commission rate in basis points (1 bp = 0.01%)

  • min_cost::Float64 - Minimum cost per trade

Example

julia
model = ProportionalCostModel(rate_bps=5.0, min_cost=1.0)  # 5 bps with $1 minimum
cost = compute_cost(model, 10000.0, 150.0, 1e6)  # Returns 5.0 (0.05% of 10000)
source
QuantNova.TransactionCosts.TieredCostModel Type
julia
TieredCostModel <: AbstractCostModel

Volume-based tiered pricing (common for institutional traders).

Fields

  • tiers::Vector{Tuple{Float64,Float64}} - (threshold, rate_bps) pairs, sorted ascending

  • min_cost::Float64 - Minimum cost per trade

Tiers are cumulative: first tier applies up to first threshold, etc.

Example

julia
# 10 bps up to $10k, 5 bps from $10k-$100k, 2 bps above $100k
model = TieredCostModel([
    (10_000.0, 10.0),
    (100_000.0, 5.0),
    (Inf, 2.0)
])
source
QuantNova.TransactionCosts.SpreadCostModel Type
julia
SpreadCostModel <: AbstractCostModel

Bid-ask spread cost model.

Fields

  • half_spread_bps::Float64 - Half the bid-ask spread in basis points

  • spread_estimator::Symbol - How to estimate spread (:fixed, :volatility_based)

  • vol_multiplier::Float64 - For volatility-based: spread = vol * multiplier

Example

julia
# Fixed 5 bps half-spread (10 bps round-trip)
model = SpreadCostModel(half_spread_bps=5.0)

# Volatility-based spread estimation
model = SpreadCostModel(spread_estimator=:volatility_based, vol_multiplier=0.1)
source
QuantNova.TransactionCosts.AlmgrenChrissModel Type
julia
AlmgrenChrissModel <: AbstractCostModel

Square-root market impact model based on Almgren-Chriss framework.

Market impact = σ * √(order_shares / ADV) * price * order_shares

This is the industry-standard model for estimating permanent and temporary price impact from trading.

Fields

  • volatility::Float64 - Daily volatility (annualized σ / √252)

  • participation_rate::Float64 - Fraction of ADV you're willing to trade

  • temporary_impact::Float64 - Temporary impact coefficient (default: 0.1)

  • permanent_impact::Float64 - Permanent impact coefficient (default: 0.1)

Example

julia
model = AlmgrenChrissModel(
    volatility=0.02,           # 2% daily vol
    participation_rate=0.1,    # Trade up to 10% of ADV
    temporary_impact=0.1,
    permanent_impact=0.1
)

Reference

Almgren, R., & Chriss, N. (2000). Optimal execution of portfolio transactions.

source
QuantNova.TransactionCosts.CompositeCostModel Type
julia
CompositeCostModel <: AbstractCostModel

Combines multiple cost models (e.g., commission + spread + market impact).

Example

julia
model = CompositeCostModel([
    ProportionalCostModel(rate_bps=1.0),      # 1 bp commission
    SpreadCostModel(half_spread_bps=5.0),     # 5 bp half-spread
    AlmgrenChrissModel(volatility=0.02)       # Market impact
])
source
QuantNova.TransactionCosts.CostAwareExecutionModel Type
julia
CostAwareExecutionModel

Execution model that tracks detailed transaction costs.

source
QuantNova.TransactionCosts.compute_cost Function
julia
compute_cost(model, order_value, price, volume; kwargs...) -> Float64

Compute transaction cost for a trade.

Arguments

  • order_value - Absolute dollar value of the order

  • price - Current price per share

  • volume - Average daily volume (shares) - used for market impact

source
QuantNova.TransactionCosts.execute_with_costs Function
julia
execute_with_costs(model, symbol, order_value, price) -> (exec_price, breakdown)

Execute a trade and return execution price with cost breakdown.

source
QuantNova.TransactionCosts.TradeCostBreakdown Type
julia
TradeCostBreakdown

Detailed breakdown of costs for a single trade.

source
QuantNova.TransactionCosts.CostTracker Type
julia
CostTracker

Tracks transaction costs across a backtest.

source
QuantNova.TransactionCosts.record_trade! Function
julia
record_trade!(tracker, breakdown)

Record a trade's costs in the tracker.

source
QuantNova.TransactionCosts.cost_summary Function
julia
cost_summary(tracker) -> Dict{Symbol,Float64}

Get summary statistics from cost tracker.

source
QuantNova.TransactionCosts.compute_turnover Function
julia
compute_turnover(weights_history::Vector{Dict{Symbol,Float64}}) -> Float64

Compute total portfolio turnover from a history of weights.

Turnover = Σ |w_t - w_{t-1}| / 2

Returns annualized turnover if daily data (multiply by 252).

source
julia
compute_turnover(positions_history, prices_history) -> Float64

Compute turnover from position and price histories.

source
QuantNova.TransactionCosts.compute_net_returns Function
julia
compute_net_returns(gross_returns, costs, portfolio_values) -> Vector{Float64}

Compute net returns after transaction costs.

Arguments

  • gross_returns - Returns before costs

  • costs - Transaction costs per period

  • portfolio_values - Portfolio value at start of each period

source
QuantNova.TransactionCosts.estimate_break_even_sharpe Function
julia
estimate_break_even_sharpe(cost_bps, volatility; periods_per_year=252) -> Float64

Estimate minimum Sharpe ratio needed to break even after costs.

A strategy with Sharpe below this threshold will likely lose money after costs.

source

Scenario Analysis

QuantNova.ScenarioAnalysis.StressScenario Type
julia
StressScenario{T<:Real}

Defines a stress scenario with shocks to different asset classes.

Fields

  • name::String - Human-readable scenario name

  • description::String - Detailed description of the historical event

  • shocks::Dict{Symbol,T} - Asset class to percent change mapping (e.g., -0.50 for -50%)

  • duration_days::Int - Historical duration of the stress event

Type Parameter

The type parameter T allows AD (automatic differentiation) to work through scenario calculations. For standard usage, T=Float64. For gradient computation via ForwardDiff, T will be ForwardDiff.Dual.

source
QuantNova.ScenarioAnalysis.ScenarioImpact Type
julia
ScenarioImpact

Result of applying a stress scenario.

Fields

  • scenario_name::String - Name of the applied scenario

  • initial_value::Float64 - Portfolio value before stress

  • stressed_value::Float64 - Portfolio value after stress

  • pnl::Float64 - Profit/loss from the scenario

  • pct_change::Float64 - Percentage change in portfolio value

  • asset_impacts::Dict{Symbol,Float64} - Per-asset P&L breakdown

source
QuantNova.ScenarioAnalysis.CRISIS_SCENARIOS Constant
julia
CRISIS_SCENARIOS

Dictionary of built-in historical crisis scenarios for stress testing.

Available scenarios:

  • :financial_crisis_2008 - Global financial crisis, S&P 500 fell ~57% from peak

  • :covid_crash_2020 - Rapid market crash in March 2020

  • :dot_com_bust_2000 - Tech bubble burst, NASDAQ fell ~78%

  • :black_monday_1987 - Single-day crash of 22.6%

  • :rate_shock_2022 - Fed aggressive tightening, bonds and stocks fell together

  • :stagflation_1970s - High inflation with economic stagnation

source
QuantNova.ScenarioAnalysis.apply_scenario Function
julia
apply_scenario(scenario, state, asset_classes)

Apply a stress scenario to a simulation state, returning a new stressed state.

Arguments

  • scenario::StressScenario - The stress scenario to apply

  • state::SimulationState{T} - Current portfolio state

  • asset_classes::Dict{Symbol,Symbol} - Mapping of asset symbols to asset classes

Returns

  • SimulationState{T} - New state with stressed prices

Example

julia
state = SimulationState(
    timestamp=DateTime(2024, 1, 1),
    cash=50_000.0,
    positions=Dict(:SPY => 100.0, :TLT => 50.0),
    prices=Dict(:SPY => 450.0, :TLT => 100.0)
)
asset_classes = Dict(:SPY => :equity, :TLT => :bond)
scenario = CRISIS_SCENARIOS[:financial_crisis_2008]
stressed_state = apply_scenario(scenario, state, asset_classes)
source
QuantNova.ScenarioAnalysis.scenario_impact Function
julia
scenario_impact(scenario, state, asset_classes)

Compute the impact of a stress scenario on a portfolio.

Arguments

  • scenario::StressScenario - The stress scenario to evaluate

  • state::SimulationState - Current portfolio state

  • asset_classes::Dict{Symbol,Symbol} - Mapping of asset symbols to asset classes

Returns

  • ScenarioImpact - Detailed impact analysis including P&L and per-asset breakdown

Example

julia
state = SimulationState(
    timestamp=DateTime(2024, 1, 1),
    cash=50_000.0,
    positions=Dict(:SPY => 100.0, :TLT => 50.0),
    prices=Dict(:SPY => 450.0, :TLT => 100.0)
)
asset_classes = Dict(:SPY => :equity, :TLT => :bond)
scenario = CRISIS_SCENARIOS[:financial_crisis_2008]
impact = scenario_impact(scenario, state, asset_classes)
# impact.pnl < 0 (loss during crisis)
source
QuantNova.ScenarioAnalysis.compare_scenarios Function
julia
compare_scenarios(scenarios, state, asset_classes)

Compare impact of multiple scenarios on a portfolio.

Arguments

  • scenarios::Vector{StressScenario} - List of scenarios to compare

  • state::SimulationState - Current portfolio state

  • asset_classes::Dict{Symbol,Symbol} - Mapping of asset symbols to asset classes

Returns

  • Vector{ScenarioImpact} - Impact results for each scenario

Example

julia
scenarios = [
    CRISIS_SCENARIOS[:financial_crisis_2008],
    CRISIS_SCENARIOS[:covid_crash_2020]
]
impacts = compare_scenarios(scenarios, state, asset_classes)
source
QuantNova.ScenarioAnalysis.worst_case_scenario Function
julia
worst_case_scenario(scenarios, state, asset_classes)

Find the scenario with worst portfolio impact.

Arguments

  • scenarios::Vector{StressScenario} - List of scenarios to evaluate

  • state::SimulationState - Current portfolio state

  • asset_classes::Dict{Symbol,Symbol} - Mapping of asset symbols to asset classes

Returns

  • ScenarioImpact - Impact of the worst-case scenario

Example

julia
scenarios = [
    CRISIS_SCENARIOS[:financial_crisis_2008],
    CRISIS_SCENARIOS[:covid_crash_2020]
]
worst = worst_case_scenario(scenarios, state, asset_classes)
println("Worst case: $(worst.scenario_name) with $(worst.pct_change * 100)% loss")
source
QuantNova.ScenarioAnalysis.SensitivityResult Type
julia
SensitivityResult

Result of a single sensitivity point.

Fields

  • shock::Float64 - The shock level applied (e.g., -0.10 for -10%)

  • portfolio_value::Float64 - Portfolio value after applying the shock

  • pnl::Float64 - Profit/loss from the shock

  • pct_change::Float64 - Percentage change in portfolio value

source
QuantNova.ScenarioAnalysis.sensitivity_analysis Function
julia
sensitivity_analysis(state, asset_classes, target_class; shock_range)

Analyze portfolio sensitivity to shocks in a specific asset class.

Arguments

  • state::SimulationState - Current portfolio state

  • asset_classes::Dict{Symbol,Symbol} - Mapping of asset symbols to asset classes

  • target_class::Symbol - Asset class to shock (e.g., :equity, :bond)

  • shock_range::AbstractRange - Range of shock levels to test (default: -0.50:0.05:0.50)

Returns

  • Vector{SensitivityResult} - Results for each shock level

Example

julia
results = sensitivity_analysis(state, asset_classes, :equity; shock_range=-0.50:0.10:0.50)
for r in results
    println("Shock: $(r.shock*100)% -> Value: $(r.portfolio_value)")
end
source
QuantNova.ScenarioAnalysis.ProjectionResult Type
julia
ProjectionResult

Results from Monte Carlo portfolio projection.

source
QuantNova.ScenarioAnalysis.monte_carlo_projection Function
julia
monte_carlo_projection(state, expected_returns, volatilities; kwargs...)

Project portfolio forward using Monte Carlo simulation.

Arguments

  • state::SimulationState - Current portfolio state

  • expected_returns::Dict{Symbol,Float64} - Annual expected returns per asset

  • volatilities::Dict{Symbol,Float64} - Annual volatilities per asset

  • correlation::Float64=0.3 - Pairwise correlation (simplified)

  • horizon_days::Int=252 - Projection horizon in days

  • n_simulations::Int=10000 - Number of Monte Carlo paths

  • rng - Random number generator (optional)

Returns

ProjectionResult with distribution of terminal values and risk metrics.

source

Factor Models

QuantNova.FactorModels.RegressionResult Type
julia
RegressionResult

Results from factor regression.

source
QuantNova.FactorModels.factor_regression Function
julia
factor_regression(returns, factors; factor_names=nothing, rf=0.0)

Regress strategy returns on factor returns.

returns = α + Σ(βᵢ * factorᵢ) + ε

Returns RegressionResult with alpha, betas, and statistics.

source
QuantNova.FactorModels.capm_regression Function
julia
capm_regression(returns, market_returns; rf=0.0)

Capital Asset Pricing Model regression.

Returns (alpha, beta, r_squared, alpha_tstat, alpha_pvalue)

source
QuantNova.FactorModels.FamaFrenchResult Type
julia
FamaFrenchResult

Results from Fama-French factor analysis.

source
QuantNova.FactorModels.fama_french_regression Function
julia
fama_french_regression(returns, mkt, smb, hml; mom=nothing, rf=0.0)

Fama-French 3-factor (or 4-factor with momentum) regression.

Factors should be factor returns (not cumulative).

source
QuantNova.FactorModels.construct_market_factor Function
julia
construct_market_factor(returns_matrix, weights=nothing) -> Vector{Float64}

Construct market factor from asset returns matrix (n_periods × n_assets). Default: equal-weighted market return.

source
QuantNova.FactorModels.construct_long_short_factor Function
julia
construct_long_short_factor(returns_matrix, signal; quantile=0.3) -> Vector{Float64}

Construct long-short factor: long top quantile, short bottom quantile.

source
QuantNova.FactorModels.AttributionResult Type
julia
AttributionResult

Factor-based return attribution.

source
QuantNova.FactorModels.return_attribution Function
julia
return_attribution(returns, factors, betas, alpha; factor_names=nothing)

Decompose total return into factor contributions + alpha + residual.

source
QuantNova.FactorModels.rolling_beta Function
julia
rolling_beta(returns, factor; window=60) -> Vector{Float64}

Compute rolling beta to a factor.

source
QuantNova.FactorModels.rolling_alpha Function
julia
rolling_alpha(returns, factor; window=60, rf=0.0) -> Vector{Float64}

Compute rolling alpha vs a factor (annualized).

source
QuantNova.FactorModels.StyleAnalysisResult Type
julia
StyleAnalysisResult

Results from returns-based style analysis.

source
QuantNova.FactorModels.style_analysis Function
julia
style_analysis(returns, style_returns; style_names=nothing)

Returns-based style analysis (Sharpe 1992). Constrained regression: weights ≥ 0, sum to 1.

Finds style portfolio that best replicates manager returns.

source
QuantNova.FactorModels.tracking_error Function
julia
tracking_error(returns, benchmark_returns) -> Float64

Annualized tracking error (volatility of active returns).

source
QuantNova.FactorModels.information_ratio Function
julia
information_ratio(returns, benchmark_returns) -> Float64

Annualized information ratio = active return / tracking error.

source
QuantNova.FactorModels.up_capture_ratio Function
julia
up_capture_ratio(returns, benchmark_returns) -> Float64

Up capture = mean(portfolio | benchmark > 0) / mean(benchmark | benchmark > 0)

source
QuantNova.FactorModels.down_capture_ratio Function
julia
down_capture_ratio(returns, benchmark_returns) -> Float64

Down capture = mean(portfolio | benchmark < 0) / mean(benchmark | benchmark < 0) Lower is better (lose less when market falls).

source
QuantNova.FactorModels.capture_ratio Function
julia
capture_ratio(returns, benchmark_returns) -> Float64

Capture ratio = up_capture / down_capture.

1 means manager adds value (captures more upside, less downside).

source

Visualization

QuantNova.Visualization.AbstractVisualization Type
julia
AbstractVisualization

Base type for visualization objects.

source
QuantNova.Visualization.VisualizationSpec Type
julia
VisualizationSpec

Lazy container for visualization configuration. Not rendered until displayed.

source
QuantNova.Visualization.LinkedContext Type
julia
LinkedContext

Shared state for linked interactive plots. All plots sharing a context will synchronize their cursors, zoom levels, and selections.

source
QuantNova.Visualization.visualize Function
julia
visualize(data; kwargs...)
visualize(data, view::Symbol; kwargs...)
visualize(data, views::Vector{Symbol}; kwargs...)

Create a visualization specification for the given data.

Arguments

  • data: Data to visualize (BacktestResult, OptimizationResult, etc.)

  • view: Specific view to render (e.g., :equity, :drawdown, :frontier)

  • views: Multiple views to render as linked panels

  • theme: Override theme (:light, :dark, or custom Dict)

  • backend: Override backend (:gl, :wgl, :cairo)

Examples

julia
result = backtest(strategy, data)
visualize(result)                    # Default view
visualize(result, :drawdown)         # Specific view
visualize(result, [:equity, :drawdown])  # Multiple linked views
source
QuantNova.Visualization.available_views Function
julia
available_views(data)

Return the list of available visualization views for the given data type.

source
QuantNova.Visualization.set_theme! Function
julia
set_theme!(theme::Symbol)

Set the global visualization theme. Options: :light, :dark.

source
QuantNova.Visualization.get_theme Function
julia
get_theme()

Get the current theme dictionary.

source
QuantNova.Visualization.LIGHT_THEME Constant
julia
LIGHT_THEME

Default light theme configuration for visualizations.

source
QuantNova.Visualization.DARK_THEME Constant
julia
DARK_THEME

Default dark theme configuration for visualizations.

source
QuantNova.Visualization.COLORS Constant
julia
COLORS

Semantic color palette used across visualizations.

source
QuantNova.Visualization.render Function
julia
render(spec::VisualizationSpec)

Render a visualization specification to produce a plot.

This function is implemented by the Makie extension (QuantNovaMakieExt). To use it, load Makie or one of its backends (CairoMakie, GLMakie, WGLMakie).

Examples

julia
using QuantNova
using CairoMakie  # or GLMakie, WGLMakie

result = backtest(strategy, data)
spec = visualize(result, :equity)
fig = render(spec)
source
QuantNova.Visualization.Row Type
julia
Row(items...; weight=1)

A row in a dashboard layout.

source
QuantNova.Visualization.Dashboard Type
julia
Dashboard

A multi-panel dashboard layout.

Example

julia
dashboard = Dashboard(
    title = "Strategy Monitor",
    theme = :dark,
    layout = [
        Row(visualize(result, :equity), weight=2),
        Row(visualize(result, :drawdown), visualize(result, :returns)),
    ]
)
serve(dashboard)
source
QuantNova.Visualization.serve Function
julia
serve(item; port=8080)

Serve a visualization or dashboard in the browser. Requires WGLMakie and Bonito to be loaded.

source

Missing docstring.

Missing docstring for save. Check Documenter's build log for details.

Statistics

QuantNova.Statistics.sharpe_ratio Function
julia
sharpe_ratio(returns; rf=0.0, periods_per_year=252) -> Float64

Compute annualized Sharpe ratio.

source
QuantNova.Statistics.sharpe_std_error Function
julia
sharpe_std_error(returns, sharpe; periods_per_year=252) -> Float64

Standard error of Sharpe ratio estimate. Lo (2002) formula. SE(SR) ≈ sqrt((1 + 0.5*SR²) / n)

source
QuantNova.Statistics.sharpe_confidence_interval Function
julia
sharpe_confidence_interval(returns; rf=0.0, confidence=0.95, periods_per_year=252)

Confidence interval for Sharpe ratio.

Returns (sharpe, lower, upper, std_error)

source
QuantNova.Statistics.sharpe_t_stat Function
julia
sharpe_t_stat(returns; rf=0.0, benchmark_sharpe=0.0) -> Float64

T-statistic for Sharpe ratio vs benchmark (default: testing if SR > 0).

source
QuantNova.Statistics.sharpe_pvalue Function
julia
sharpe_pvalue(returns; rf=0.0, benchmark_sharpe=0.0, alternative=:greater) -> Float64

P-value for Sharpe ratio hypothesis test.

  • :greater - test if SR > benchmark (one-tailed)

  • :two_sided - test if SR ≠ benchmark

source
QuantNova.Statistics.probabilistic_sharpe_ratio Function
julia
probabilistic_sharpe_ratio(returns, benchmark_sharpe; rf=0.0) -> Float64

Probability that true Sharpe exceeds benchmark, accounting for skewness/kurtosis. Bailey & López de Prado (2012).

source
QuantNova.Statistics.deflated_sharpe_ratio Function
julia
deflated_sharpe_ratio(returns, n_trials; rf=0.0, expected_max_sr=nothing) -> Float64

Deflated Sharpe Ratio - adjusts for multiple testing (strategy selection bias). Bailey & López de Prado (2014).

n_trials = number of strategies/parameters tested before selecting this one.

source
QuantNova.Statistics.compare_sharpe_ratios Function
julia
compare_sharpe_ratios(returns_a, returns_b; rf=0.0, method=:jobson_korkie)

Test if strategy A has significantly higher Sharpe than strategy B.

Methods:

  • :jobson_korkie - Jobson-Korkie (1981) test

  • :bootstrap - Bootstrap test (more robust)

Returns (z_stat, pvalue, sharpe_diff)

source
QuantNova.Statistics.minimum_backtest_length Function
julia
minimum_backtest_length(sharpe_target, n_trials; confidence=0.95) -> Int

Minimum backtest length needed to achieve target Sharpe with given confidence, accounting for multiple testing. Bailey et al. (2015).

More trials = higher expected max SR under null = need more data to prove significance.

source
QuantNova.Statistics.probability_of_backtest_overfitting Function
julia
probability_of_backtest_overfitting(in_sample_sr, out_sample_sr, n_trials) -> Float64

Estimate probability that backtest is overfit. High if in-sample >> out-sample and many trials.

source
QuantNova.Statistics.combinatorial_purged_cv_pbo Function
julia
combinatorial_purged_cv_pbo(returns, n_paths; train_frac=0.5) -> Float64

Probability of Backtest Overfitting via Combinatorial Purged Cross-Validation. Bailey et al. (2017). Simplified implementation.

Returns probability that strategy is overfit.

source
QuantNova.Statistics.information_coefficient Function
julia
information_coefficient(predictions, outcomes) -> Float64

Correlation between predictions and outcomes. Key alpha metric.

source
QuantNova.Statistics.hit_rate Function
julia
hit_rate(predictions, outcomes) -> Float64

Fraction of correct directional predictions.

source
QuantNova.Statistics.hit_rate_significance Function
julia
hit_rate_significance(hit_rate, n_predictions; benchmark=0.5) -> (z_stat, pvalue)

Test if hit rate is significantly above benchmark (default 50%).

source