API Reference
Pricing
QuantNova.Instruments.black_scholes Function
black_scholes(S, K, T, r, σ, optiontype)Black-Scholes option pricing formula.
Arguments
S- Current price of underlyingK- Strike priceT- Time to expiration (years)r- Risk-free rateσ- Volatilityoptiontype- :call or :put
QuantNova.Instruments.price Function
price(instrument, market_state)Compute the current price of an instrument given market state.
sourceGreeks
QuantNova.Instruments.compute_greeks Function
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 formarket_state- Current market conditionsbackend- AD backend to use for fallback computation (default: current_backend())
QuantNova.Instruments.GreeksResult Type
GreeksResultContainer 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)
Instruments
QuantNova.Instruments.Stock Type
Stock <: AbstractEquityA simple equity instrument.
Fields
symbol::String- Ticker symbol
QuantNova.Instruments.EuropeanOption Type
EuropeanOption <: AbstractOptionA European-style option (exercise only at expiry).
Fields
underlying::String- Symbol of underlying assetstrike::Float64- Strike priceexpiry::Float64- Time to expiration (in years)optiontype::Symbol- :call or :put
QuantNova.PortfolioModule.Portfolio Type
Portfolio{I<:AbstractInstrument} <: AbstractPortfolioA collection of financial instruments with associated position weights.
Fields
instruments::Vector{I}- The instruments in the portfolioweights::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
# 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
Missing docstring.
Missing docstring for value. Check Documenter's build log for details.
QuantNova.PortfolioModule.portfolio_greeks Function
portfolio_greeks(portfolio, market_state)Compute aggregated Greeks for the portfolio. Only includes instruments that have Greeks (options).
sourceQuantNova.Core.MarketState Type
MarketState{P,R,V,T}Immutable snapshot of market conditions.
Fields
prices::P- Current prices by symbolrates::R- Interest rates by currencyvolatilities::V- Implied volatilities by symboltimestamp::T- Time of snapshot
AD System
QuantNova.AD.gradient Function
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.
QuantNova.AD.hessian Function
hessian(f, x; backend=current_backend())Compute the Hessian of f at x using the specified backend.
QuantNova.AD.jacobian Function
jacobian(f, x; backend=current_backend())Compute the Jacobian of f at x using the specified backend.
QuantNova.AD.value_and_gradient Function
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)).
QuantNova.AD.current_backend Function
current_backend()Return the currently active AD backend.
sourceQuantNova.AD.set_backend! Function
set_backend!(backend::ADBackend)Set the global AD backend.
sourceQuantNova.AD.with_backend Function
with_backend(f, backend::ADBackend)Execute f with backend as the active backend, then restore the original.
Example
with_backend(EnzymeBackend()) do
gradient(loss, params)
endBackends
QuantNova.AD.ForwardDiffBackend Type
ForwardDiffBackend <: ADBackendCPU-based forward-mode AD using ForwardDiff.jl. Best for low-dimensional problems and nested derivatives (Greeks).
sourceQuantNova.AD.PureJuliaBackend Type
PureJuliaBackend <: ADBackendReference implementation using finite differences. Slow but always works. Useful for debugging and testing.
sourceQuantNova.AD.EnzymeBackend Type
EnzymeBackend <: ADBackendCPU/GPU AD using Enzyme.jl (LLVM-based differentiation). Supports both forward and reverse mode.
sourceQuantNova.AD.ReactantBackend Type
ReactantBackend <: ADBackendGPU-accelerated AD using Reactant.jl + Enzyme. Best for high-dimensional problems (portfolio optimization).
sourceMonte Carlo
QuantNova.MonteCarlo.GBMDynamics Type
GBMDynamics(r, σ)Geometric Brownian Motion: dS = r_S_dt + σ_S_dW
sourceQuantNova.MonteCarlo.HestonDynamics Type
HestonDynamics(r, v0, κ, θ, ξ, ρ)Heston stochastic volatility model.
sourceQuantNova.MonteCarlo.mc_price Function
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 priceT- Time to maturitypayoff- Payoff structuredynamics- Price dynamics (GBM or Heston)npaths- Number of simulation pathsnsteps- Time steps per pathantithetic- Use antithetic variates for variance reductionrng- Random number generator (optional)
Returns
MCResult with price, standard error, and confidence interval.
sourceQuantNova.MonteCarlo.mc_price_qmc Function
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).
sourceQuantNova.MonteCarlo.mc_delta Function
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.
sourceQuantNova.MonteCarlo.mc_greeks Function
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.
sourceQuantNova.MonteCarlo.lsm_price Function
Arguments
S0- Initial spot priceT- Time to maturityoption- AmericanPut or AmericanCalldynamics- GBMDynamicsnpaths- Number of simulation pathsnsteps- Number of exercise datesrng- Random number generator
Returns
MCResult with American option price and standard error.
Reference
Longstaff & Schwartz (2001), "Valuing American Options by Simulation"
sourcePayoffs
QuantNova.MonteCarlo.EuropeanCall Type
EuropeanCall(K)European call option payoff: max(S_T - K, 0).
Arguments
K::Float64- Strike price
Example
payoff_fn = EuropeanCall(100.0)
result = mc_price(payoff_fn, dynamics, 1.0, 10000)QuantNova.MonteCarlo.EuropeanPut Type
EuropeanPut(K)European put option payoff: max(K - S_T, 0).
Arguments
K::Float64- Strike price
Example
payoff_fn = EuropeanPut(100.0)
result = mc_price(payoff_fn, dynamics, 1.0, 10000)QuantNova.MonteCarlo.AsianCall Type
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
payoff_fn = AsianCall(100.0)
result = mc_price(payoff_fn, dynamics, 1.0, 10000; nsteps=252)QuantNova.MonteCarlo.AsianPut Type
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
payoff_fn = AsianPut(100.0)
result = mc_price(payoff_fn, dynamics, 1.0, 10000; nsteps=252)QuantNova.MonteCarlo.UpAndOutCall Type
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 pricebarrier::Float64- Upper barrier level (must be > K for typical usage)
Example
payoff_fn = UpAndOutCall(100.0, 120.0) # Knocks out if S >= 120
result = mc_price(payoff_fn, dynamics, 1.0, 10000; nsteps=252)QuantNova.MonteCarlo.DownAndOutPut Type
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 pricebarrier::Float64- Lower barrier level (must be < K for typical usage)
Example
payoff_fn = DownAndOutPut(100.0, 80.0) # Knocks out if S <= 80
result = mc_price(payoff_fn, dynamics, 1.0, 10000; nsteps=252)Risk Measures
QuantNova.Risk.VaR Type
VaR <: AbstractRiskMeasureValue at Risk at specified confidence level.
sourceQuantNova.Risk.CVaR Type
CVaR <: AbstractRiskMeasureConditional Value at Risk (Expected Shortfall) at specified confidence level.
sourceQuantNova.Risk.Volatility Type
Volatility <: AbstractRiskMeasureStandard deviation of returns.
sourceQuantNova.Risk.Sharpe Type
Sharpe <: AbstractRiskMeasureSharpe 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)
QuantNova.Risk.MaxDrawdown Type
MaxDrawdown <: AbstractRiskMeasureMaximum peak-to-trough decline.
sourceQuantNova.Risk.compute Function
compute(measure::AbstractRiskMeasure, returns)Compute the risk measure for given returns.
sourceOptimization
QuantNova.Optimization.MeanVariance Type
MeanVarianceMean-variance optimization objective (Markowitz).
sourceQuantNova.Optimization.SharpeMaximizer Type
SharpeMaximizerMaximize Sharpe ratio (non-convex).
sourceQuantNova.Optimization.optimize Function
optimize(objective; kwargs...)Optimize portfolio weights for given objective.
sourceQuantNova.Optimization.OptimizationResult Type
OptimizationResultResult 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 successfullyiterations::Int- Number of iterations used
Example
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)
endSee also: optimize, MeanVariance
Planned Features
CVaRObjective and KellyCriterion types are defined but optimize() methods are not yet implemented.
Stochastic Volatility Models
QuantNova.Models.SABRParams Type
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)
QuantNova.Models.sabr_implied_vol Function
sabr_implied_vol(F, K, T, params::SABRParams)Compute SABR implied volatility using Hagan's approximation formula.
Arguments
F- Forward priceK- Strike priceT- Time to expiry (in years)params- SABR model parameters
Returns
Implied Black volatility for the given strike.
sourceQuantNova.Models.sabr_price Function
sabr_price(F, K, T, r, params::SABRParams, optiontype::Symbol)Price a European option using SABR implied vol + Black-76.
Arguments
F- Forward priceK- Strike priceT- Time to expiry (in years)r- Risk-free rateparams- SABR model parametersoptiontype- :call or :put
Returns
Option price
sourceQuantNova.Models.HestonParams Type
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.
sourceQuantNova.Models.heston_price Function
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 priceK- Strike priceT- Time to expiry (in years)r- Risk-free rateq- Continuous dividend yield (default 0.0)params- Heston model parametersoptiontype- :call or :putN- Number of integration points (default 128)
Returns
Option price
Notes
Uses the Gil-Pelaez / Carr-Madan approach with trapezoidal integration.
Example
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)Calibration
QuantNova.Calibration.OptionQuote Type
OptionQuoteA single option quote from the market.
Fields
strike::Float64- Strike priceexpiry::Float64- Time to expiry (in years)price::Float64- Market price (can be 0 if only using implied_vol)optiontype::Symbol- :call or :putimplied_vol::Float64- Market implied volatility
QuantNova.Calibration.SmileData Type
SmileDataMarket data for a single expiry (a volatility smile).
Fields
expiry::Float64- Time to expiry (in years)forward::Float64- Forward pricerate::Float64- Risk-free interest ratequotes::Vector{OptionQuote}- Option quotes at this expiry
QuantNova.Calibration.VolSurface Type
VolSurfaceMarket data for multiple expiries (full volatility surface).
Fields
spot::Float64- Current spot pricerate::Float64- Risk-free interest ratesmiles::Vector{SmileData}- Smile data for each expiry
QuantNova.Calibration.calibrate_sabr Function
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 expirybeta- CEV exponent (fixed during calibration)max_iter- Maximum optimizer iterations (distributed across multi-start runs)tol- Convergence tolerance for gradient norm and loss plateau detectionlr- Learning rate for Adam optimizerbackend- 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 termsconverged- Whether optimizer converged (gradient norm < tol OR loss plateau for 20 iterations)iterations- Total iterations across all multi-start runs
Example
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())QuantNova.Calibration.calibrate_heston Function
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 datamax_iter- Maximum gradient descent iterationstol- Convergence tolerance on loss improvementlr- Learning ratebackend- AD backend for gradient computation (default: current_backend())
Returns
CalibrationResult with fitted HestonParams.
Example
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())QuantNova.Calibration.CalibrationResult Type
CalibrationResult{P}Result of model calibration.
Fields
params::P- Fitted model parametersloss::Float64- Final objective valueconverged::Bool- Whether optimization convergediterations::Int- Number of iterations takenrmse::Float64- Root mean squared error (in volatility terms)
Interest Rates
Yield Curves
QuantNova.InterestRates.RateCurve Type
RateCurveAbstract base type for interest rate curves.
All rate curves support the following operations:
discount(curve, T)- Get discount factor to time Tzero_rate(curve, T)- Get zero rate to time Tforward_rate(curve, T1, T2)- Get forward rate between T1 and T2instantaneous_forward(curve, T)- Get instantaneous forward rate at T
Subtypes
DiscountCurve- Curve of discount factorsZeroCurve- Curve of zero ratesForwardCurve- Curve of instantaneous forward ratesNelsonSiegelCurve- Parametric Nelson-Siegel curveSvenssonCurve- Parametric Svensson curve
Example
# 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.05QuantNova.InterestRates.DiscountCurve Type
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 yearsdiscount_factors::Vector{Float64}- Discount factors (must be positive)interp::InterpolationMethod- Interpolation method (default: LogLinearInterp)
Constructors
DiscountCurve(times, dfs)- From vectorsDiscountCurve(rate)- Flat curve at given rate
Example
curve = DiscountCurve([0.0, 1.0, 5.0], [1.0, 0.95, 0.78])
df = discount(curve, 2.5) # Interpolated discount factorQuantNova.InterestRates.ZeroCurve Type
ZeroCurve(times, zero_rates; interp=LinearInterp())Curve of continuously compounded zero rates.
sourceQuantNova.InterestRates.ForwardCurve Type
ForwardCurve(times, forward_rates; interp=LinearInterp())Curve of instantaneous forward rates.
sourceQuantNova.InterestRates.NelsonSiegelCurve Type
NelsonSiegelCurve(β0, β1, β2, τ)Nelson-Siegel parametric yield curve model.
The zero rate at maturity T is given by:
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
curve = NelsonSiegelCurve(0.05, -0.02, 0.01, 2.0)
zero_rate(curve, 5.0) # Get 5-year zero rateQuantNova.InterestRates.SvenssonCurve Type
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:
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
curve = SvenssonCurve(0.05, -0.02, 0.01, 0.005, 2.0, 5.0)
zero_rate(curve, 10.0) # Get 10-year zero rateQuantNova.InterestRates.discount Function
discount(curve, T) -> Float64Discount factor from time 0 to time T.
sourceQuantNova.InterestRates.zero_rate Function
zero_rate(curve, T) -> Float64Continuously compounded zero rate to time T.
sourceQuantNova.InterestRates.forward_rate Function
forward_rate(curve, T1, T2) -> Float64Simply compounded forward rate between T1 and T2.
sourceQuantNova.InterestRates.instantaneous_forward Function
instantaneous_forward(curve, T) -> Float64Instantaneous forward rate at time T: f(T) = -d/dT ln(P(0,T))
sourceQuantNova.InterestRates.fit_nelson_siegel Function
fit_nelson_siegel(maturities, rates; initial_guess=nothing) -> NelsonSiegelCurveFit a Nelson-Siegel curve to observed zero rates using least squares.
Arguments
maturities- Vector of maturities (in years)rates- Vector of observed zero ratesinitial_guess- Optional (β0, β1, β2, τ) starting point
Returns
A fitted NelsonSiegelCurve
Example
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)QuantNova.InterestRates.fit_svensson Function
fit_svensson(maturities, rates; initial_guess=nothing) -> SvenssonCurveFit a Svensson curve to observed zero rates using least squares.
Arguments
maturities- Vector of maturities (in years)rates- Vector of observed zero ratesinitial_guess- Optional (β0, β1, β2, β3, τ1, τ2) starting point
Returns
A fitted SvenssonCurve
sourceInterpolation
QuantNova.InterestRates.LinearInterp Type
LinearInterp <: InterpolationMethodLinear 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
curve = ZeroCurve(times, rates; interp=LinearInterp())QuantNova.InterestRates.LogLinearInterp Type
LogLinearInterp <: InterpolationMethodLog-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
curve = DiscountCurve(times, dfs; interp=LogLinearInterp())QuantNova.InterestRates.CubicSplineInterp Type
CubicSplineInterp <: InterpolationMethodNatural 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
curve = ZeroCurve(times, rates; interp=CubicSplineInterp())Bootstrapping
QuantNova.InterestRates.bootstrap Function
bootstrap(instruments; interp=LogLinearInterp()) -> DiscountCurveBootstrap 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
DepositRate- Money market deposits (short end)FuturesRate- Interest rate futures (middle)SwapRate- Par swap rates (long end)
Returns
A DiscountCurve that reprices all input instruments.
Example
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
Bonds
QuantNova.InterestRates.Bond Type
BondAbstract base type for fixed income instruments.
All bonds support the following operations:
price(bond, curve)- Present value using a discount curveprice(bond, yield)- Present value at a given yieldyield_to_maturity(bond, price)- Solve for yield given priceduration(bond, yield)- Macaulay durationmodified_duration(bond, yield)- Modified durationconvexity(bond, yield)- Convexitydv01(bond, yield)- Dollar value of 1 basis point
Subtypes
ZeroCouponBond- Zero-coupon (discount) bondFixedRateBond- Fixed-rate coupon bondFloatingRateBond- Floating-rate bond
Example
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)QuantNova.InterestRates.ZeroCouponBond Type
ZeroCouponBond(maturity, face_value=100.0)Zero-coupon bond paying face value at maturity.
Arguments
maturity::Float64- Time to maturity in yearsface_value::Float64- Face (par) value (default: 100.0)
Example
zcb = ZeroCouponBond(5.0) # 5-year zero
price(zcb, 0.05) # ≈ 78.12 at 5% yieldQuantNova.InterestRates.FixedRateBond Type
FixedRateBond(maturity, coupon_rate, frequency=2, face_value=100.0)Fixed-rate coupon bond. Coupon rate is annual, paid at given frequency.
sourceQuantNova.InterestRates.FloatingRateBond Type
FloatingRateBond(maturity, spread, frequency=4, face_value=100.0)Floating-rate bond paying reference rate + spread.
sourceQuantNova.InterestRates.yield_to_maturity Function
yield_to_maturity(bond, market_price; tol=1e-10) -> Float64Solve for yield given market price using Newton-Raphson.
sourceQuantNova.InterestRates.duration Function
duration(bond, yield) -> Float64Macaulay duration: weighted average time to cash flows.
sourceQuantNova.InterestRates.modified_duration Function
modified_duration(bond, yield) -> Float64Modified duration: -1/P * dP/dy
sourceQuantNova.InterestRates.convexity Function
convexity(bond, yield) -> Float64Convexity: 1/P * d²P/dy²
sourceQuantNova.InterestRates.dv01 Function
dv01(bond, yield) -> Float64Dollar value of 1 basis point: price change for 1bp yield move.
sourceQuantNova.InterestRates.accrued_interest Function
accrued_interest(bond, settlement_time) -> Float64Accrued interest from last coupon to settlement.
sourceShort-Rate Models
QuantNova.InterestRates.ShortRateModel Type
ShortRateModelBase type for short-rate interest rate models.
sourceQuantNova.InterestRates.Vasicek Type
Vasicek(κ, θ, σ, r0)Vasicek model: dr = κ(θ - r)dt + σdW
Parameters:
κ: mean reversion speed
θ: long-term mean rate
σ: volatility
r0: initial short rate
QuantNova.InterestRates.CIR Type
CIR(κ, θ, σ, r0)Cox-Ingersoll-Ross model: dr = κ(θ - r)dt + σ√r dW
Feller condition: 2κθ > σ² ensures r stays positive.
sourceQuantNova.InterestRates.HullWhite Type
HullWhite(κ, σ, curve)Hull-White model: dr = (θ(t) - κr)dt + σdW
Time-dependent θ(t) calibrated to fit initial term structure.
sourceQuantNova.InterestRates.bond_price Function
bond_price(model, T) -> Float64Zero-coupon bond price P(0,T) under the short rate model.
sourceQuantNova.InterestRates.short_rate Function
short_rate(model, t) -> (mean, variance)Expected short rate and variance at time t.
sourceQuantNova.InterestRates.simulate_short_rate Function
simulate_short_rate(model, T, n_steps, n_paths) -> MatrixSimulate short rate paths. Returns [n_steps+1 × n_paths] matrix.
sourceInterest Rate Derivatives
QuantNova.InterestRates.Swaption Type
Swaption(expiry, swap_maturity, strike, is_payer, notional)European swaption - option to enter a swap.
sourceQuantNova.InterestRates.black_caplet Function
black_caplet(caplet, curve, volatility) -> Float64Price a caplet using Black's formula.
sourceMissing docstring.
Missing docstring for black_floorlet. Check Documenter's build log for details.
QuantNova.InterestRates.black_cap Function
black_cap(cap, curve, volatilities) -> Float64Price a cap as sum of caplets. volatilities can be scalar (flat) or vector (per caplet).
sourceMissing docstring.
Missing docstring for black_floor. Check Documenter's build log for details.
Market Data
QuantNova.MarketData.AbstractMarketData Type
AbstractMarketDataBase type for all market data containers.
sourceQuantNova.MarketData.AbstractPriceHistory Type
AbstractPriceHistory <: AbstractMarketDataBase type for historical price data (OHLCV).
sourceQuantNova.MarketData.AbstractDataAdapter Type
AbstractDataAdapterBase type for data loading adapters.
sourceQuantNova.MarketData.PriceHistory Type
PriceHistory <: AbstractPriceHistoryContainer for OHLCV (Open, High, Low, Close, Volume) price data.
Fields
symbol::String- Ticker symboltimestamps::Vector{DateTime}- Timestamps for each baropen::Vector{Float64}- Opening priceshigh::Vector{Float64}- High priceslow::Vector{Float64}- Low pricesclose::Vector{Float64}- Closing pricesvolume::Vector{Float64}- Trading volume
QuantNova.MarketData.returns Function
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})
QuantNova.MarketData.resample Function
resample(ph::PriceHistory, frequency::Symbol) -> PriceHistoryResample price history to a different frequency.
Arguments
frequency- :daily, :weekly, :monthly
QuantNova.MarketData.align Function
align(histories::Vector{PriceHistory}) -> Vector{PriceHistory}Align multiple price histories to common timestamps (inner join).
sourceQuantNova.MarketData.fetch_prices Function
fetch_prices(symbol::String; range="1y", interval="1d",
startdt=nothing, enddt=nothing, autoadjust=true) -> PriceHistoryFetch 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 Dateenddt- End date, format: "YYYY-MM-DD" or Dateautoadjust- Whether to use adjusted prices (default: true)
Examples
# 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")QuantNova.MarketData.fetch_multiple Function
fetch_multiple(symbols::Vector{String}; align_dates=true, kwargs...) -> Vector{PriceHistory}Fetch historical price data for multiple symbols.
Arguments
symbols- Vector of ticker symbolsalign_dates- Whether to align all histories to common dates (default: true)kwargs...- Arguments passed tofetch_prices
Examples
# Fetch and align multiple stocks
histories = fetch_multiple(["AAPL", "MSFT", "GOOGL"])
# Access individual histories
aapl, msft, googl = historiesQuantNova.MarketData.fetch_returns Function
fetch_returns(symbol::String; type=:simple, kwargs...) -> Vector{Float64}Convenience function to fetch prices and compute returns directly.
Arguments
symbol- Ticker symboltype- :simple or :log returnskwargs...- Arguments passed tofetch_prices
QuantNova.MarketData.fetch_return_matrix Function
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
# Get return matrix for portfolio optimization
R = fetch_return_matrix(["AAPL", "MSFT", "GOOGL", "AMZN"], range="2y")
# R is (n_days-1) x 4 matrixQuantNova.MarketData.to_backtest_format Function
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 timestampsprice_series::Dict{Symbol,Vector{Float64}}- Close prices keyed by symbol
Example
histories = fetch_multiple(["AAPL", "MSFT", "GOOGL"], range="1y")
timestamps, prices = to_backtest_format(histories)
result = backtest(strategy, timestamps, prices)Simulation
QuantNova.Simulation.SimulationState Type
SimulationState{T}Point-in-time snapshot of simulation state.
Fields
timestamp::DateTime- Current simulation timecash::T- Cash balancepositions::Dict{Symbol,T}- Asset positions (symbol => quantity)prices::Dict{Symbol,T}- Current market pricesmetadata::Dict{Symbol,Any}- Extensible storage for custom data
QuantNova.Simulation.MarketSnapshot Type
MarketSnapshotMarket data at a single point in time (yielded by drivers).
sourceQuantNova.Simulation.AbstractDriver Type
AbstractDriverBase type for market data drivers used in simulations.
sourceQuantNova.Simulation.HistoricalDriver Type
HistoricalDriver <: AbstractDriverDriver that replays historical price data.
sourceQuantNova.Simulation.AbstractExecutionModel Type
AbstractExecutionModelBase type for execution models that translate orders into fills.
sourceQuantNova.Simulation.InstantFill Type
InstantFill <: AbstractExecutionModelInstant execution at current market price with no slippage.
sourceQuantNova.Simulation.SlippageModel Type
SlippageModel <: AbstractExecutionModelLinear slippage based on bid-ask spread.
sourceQuantNova.Simulation.MarketImpactModel Type
MarketImpactModel <: AbstractExecutionModelSlippage with additional price impact based on order size.
sourceQuantNova.Simulation.execute Function
execute(model, order, prices; timestamp=now())Execute an order using the given execution model.
sourceQuantNova.Simulation.SimulationResult Type
SimulationResult{T}Complete result of running a simulation.
sourceQuantNova.Simulation.simulate Function
simulate(driver, initial_state; execution_model=InstantFill())Run simulation over the driver's time series.
sourceBacktesting
QuantNova.Backtesting.AbstractStrategy Type
AbstractStrategyBase type for trading strategies used by the backtesting engine.
sourceQuantNova.Backtesting.BuyAndHoldStrategy Type
BuyAndHoldStrategy <: AbstractStrategyInvest 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
strategy = BuyAndHoldStrategy(Dict(:AAPL => 0.6, :GOOGL => 0.4))
orders = generate_orders(strategy, state)QuantNova.Backtesting.RebalancingStrategy Type
RebalancingStrategy <: AbstractStrategyPeriodically rebalance to target weights.
Fields
target_weights::Dict{Symbol,Float64}- Target allocation (must sum to 1.0)rebalance_frequency::Symbol- One of :daily, :weekly, :monthlytolerance::Float64- Rebalance if off by more than this fractionlast_rebalance::Base.RefValue{Union{Nothing,DateTime}}- Last rebalance time
Example
strategy = RebalancingStrategy(
target_weights=Dict(:AAPL => 0.5, :GOOGL => 0.5),
rebalance_frequency=:monthly,
tolerance=0.05
)QuantNova.Backtesting.VolatilityTargetStrategy Type
VolatilityTargetStrategy <: AbstractStrategyWraps 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 wraptarget_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
base = RebalancingStrategy(target_weights=Dict(:AAPL => 0.5, :MSFT => 0.5), ...)
strategy = VolatilityTargetStrategy(base, target_vol=0.15, max_leverage=1.5)QuantNova.Backtesting.SignalStrategy Type
SignalStrategy <: AbstractStrategyA 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 traderebalance_frequency::Symbol- :daily, :weekly, or :monthlymin_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
# 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])QuantNova.Backtesting.MomentumStrategy Type
MomentumStrategy <: AbstractStrategyTrend-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 tradelookback::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
# Hold top 3 momentum stocks, rebalance monthly
strategy = MomentumStrategy(
[:AAPL, :MSFT, :GOOGL, :AMZN, :META],
lookback=60,
top_n=3,
rebalance_frequency=:monthly
)QuantNova.Backtesting.MeanReversionStrategy Type
MeanReversionStrategy <: AbstractStrategyContrarian 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 tradelookback::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
# Mean reversion with 2 std dev entry threshold
strategy = MeanReversionStrategy(
[:AAPL, :MSFT, :GOOGL],
lookback=20,
entry_threshold=2.0,
rebalance_frequency=:daily
)QuantNova.Backtesting.CompositeStrategy Type
CompositeStrategy <: AbstractStrategyCombines 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-strategiesstrategy_weights::Vector{Float64}- Weight for each strategy (must sum to 1.0)symbols::Vector{Symbol}- All symbols across strategies
Example
# 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]
)QuantNova.Backtesting.generate_orders Function
generate_orders(strategy, state) -> Vector{Order}Generate orders based on strategy logic and current state.
sourceQuantNova.Backtesting.should_rebalance Function
should_rebalance(strategy, state) -> BoolCheck if strategy should rebalance at current state.
sourceQuantNova.Backtesting.BacktestResult Type
BacktestResultComplete results from running a backtest.
sourceQuantNova.Backtesting.backtest Function
backtest(strategy, timestamps, price_series; kwargs...)Run a full backtest simulation.
Arguments
strategy::AbstractStrategy- Trading strategytimestamps::Vector{DateTime}- Time series datesprice_series::Dict{Symbol,Vector{Float64}}- Price data per assetinitial_cash::Float64=100_000.0- Starting capitalexecution_model::AbstractExecutionModel=InstantFill()- How orders executecost_model::Union{Nothing,AbstractCostModel}=nothing- Transaction cost modeladv::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
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)QuantNova.Backtesting.compute_backtest_metrics Function
compute_backtest_metrics(equity_curve, returns)Compute standard backtest performance metrics.
sourceQuantNova.Backtesting.WalkForwardConfig Type
WalkForwardConfigConfiguration for walk-forward backtesting.
Fields
train_period::Int- Number of days for training/optimization windowtest_period::Int- Number of days for out-of-sample testingstep_size::Int- Days to advance between windows (default: test_period)min_train_periods::Int- Minimum training periods before first testexpanding::Bool- If true, training window expands; if false, it rolls
QuantNova.Backtesting.WalkForwardPeriod Type
WalkForwardPeriodResults from a single walk-forward period.
sourceQuantNova.Backtesting.WalkForwardResult Type
WalkForwardResultComplete results from walk-forward backtesting.
sourceQuantNova.Backtesting.walk_forward_backtest Function
walk_forward_backtest(
optimizer_fn,
symbols,
timestamps,
price_series;
config=WalkForwardConfig(),
initial_cash=100_000.0,
execution_model=InstantFill()
) -> WalkForwardResultRun 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 weightssymbols::Vector{String}- Asset symbols in ordertimestamps::Vector{DateTime}- Full timestamp seriesprice_series::Dict{Symbol,Vector{Float64}}- Price data per assetconfig::WalkForwardConfig- Walk-forward configurationinitial_cash::Float64- Starting capitalexecution_model- Execution model for backtesting
Example
# 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)
)QuantNova.Backtesting.compute_extended_metrics Function
compute_extended_metrics(returns; rf=0.0, benchmark_returns=nothing)Compute extended performance metrics including Sortino, Information Ratio, etc.
sourceTransaction Costs
QuantNova.TransactionCosts.AbstractCostModel Type
AbstractCostModelBase type for transaction cost models.
sourceQuantNova.TransactionCosts.FixedCostModel Type
FixedCostModel <: AbstractCostModelFlat fee per trade regardless of size.
Fields
cost_per_trade::Float64- Fixed cost per trade (e.g., 5.0)
Example
model = FixedCostModel(5.0) # $5 per trade
cost = compute_cost(model, 10000.0, 150.0, 1e6) # Returns 5.0QuantNova.TransactionCosts.ProportionalCostModel Type
ProportionalCostModel <: AbstractCostModelCommission 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
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)QuantNova.TransactionCosts.TieredCostModel Type
TieredCostModel <: AbstractCostModelVolume-based tiered pricing (common for institutional traders).
Fields
tiers::Vector{Tuple{Float64,Float64}}- (threshold, rate_bps) pairs, sorted ascendingmin_cost::Float64- Minimum cost per trade
Tiers are cumulative: first tier applies up to first threshold, etc.
Example
# 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)
])QuantNova.TransactionCosts.SpreadCostModel Type
SpreadCostModel <: AbstractCostModelBid-ask spread cost model.
Fields
half_spread_bps::Float64- Half the bid-ask spread in basis pointsspread_estimator::Symbol- How to estimate spread (:fixed, :volatility_based)vol_multiplier::Float64- For volatility-based: spread = vol * multiplier
Example
# 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)QuantNova.TransactionCosts.AlmgrenChrissModel Type
AlmgrenChrissModel <: AbstractCostModelSquare-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 tradetemporary_impact::Float64- Temporary impact coefficient (default: 0.1)permanent_impact::Float64- Permanent impact coefficient (default: 0.1)
Example
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.
sourceQuantNova.TransactionCosts.CompositeCostModel Type
CompositeCostModel <: AbstractCostModelCombines multiple cost models (e.g., commission + spread + market impact).
Example
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
])QuantNova.TransactionCosts.CostAwareExecutionModel Type
CostAwareExecutionModelExecution model that tracks detailed transaction costs.
sourceQuantNova.TransactionCosts.compute_cost Function
compute_cost(model, order_value, price, volume; kwargs...) -> Float64Compute transaction cost for a trade.
Arguments
order_value- Absolute dollar value of the orderprice- Current price per sharevolume- Average daily volume (shares) - used for market impact
QuantNova.TransactionCosts.execute_with_costs Function
execute_with_costs(model, symbol, order_value, price) -> (exec_price, breakdown)Execute a trade and return execution price with cost breakdown.
sourceQuantNova.TransactionCosts.TradeCostBreakdown Type
TradeCostBreakdownDetailed breakdown of costs for a single trade.
sourceQuantNova.TransactionCosts.CostTracker Type
CostTrackerTracks transaction costs across a backtest.
sourceQuantNova.TransactionCosts.record_trade! Function
record_trade!(tracker, breakdown)Record a trade's costs in the tracker.
sourceQuantNova.TransactionCosts.cost_summary Function
cost_summary(tracker) -> Dict{Symbol,Float64}Get summary statistics from cost tracker.
sourceQuantNova.TransactionCosts.compute_turnover Function
compute_turnover(weights_history::Vector{Dict{Symbol,Float64}}) -> Float64Compute total portfolio turnover from a history of weights.
Turnover = Σ |w_t - w_{t-1}| / 2
Returns annualized turnover if daily data (multiply by 252).
sourcecompute_turnover(positions_history, prices_history) -> Float64Compute turnover from position and price histories.
sourceQuantNova.TransactionCosts.compute_net_returns Function
compute_net_returns(gross_returns, costs, portfolio_values) -> Vector{Float64}Compute net returns after transaction costs.
Arguments
gross_returns- Returns before costscosts- Transaction costs per periodportfolio_values- Portfolio value at start of each period
QuantNova.TransactionCosts.estimate_break_even_sharpe Function
estimate_break_even_sharpe(cost_bps, volatility; periods_per_year=252) -> Float64Estimate minimum Sharpe ratio needed to break even after costs.
A strategy with Sharpe below this threshold will likely lose money after costs.
sourceScenario Analysis
QuantNova.ScenarioAnalysis.StressScenario Type
StressScenario{T<:Real}Defines a stress scenario with shocks to different asset classes.
Fields
name::String- Human-readable scenario namedescription::String- Detailed description of the historical eventshocks::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.
QuantNova.ScenarioAnalysis.ScenarioImpact Type
ScenarioImpactResult of applying a stress scenario.
Fields
scenario_name::String- Name of the applied scenarioinitial_value::Float64- Portfolio value before stressstressed_value::Float64- Portfolio value after stresspnl::Float64- Profit/loss from the scenariopct_change::Float64- Percentage change in portfolio valueasset_impacts::Dict{Symbol,Float64}- Per-asset P&L breakdown
QuantNova.ScenarioAnalysis.CRISIS_SCENARIOS Constant
CRISIS_SCENARIOSDictionary 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
QuantNova.ScenarioAnalysis.apply_scenario Function
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 applystate::SimulationState{T}- Current portfolio stateasset_classes::Dict{Symbol,Symbol}- Mapping of asset symbols to asset classes
Returns
SimulationState{T}- New state with stressed prices
Example
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)QuantNova.ScenarioAnalysis.scenario_impact Function
scenario_impact(scenario, state, asset_classes)Compute the impact of a stress scenario on a portfolio.
Arguments
scenario::StressScenario- The stress scenario to evaluatestate::SimulationState- Current portfolio stateasset_classes::Dict{Symbol,Symbol}- Mapping of asset symbols to asset classes
Returns
ScenarioImpact- Detailed impact analysis including P&L and per-asset breakdown
Example
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)QuantNova.ScenarioAnalysis.compare_scenarios Function
compare_scenarios(scenarios, state, asset_classes)Compare impact of multiple scenarios on a portfolio.
Arguments
scenarios::Vector{StressScenario}- List of scenarios to comparestate::SimulationState- Current portfolio stateasset_classes::Dict{Symbol,Symbol}- Mapping of asset symbols to asset classes
Returns
Vector{ScenarioImpact}- Impact results for each scenario
Example
scenarios = [
CRISIS_SCENARIOS[:financial_crisis_2008],
CRISIS_SCENARIOS[:covid_crash_2020]
]
impacts = compare_scenarios(scenarios, state, asset_classes)QuantNova.ScenarioAnalysis.worst_case_scenario Function
worst_case_scenario(scenarios, state, asset_classes)Find the scenario with worst portfolio impact.
Arguments
scenarios::Vector{StressScenario}- List of scenarios to evaluatestate::SimulationState- Current portfolio stateasset_classes::Dict{Symbol,Symbol}- Mapping of asset symbols to asset classes
Returns
ScenarioImpact- Impact of the worst-case scenario
Example
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")QuantNova.ScenarioAnalysis.SensitivityResult Type
SensitivityResultResult 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 shockpnl::Float64- Profit/loss from the shockpct_change::Float64- Percentage change in portfolio value
QuantNova.ScenarioAnalysis.sensitivity_analysis Function
sensitivity_analysis(state, asset_classes, target_class; shock_range)Analyze portfolio sensitivity to shocks in a specific asset class.
Arguments
state::SimulationState- Current portfolio stateasset_classes::Dict{Symbol,Symbol}- Mapping of asset symbols to asset classestarget_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
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)")
endQuantNova.ScenarioAnalysis.ProjectionResult Type
ProjectionResultResults from Monte Carlo portfolio projection.
sourceQuantNova.ScenarioAnalysis.monte_carlo_projection Function
monte_carlo_projection(state, expected_returns, volatilities; kwargs...)Project portfolio forward using Monte Carlo simulation.
Arguments
state::SimulationState- Current portfolio stateexpected_returns::Dict{Symbol,Float64}- Annual expected returns per assetvolatilities::Dict{Symbol,Float64}- Annual volatilities per assetcorrelation::Float64=0.3- Pairwise correlation (simplified)horizon_days::Int=252- Projection horizon in daysn_simulations::Int=10000- Number of Monte Carlo pathsrng- Random number generator (optional)
Returns
ProjectionResult with distribution of terminal values and risk metrics.
Factor Models
QuantNova.FactorModels.RegressionResult Type
RegressionResultResults from factor regression.
sourceQuantNova.FactorModels.factor_regression Function
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.
sourceQuantNova.FactorModels.capm_regression Function
capm_regression(returns, market_returns; rf=0.0)Capital Asset Pricing Model regression.
Returns (alpha, beta, r_squared, alpha_tstat, alpha_pvalue)
sourceQuantNova.FactorModels.FamaFrenchResult Type
FamaFrenchResultResults from Fama-French factor analysis.
sourceQuantNova.FactorModels.fama_french_regression Function
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).
sourceQuantNova.FactorModels.construct_market_factor Function
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.
sourceQuantNova.FactorModels.construct_long_short_factor Function
construct_long_short_factor(returns_matrix, signal; quantile=0.3) -> Vector{Float64}Construct long-short factor: long top quantile, short bottom quantile.
sourceQuantNova.FactorModels.AttributionResult Type
AttributionResultFactor-based return attribution.
sourceQuantNova.FactorModels.return_attribution Function
return_attribution(returns, factors, betas, alpha; factor_names=nothing)Decompose total return into factor contributions + alpha + residual.
sourceQuantNova.FactorModels.rolling_beta Function
rolling_beta(returns, factor; window=60) -> Vector{Float64}Compute rolling beta to a factor.
sourceQuantNova.FactorModels.rolling_alpha Function
rolling_alpha(returns, factor; window=60, rf=0.0) -> Vector{Float64}Compute rolling alpha vs a factor (annualized).
sourceQuantNova.FactorModels.StyleAnalysisResult Type
StyleAnalysisResultResults from returns-based style analysis.
sourceQuantNova.FactorModels.style_analysis Function
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.
sourceQuantNova.FactorModels.tracking_error Function
tracking_error(returns, benchmark_returns) -> Float64Annualized tracking error (volatility of active returns).
sourceQuantNova.FactorModels.information_ratio Function
information_ratio(returns, benchmark_returns) -> Float64Annualized information ratio = active return / tracking error.
sourceQuantNova.FactorModels.up_capture_ratio Function
up_capture_ratio(returns, benchmark_returns) -> Float64Up capture = mean(portfolio | benchmark > 0) / mean(benchmark | benchmark > 0)
sourceQuantNova.FactorModels.down_capture_ratio Function
down_capture_ratio(returns, benchmark_returns) -> Float64Down capture = mean(portfolio | benchmark < 0) / mean(benchmark | benchmark < 0) Lower is better (lose less when market falls).
sourceQuantNova.FactorModels.capture_ratio Function
capture_ratio(returns, benchmark_returns) -> Float64Capture ratio = up_capture / down_capture.
source1 means manager adds value (captures more upside, less downside).
Visualization
QuantNova.Visualization.AbstractVisualization Type
AbstractVisualizationBase type for visualization objects.
sourceQuantNova.Visualization.VisualizationSpec Type
VisualizationSpecLazy container for visualization configuration. Not rendered until displayed.
sourceQuantNova.Visualization.LinkedContext Type
LinkedContextShared state for linked interactive plots. All plots sharing a context will synchronize their cursors, zoom levels, and selections.
sourceQuantNova.Visualization.visualize Function
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 panelstheme: Override theme (:light,:dark, or custom Dict)backend: Override backend (:gl,:wgl,:cairo)
Examples
result = backtest(strategy, data)
visualize(result) # Default view
visualize(result, :drawdown) # Specific view
visualize(result, [:equity, :drawdown]) # Multiple linked viewsQuantNova.Visualization.available_views Function
available_views(data)Return the list of available visualization views for the given data type.
sourceQuantNova.Visualization.set_theme! Function
set_theme!(theme::Symbol)Set the global visualization theme. Options: :light, :dark.
QuantNova.Visualization.LIGHT_THEME Constant
LIGHT_THEMEDefault light theme configuration for visualizations.
sourceQuantNova.Visualization.DARK_THEME Constant
DARK_THEMEDefault dark theme configuration for visualizations.
sourceQuantNova.Visualization.COLORS Constant
COLORSSemantic color palette used across visualizations.
sourceQuantNova.Visualization.render Function
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
using QuantNova
using CairoMakie # or GLMakie, WGLMakie
result = backtest(strategy, data)
spec = visualize(result, :equity)
fig = render(spec)QuantNova.Visualization.Dashboard Type
DashboardA multi-panel dashboard layout.
Example
dashboard = Dashboard(
title = "Strategy Monitor",
theme = :dark,
layout = [
Row(visualize(result, :equity), weight=2),
Row(visualize(result, :drawdown), visualize(result, :returns)),
]
)
serve(dashboard)QuantNova.Visualization.serve Function
serve(item; port=8080)Serve a visualization or dashboard in the browser. Requires WGLMakie and Bonito to be loaded.
sourceMissing docstring.
Missing docstring for save. Check Documenter's build log for details.
Statistics
QuantNova.Statistics.sharpe_ratio Function
sharpe_ratio(returns; rf=0.0, periods_per_year=252) -> Float64Compute annualized Sharpe ratio.
sourceQuantNova.Statistics.sharpe_std_error Function
sharpe_std_error(returns, sharpe; periods_per_year=252) -> Float64Standard error of Sharpe ratio estimate. Lo (2002) formula. SE(SR) ≈ sqrt((1 + 0.5*SR²) / n)
sourceQuantNova.Statistics.sharpe_confidence_interval Function
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)
sourceQuantNova.Statistics.sharpe_t_stat Function
sharpe_t_stat(returns; rf=0.0, benchmark_sharpe=0.0) -> Float64T-statistic for Sharpe ratio vs benchmark (default: testing if SR > 0).
sourceQuantNova.Statistics.sharpe_pvalue Function
sharpe_pvalue(returns; rf=0.0, benchmark_sharpe=0.0, alternative=:greater) -> Float64P-value for Sharpe ratio hypothesis test.
:greater - test if SR > benchmark (one-tailed)
:two_sided - test if SR ≠ benchmark
QuantNova.Statistics.probabilistic_sharpe_ratio Function
probabilistic_sharpe_ratio(returns, benchmark_sharpe; rf=0.0) -> Float64Probability that true Sharpe exceeds benchmark, accounting for skewness/kurtosis. Bailey & López de Prado (2012).
sourceQuantNova.Statistics.deflated_sharpe_ratio Function
deflated_sharpe_ratio(returns, n_trials; rf=0.0, expected_max_sr=nothing) -> Float64Deflated 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.
QuantNova.Statistics.compare_sharpe_ratios Function
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)
sourceQuantNova.Statistics.minimum_backtest_length Function
minimum_backtest_length(sharpe_target, n_trials; confidence=0.95) -> IntMinimum 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.
sourceQuantNova.Statistics.probability_of_backtest_overfitting Function
probability_of_backtest_overfitting(in_sample_sr, out_sample_sr, n_trials) -> Float64Estimate probability that backtest is overfit. High if in-sample >> out-sample and many trials.
sourceQuantNova.Statistics.combinatorial_purged_cv_pbo Function
combinatorial_purged_cv_pbo(returns, n_paths; train_frac=0.5) -> Float64Probability of Backtest Overfitting via Combinatorial Purged Cross-Validation. Bailey et al. (2017). Simplified implementation.
Returns probability that strategy is overfit.
sourceQuantNova.Statistics.information_coefficient Function
information_coefficient(predictions, outcomes) -> Float64Correlation between predictions and outcomes. Key alpha metric.
sourceQuantNova.Statistics.hit_rate Function
hit_rate(predictions, outcomes) -> Float64Fraction of correct directional predictions.
sourceQuantNova.Statistics.hit_rate_significance Function
hit_rate_significance(hit_rate, n_predictions; benchmark=0.5) -> (z_stat, pvalue)Test if hit rate is significantly above benchmark (default 50%).
source