39 toolsTool reference

Every entry below is rendered from the registry this server serves, so a renamed argument changes this page on the next build. The descriptions are the ones a client receives in tools/list.

Read the conventions first if you are about to call one of these.

Options

Pricing, Greeks and the checks worth running before either. Generalised Black-Scholes-Merton, so one parameterisation covers shares, futures and currencies by the cost of carry you pass.

price_european_option

European option price

Price a European option under the generalised Black-Scholes-Merton model, and report the forward, the discounted intrinsic value and the time value alongside it. Volatility and rates are decimal fractions and time is a year fraction.

ArgumentTypeMeaning
raterequirednumberContinuously compounded risk-free rate, annualised, as a decimal fraction: 4.5% is 0.045.
spotrequirednumberPrice of the underlying now. Must be positive.
strikerequirednumberExercise price of the option. Must be positive.
timerequirednumberYear fraction remaining to expiry, not a count of days. Thirty days is roughly 0.082; one year is 1.0.
typerequiredcall | putWhich side of the strike the holder receives.
volrequirednumberAnnualised lognormal volatility, as a decimal fraction: 20% is 0.2, not 20.
carrynumberCost of carry, annualised, as a decimal fraction. Defaults to the rate, which is the non-dividend-paying share case. Use rate minus the dividend yield for a paying share, and zero for a future.

european_option_greeks

European option Greeks

Analytic sensitivities of a European option: delta, gamma, vega, theta and rho, together with the second- and third-order Greeks (vanna, volga, charm, speed, zomma, colour, veta) and the sensitivities to strike and carry. Vega is per 1.00 of volatility and theta is per year.

ArgumentTypeMeaning
raterequirednumberContinuously compounded risk-free rate, annualised, as a decimal fraction: 4.5% is 0.045.
spotrequirednumberPrice of the underlying now. Must be positive.
strikerequirednumberExercise price of the option. Must be positive.
timerequirednumberYear fraction remaining to expiry, not a count of days. Thirty days is roughly 0.082; one year is 1.0.
typerequiredcall | putWhich side of the strike the holder receives.
volrequirednumberAnnualised lognormal volatility, as a decimal fraction: 20% is 0.2, not 20.
carrynumberCost of carry, annualised, as a decimal fraction. Defaults to the rate, which is the non-dividend-paying share case. Use rate minus the dividend yield for a paying share, and zero for a future.

european_option_analytics

European option price and Greeks

Price and the full Greek set in one call, for when both are wanted and a second round trip is not.

ArgumentTypeMeaning
raterequirednumberContinuously compounded risk-free rate, annualised, as a decimal fraction: 4.5% is 0.045.
spotrequirednumberPrice of the underlying now. Must be positive.
strikerequirednumberExercise price of the option. Must be positive.
timerequirednumberYear fraction remaining to expiry, not a count of days. Thirty days is roughly 0.082; one year is 1.0.
typerequiredcall | putWhich side of the strike the holder receives.
volrequirednumberAnnualised lognormal volatility, as a decimal fraction: 20% is 0.2, not 20.
carrynumberCost of carry, annualised, as a decimal fraction. Defaults to the rate, which is the non-dividend-paying share case. Use rate minus the dividend yield for a paying share, and zero for a future.

put_call_parity

Put-call parity check

Price both sides of a strike and report the put-call parity residual. The residual is zero for a consistent pair, so a non-zero value is a direct read on accumulated rounding error.

ArgumentTypeMeaning
raterequirednumberContinuously compounded risk-free rate, annualised, as a decimal fraction: 4.5% is 0.045.
spotrequirednumberPrice of the underlying now. Must be positive.
strikerequirednumberExercise price of the option. Must be positive.
timerequirednumberYear fraction remaining to expiry, not a count of days. Thirty days is roughly 0.082; one year is 1.0.
volrequirednumberAnnualised lognormal volatility, as a decimal fraction: 20% is 0.2, not 20.
carrynumberCost of carry, annualised, as a decimal fraction. Defaults to the rate, which is the non-dividend-paying share case. Use rate minus the dividend yield for a paying share, and zero for a future.

option_price_bounds

Attainable price range

The range of prices attainable by some non-negative volatility, and whether an observed price falls inside it. A price outside the range has no implied volatility, so this is worth checking before asking for one.

ArgumentTypeMeaning
pricerequirednumberObserved market price of the option.
raterequirednumberContinuously compounded risk-free rate, annualised, as a decimal fraction: 4.5% is 0.045.
spotrequirednumberPrice of the underlying now. Must be positive.
strikerequirednumberExercise price of the option. Must be positive.
timerequirednumberYear fraction remaining to expiry, not a count of days. Thirty days is roughly 0.082; one year is 1.0.
typerequiredcall | putWhich side of the strike the holder receives.
carrynumberCost of carry, annualised, as a decimal fraction. Defaults to the rate, which is the non-dividend-paying share case. Use rate minus the dividend yield for a paying share, and zero for a future.

Volatility

Recovering a volatility from a price, and fitting a surface to a set of them with both no-arbitrage conditions reported rather than assumed.

implied_volatility

Implied volatility

Recover the Black-Scholes volatility implied by an observed option price, with the evidence that the answer is right: how many iterations it took, which method produced it, and the price residual at the recovered volatility. A price outside the attainable range is refused with the range, since no volatility reproduces it.

ArgumentTypeMeaning
pricerequirednumberObserved market price of the option.
raterequirednumberContinuously compounded risk-free rate, annualised, as a decimal fraction: 4.5% is 0.045.
spotrequirednumberPrice of the underlying now. Must be positive.
strikerequirednumberExercise price of the option. Must be positive.
timerequirednumberYear fraction remaining to expiry, not a count of days. Thirty days is roughly 0.082; one year is 1.0.
typerequiredcall | putWhich side of the strike the holder receives.
carrynumberCost of carry, annualised, as a decimal fraction. Defaults to the rate, which is the non-dividend-paying share case. Use rate minus the dividend yield for a paying share, and zero for a future.

fit_volatility_slice

Fit a volatility smile

Fit a raw SVI slice to quoted volatilities at one maturity. Returns the five parameters, the fit residuals, the asymptotic wing slopes against Lee's bound, and whether the fitted slice implies a non-negative probability density. Log-moneyness is measured on the forward as log(strike / forward).

ArgumentTypeMeaning
forwardrequirednumberForward price at this maturity, which log-moneyness is measured on.
quotesrequiredobject[]At least five strikes, since a raw SVI slice has five parameters.
timerequirednumberYear fraction to this maturity.

fit_volatility_surface

Fit a volatility surface

Fit a volatility surface through quoted slices at several maturities. Returns the SVI parameters for each slice rather than a grid of numbers, since the parameters are exact and a grid is easy to misread, plus both no-arbitrage checks: butterfly, which is whether the implied density stays non-negative, and calendar, which is whether two maturities cross. Both are scanned between the quoted maturities as well as at them, because interpolation is where a condition quietly stops holding. Ask for strikeRatios to also receive a labelled grid of volatilities.

ArgumentTypeMeaning
slicesrequiredobject[]
strikeRatiosnumber[]Strikes to report, as multiples of the forward: 1.0 is at the money, 0.9 is ten percent below it.

local_volatility

Dupire local volatility

Extract Dupire local volatilities from a fitted surface at chosen strikes and maturities. Points where the identity has no answer are returned marked inadmissible, with the two quantities that failed, rather than as a number that would read as a real volatility.

ArgumentTypeMeaning
maturitiesrequirednumber[]Year fractions at which to evaluate the local volatility.
slicesrequiredobject[]
strikeRatiosrequirednumber[]Strikes to report, as multiples of the forward: 1.0 is at the money, 0.9 is ten percent below it.

American exercise

Two methods and the boundary between exercising and holding. The method is named in every result, because a lattice price and a closed-form approximation are not the same claim.

price_american_lattice

American option price on a lattice

Price an American option on a binomial or trinomial lattice. Returns the price with the method and resolution that produced it, the European price, and the early-exercise premium between them. Set convergence to also price at a doubling ladder of resolutions and see how much the answer is still moving — an American price is the output of a numerical method, and how converged it is cannot be read off the number.

ArgumentTypeMeaning
raterequirednumberContinuously compounded risk-free rate, annualised, as a decimal fraction: 4.5% is 0.045.
spotrequirednumberPrice of the underlying now. Must be positive.
strikerequirednumberExercise price of the option. Must be positive.
timerequirednumberYear fraction remaining to expiry, not a count of days. Thirty days is roughly 0.082; one year is 1.0.
typerequiredcall | putWhich side of the strike the holder receives.
volrequirednumberAnnualised lognormal volatility, as a decimal fraction: 20% is 0.2, not 20.
carrynumberCost of carry, annualised, as a decimal fraction. Defaults to the rate, which is the non-dividend-paying share case. Use rate minus the dividend yield for a paying share, and zero for a future.
convergencebooleanAlso report prices at 64 to 1024 layers and the error estimate.
latticecrr | jarrow-rudd | trinomialWhich discretisation to build. Cox-Ross-Rubinstein by default; the trinomial tree converges more smoothly at a higher cost per layer.
stepsintegerLayers in the lattice. More is closer to the limit and costs quadratically more. 512 by default.

price_american_closed_form

American option price, closed form

Price an American option by the Bjerksund-Stensland 2002 approximation: fast, close, and explicitly not the limit of a refinement. Reports the trigger price it exercises at and the 1993 formula beside it. Use price_american_lattice when the error matters.

ArgumentTypeMeaning
raterequirednumberContinuously compounded risk-free rate, annualised, as a decimal fraction: 4.5% is 0.045.
spotrequirednumberPrice of the underlying now. Must be positive.
strikerequirednumberExercise price of the option. Must be positive.
timerequirednumberYear fraction remaining to expiry, not a count of days. Thirty days is roughly 0.082; one year is 1.0.
typerequiredcall | putWhich side of the strike the holder receives.
volrequirednumberAnnualised lognormal volatility, as a decimal fraction: 20% is 0.2, not 20.
carrynumberCost of carry, annualised, as a decimal fraction. Defaults to the rate, which is the non-dividend-paying share case. Use rate minus the dividend yield for a paying share, and zero for a future.

american_exercise_boundary

Early-exercise boundary

The early-exercise boundary of an American option, read off the lattice as it unwinds: the spot at which exercising now is worth at least as much as holding on, at each time to expiry. This is what makes an American option different from a European one, and it is often more useful than the price.

ArgumentTypeMeaning
raterequirednumberContinuously compounded risk-free rate, annualised, as a decimal fraction: 4.5% is 0.045.
spotrequirednumberPrice of the underlying now. Must be positive.
strikerequirednumberExercise price of the option. Must be positive.
timerequirednumberYear fraction remaining to expiry, not a count of days. Thirty days is roughly 0.082; one year is 1.0.
typerequiredcall | putWhich side of the strike the holder receives.
volrequirednumberAnnualised lognormal volatility, as a decimal fraction: 20% is 0.2, not 20.
carrynumberCost of carry, annualised, as a decimal fraction. Defaults to the rate, which is the non-dividend-paying share case. Use rate minus the dividend yield for a paying share, and zero for a future.
latticecrr | jarrow-rudd | trinomialWhich discretisation to build. Cox-Ross-Rubinstein by default; the trinomial tree converges more smoothly at a higher cost per layer.
pointsintegerHow many points to report. The series is thinned to this.
stepsintegerLayers in the lattice. More is closer to the limit and costs quadratically more. 512 by default.

Position books

More than one position at once, carried by a handle so the book is sent once and asked several questions.

open_position_book

Open a position book

Assemble option and underlying positions over one underlying into a book, and return a handle for asking further questions of it. The handle carries the book itself rather than pointing at stored state, so it works across processes and expires on its own; pass it back unchanged. Volatilities and rates are decimal fractions and time is a year fraction.

ArgumentTypeMeaning
legsrequiredobject[]The positions in the book, at most 64 of them.
raterequirednumberContinuously compounded risk-free rate, annualised, as a decimal fraction: 4.5% is 0.045.
spotrequirednumberPrice of the underlying now. Must be positive.
labelstringYour name for the book, echoed back.

describe_position_book

Read a position book back

Return the positions a handle carries, with the book's total value. Use this to confirm a handle is still live and holds what you think it holds before acting on a number derived from it.

ArgumentTypeMeaning
handlerequiredstringThe handle returned by open_position_book. It carries the book itself rather than pointing at stored state, so pass it back unchanged. It expires; if it does, open the book again.

amend_position_book

Amend a position book

Add legs, remove legs by index, or move the spot and rate under an existing book, returning a new handle. The original handle keeps working until it expires, because the server holds no record of it and so cannot revoke it.

ArgumentTypeMeaning
handlerequiredstringThe handle returned by open_position_book. It carries the book itself rather than pointing at stored state, so pass it back unchanged. It expires; if it does, open the book again.
addLegsobject[]
ratenumberContinuously compounded risk-free rate, annualised, as a decimal fraction: 4.5% is 0.045.
removeLegsinteger[]Indices of legs to drop, as reported by describe_position_book. Applied before addLegs.
spotnumberPrice of the underlying now. Must be positive.

position_book_greeks

Aggregate risk of a position book

Total value and net sensitivities across a book, with the per-leg breakdown they were summed from. Legs with no defined derivative — expired, or carrying no volatility — are priced into the value but left out of the aggregate and named explicitly, so a book is never reported as flat when part of it simply has no delta.

ArgumentTypeMeaning
handlerequiredstringThe handle returned by open_position_book. It carries the book itself rather than pointing at stored state, so pass it back unchanged. It expires; if it does, open the book again.

position_book_scenarios

Scenario grid over spot and volatility

Reprice a book across a grid of relative spot moves and absolute volatility shifts, reporting value, profit and loss against the current market, and net delta and gamma in each cell. Rows are labelled with their volatility shift and cells with their spot, so the two axes cannot be read for one another.

ArgumentTypeMeaning
handlerequiredstringThe handle returned by open_position_book. It carries the book itself rather than pointing at stored state, so pass it back unchanged. It expires; if it does, open the book again.
spotShiftsnumber[]Relative moves in the underlying, as decimal fractions: -0.1 is a ten percent fall. Defaults to ±10% and ±5%.
volShiftsnumber[]Volatility points added to every option leg, floored at zero: 0.05 is five volatility points. Defaults to ±5.

Portfolio risk

Covariance, tail risk, where the risk sits, what the path did, and whether the forecast was any good once the period has passed. Estimate once and reuse the estimate; the tools that read the return path say so rather than guessing.

estimate_return_moments

Estimate a covariance matrix from returns

Estimate the mean vector and covariance matrix of a returns matrix, report the per-asset volatilities, the correlation matrix and the conditioning diagnostics, and return a handle so the estimate can be reused without resending the returns. Shrinkage is the default and the intensity it chose is reported, because an intensity near one is the estimator saying the sample carries little information about the pairwise structure — which is worth knowing before acting on the matrix. Returns are decimal fractions: a 1% gain is 0.01.

ArgumentTypeMeaning
periodsPerYearrequirednumberPeriods in a year for the data's frequency: 252 for daily trading days, 52 weekly, 12 monthly. Used only to annualise, never to reinterpret the returns. There is no default because the usual 252 is wrong for every frequency but one, and annualising weekly data with it overstates volatility sevenfold.
returnsrequirednumber[][]Periodic returns as decimal fractions, one row per period and one column per asset, in the same column order as `assets`. A 1% gain is 0.01, not 1. Rows must all be the same length.
assetsstring[]Column names, in the order the columns appear in `returns`. Defaults to asset_1, asset_2 and so on. Names are carried through to every per-asset figure, so supplying them is what makes a contribution table readable.
conventionsimple | logWhether the returns are simple (P/P-1 - 1) or logarithmic (ln(P/P)). They differ by about half the variance and aggregate in opposite directions: log returns add across time, simple returns add across a portfolio. Defaults to simple.
estimatorsample | ledoit-wolfCovariance estimator, used only when returns are supplied inline. Defaults to ledoit-wolf, whose shrinkage intensity is estimated rather than tuned. Ignored when a handle is passed, since the estimate it carries was already made.

portfolio_tail_risk

Value at risk and expected shortfall

Value at risk and expected shortfall for a weighted portfolio, by one of six methods, with the method named in the result because the number does not identify it. 'normal' and 'student-t' need only the first two moments and run from a handle. 'cornish-fisher' corrects the normal quantile using the portfolio's own skewness and excess kurtosis, and is refused rather than approximated when those moments put the correction outside the region where it is a quantile function at all. 'historical' takes the tail from the sample; 'filtered-historical' does the same after standardising by an exponentially weighted volatility and rescaling to today's. 'extreme-value' fits a generalised Pareto to the exceedances over a high threshold and extrapolates past the largest observation, which is the only method here that can answer above about 99.5% on a few years of daily data — the others are reading two observations or a shape fitted to the body. 'copula' is the only one that does not tie the joint distribution to a covariance matrix: it fits the dependence to the ranks and each marginal separately, then simulates. Reach for it when the question is what the portfolio loses if its assets fall together, because under a normal that probability is asymptotically zero at any correlation below one and under a multivariate t it is one number for every pair. It reports the Gaussian-copula figure beside its own, so the difference is the assumption rather than an argument — and that difference is largest for a book that looks *diversified*, not one already correlated, because near a correlation of one both copulas move everything together anyway. The last five read the return path, so they need the returns matrix rather than a handle. Losses are positive: a value at risk of 0.023 is a 2.3% loss.

ArgumentTypeMeaning
assetsstring[]Column names, in the order the columns appear in `returns`. Defaults to asset_1, asset_2 and so on. Names are carried through to every per-asset figure, so supplying them is what makes a contribution table readable.
confidencenumberConfidence level: 0.99 means the 1% tail. The complement convention is the common mistake, and it is wrong by an amount that grows as the tail thins, so the result states the tail probability as well.
conventionsimple | logWhether the returns are simple (P/P-1 - 1) or logarithmic (ln(P/P)). They differ by about half the variance and aggregate in opposite directions: log returns add across time, simple returns add across a portfolio. Defaults to simple.
copulaDegreesnumberFix the copula degrees of freedom instead of fitting them. Two reasons to: a stress scenario asks what a heavier joint tail would cost rather than what the sample supports, and the profile likelihood is most of this method's runtime — about twelve seconds on 1,200 observations against under one for the simulation.
copulaFamilygaussian | student-tWhich copula, for 'copula'. Defaults to student-t, whose extra parameter is what lets assets arrive in their tails together; gaussian is the reference it is measured against and has no tail dependence at any correlation below one.
copulaMarginalempirical | extreme-valueWhere each asset's own distribution comes from, for 'copula'. Defaults to empirical, under which no single asset's draw can exceed its worst observation, so all the extrapolation is in the dependence; extreme-value splices a fitted generalised Pareto onto each loss tail and puts it back.
decaynumberExponential weight on yesterday's variance, for 'filtered-historical'. Defaults to 0.94, the RiskMetrics figure for daily data.
degreesnumberDegrees of freedom for 'student-t'. Above two, because the variance of a t is v/(v-2) and does not exist at or below it. Defaults to 5. The distribution is scaled so its variance is the estimated one.
estimatorsample | ledoit-wolfCovariance estimator, used only when returns are supplied inline. Defaults to ledoit-wolf, whose shrinkage intensity is estimated rather than tuned. Ignored when a handle is passed, since the estimate it carries was already made.
handlestringA handle from estimate_return_moments, in place of `returns`. It carries the mean vector and the covariance matrix rather than the returns themselves, so it serves the parametric methods and cannot serve the ones that read the return path. It expires; estimate again if it does.
methodnormal | student-t | cornish-fisher | historical | filtered-historical | extreme-value | copulaWhich estimator. Defaults to 'normal', which understates the tail of essentially every real return series — it is the default because it is the reference, not because it is the right answer.
pathsintegerSimulated paths, for 'copula'. Defaults to 20,000, which costs well under a second; standardError says whether it was enough.
periodsPerYearnumberPeriods in a year for the data's frequency: 252 for daily trading days, 52 weekly, 12 monthly. Used only to annualise, never to reinterpret the returns. There is no default because the usual 252 is wrong for every frequency but one, and annualising weekly data with it overstates volatility sevenfold.
quantileMethodlower | higher | linear | weibullHow a sample quantile is interpolated, for the historical methods. Defaults to linear. It matters far out in a tail, where the neighbouring order statistics are far apart.
returnsnumber[][]Periodic returns as decimal fractions, one row per period and one column per asset, in the same column order as `assets`. A 1% gain is 0.01, not 1. Rows must all be the same length.
seedintegerSeed for the 'copula' simulation, so two identical calls agree. Defaults to 0 rather than to randomness, because a tool annotated idempotent that is not is worse than one that admits it.
tailFractionnumberFraction of the sample to fit above, for 'extreme-value'. Defaults to 0.05. Raising it trades the shape's bias for its variance; below about 10 exceedances the fit is refused. The mean excess curve in the result is how to choose it.
tailMethodmaximum_likelihood | probability_weighted_momentsHow the two tail parameters are estimated, for 'extreme-value'. Maximum likelihood is the default and the only one with a standard error; the moment estimator is steadier on a few dozen exceedances and cannot report a shape at or above one at all.
weightsnumber[]Portfolio weights, one per asset, in the same order as the columns. They are not normalised: the sum is reported back, and a sum more than 2% away from one is refused, because weights summing to 0.98 are either a cash position or a typo and the two want opposite treatment. Negative weights are short positions.

portfolio_risk_contributions

Where a portfolio's risk comes from

Decompose portfolio risk across its positions: each asset's marginal risk, its Euler component, and its share. The components sum to the total exactly, so a share is a share of something rather than a normalised guess, and a position that hedges shows a negative contribution rather than a small positive one. Also reports concentration, effective bets — how many independent positions the portfolio carries risk like — and the diversification ratio. Works from a handle or from a returns matrix.

ArgumentTypeMeaning
assetsstring[]Column names, in the order the columns appear in `returns`. Defaults to asset_1, asset_2 and so on. Names are carried through to every per-asset figure, so supplying them is what makes a contribution table readable.
confidencenumberConfidence level: 0.99 means the 1% tail. The complement convention is the common mistake, and it is wrong by an amount that grows as the tail thins, so the result states the tail probability as well.
conventionsimple | logWhether the returns are simple (P/P-1 - 1) or logarithmic (ln(P/P)). They differ by about half the variance and aggregate in opposite directions: log returns add across time, simple returns add across a portfolio. Defaults to simple.
estimatorsample | ledoit-wolfCovariance estimator, used only when returns are supplied inline. Defaults to ledoit-wolf, whose shrinkage intensity is estimated rather than tuned. Ignored when a handle is passed, since the estimate it carries was already made.
handlestringA handle from estimate_return_moments, in place of `returns`. It carries the mean vector and the covariance matrix rather than the returns themselves, so it serves the parametric methods and cannot serve the ones that read the return path. It expires; estimate again if it does.
measurevolatility | valueAtRisk | expectedShortfallWhich risk measure to decompose. Defaults to volatility, which needs no distributional assumption. The other two are decomposed under a normal assumption and report it.
periodsPerYearnumberPeriods in a year for the data's frequency: 252 for daily trading days, 52 weekly, 12 monthly. Used only to annualise, never to reinterpret the returns. There is no default because the usual 252 is wrong for every frequency but one, and annualising weekly data with it overstates volatility sevenfold.
returnsnumber[][]Periodic returns as decimal fractions, one row per period and one column per asset, in the same column order as `assets`. A 1% gain is 0.01, not 1. Rows must all be the same length.
weightsnumber[]Portfolio weights, one per asset, in the same order as the columns. They are not normalised: the sum is reported back, and a sum more than 2% away from one is refused, because weights summing to 0.98 are either a cash position or a typo and the two want opposite treatment. Negative weights are short positions.

risk_parity_weights

Weights that equalise risk contributions

Solve for long-only weights whose risk contributions match a budget, equal by default. Reports whether the solver converged, how far the achieved risk shares are from the targets, and the resulting contribution table — as evidence rather than as a promise, because a near-singular covariance matrix may not admit an exact solution. Works from a handle or from a returns matrix.

ArgumentTypeMeaning
assetsstring[]Column names, in the order the columns appear in `returns`. Defaults to asset_1, asset_2 and so on. Names are carried through to every per-asset figure, so supplying them is what makes a contribution table readable.
budgetsnumber[]Target risk share per asset, positional, normalised to sum to one. Defaults to equal shares. Strictly positive: an asset with a zero risk budget is one to leave out.
conventionsimple | logWhether the returns are simple (P/P-1 - 1) or logarithmic (ln(P/P)). They differ by about half the variance and aggregate in opposite directions: log returns add across time, simple returns add across a portfolio. Defaults to simple.
estimatorsample | ledoit-wolfCovariance estimator, used only when returns are supplied inline. Defaults to ledoit-wolf, whose shrinkage intensity is estimated rather than tuned. Ignored when a handle is passed, since the estimate it carries was already made.
handlestringA handle from estimate_return_moments, in place of `returns`. It carries the mean vector and the covariance matrix rather than the returns themselves, so it serves the parametric methods and cannot serve the ones that read the return path. It expires; estimate again if it does.
periodsPerYearnumberPeriods in a year for the data's frequency: 252 for daily trading days, 52 weekly, 12 monthly. Used only to annualise, never to reinterpret the returns. There is no default because the usual 252 is wrong for every frequency but one, and annualising weekly data with it overstates volatility sevenfold.
returnsnumber[][]Periodic returns as decimal fractions, one row per period and one column per asset, in the same column order as `assets`. A 1% gain is 0.01, not 1. Rows must all be the same length.

portfolio_drawdown

Drawdown and path statistics

What the portfolio's path did, which no covariance can see: the deepest drawdown with the periods it ran between, the longest time underwater, the ulcer index over the whole underwater path rather than its two extreme points, and the Calmar and Sortino ratios with their denominators stated. Depths are fractions of the peak and the recovery gain is reported alongside — a 50% fall needs a 100% gain, and that asymmetry is the part that gets misread. Needs the returns matrix: a handle carries second moments, and the path is not recoverable from them.

ArgumentTypeMeaning
periodsPerYearrequirednumberPeriods in a year for the data's frequency: 252 for daily trading days, 52 weekly, 12 monthly. Used only to annualise, never to reinterpret the returns. There is no default because the usual 252 is wrong for every frequency but one, and annualising weekly data with it overstates volatility sevenfold.
returnsrequirednumber[][]Periodic returns as decimal fractions, one row per period and one column per asset, in the same column order as `assets`. A 1% gain is 0.01, not 1. Rows must all be the same length.
assetsstring[]Column names, in the order the columns appear in `returns`. Defaults to asset_1, asset_2 and so on. Names are carried through to every per-asset figure, so supplying them is what makes a contribution table readable.
conventionsimple | logWhether the returns are simple (P/P-1 - 1) or logarithmic (ln(P/P)). They differ by about half the variance and aggregate in opposite directions: log returns add across time, simple returns add across a portfolio. Defaults to simple.
indexstring[]Labels for the points on the wealth curve — dates, usually. One MORE than there are rows of `returns`: n returns move a portfolio between n + 1 valuations, and the first label is the starting value before any return is applied. Used only to say when a drawdown began, bottomed and recovered. Without them the report uses curve positions, on the same 0-to-n numbering.
minimumDepthnumberIgnore drawdowns shallower than this when counting and listing episodes, as a fraction: 0.05 keeps falls of five percent or more. Defaults to 0, which counts every dip.
weightsnumber[]Portfolio weights, one per asset, in the same order as the columns. They are not normalised: the sum is reported back, and a sum more than 2% away from one is refused, because weights summing to 0.98 are either a cash position or a typo and the two want opposite treatment. Negative weights are short positions.
worstCountintegerHow many of the deepest episodes to list. Defaults to 5.

validate_risk_model

Score a value-at-risk forecast against what happened

Whether a risk model worked. Takes a series of realised returns and the one-step-ahead forecasts that were made for them, and runs Kupiec's unconditional coverage test on the breach count, Christoffersen's test on whether the breaches cluster, the joint conditional coverage test, and the supervisory traffic-light zone. The clustering test is the one a count cannot replace: a constant-volatility model can breach exactly the right number of times over a year and put every breach in the same fortnight. Supply expected-shortfall forecasts as well and it adds the Acerbi-Szekely statistics, which are the only way to score a tail mean because expected shortfall is not elicitable and has no breach-count equivalent. Forecasts are positive losses, the sign convention every other risk tool here returns.

ArgumentTypeMeaning
confidencerequirednumberConfidence level: 0.99 means the 1% tail. The complement convention is the common mistake, and it is wrong by an amount that grows as the tail thins, so the result states the tail probability as well.
returnsrequirednumber[]Realised returns, signed, one per period in order. A loss is negative.
valueAtRiskrequirednumber[]The forecast made FOR each return, as a POSITIVE loss: 0.023 is a forecast 2.3% loss. One per return and not offset — element i is the forecast that was made before return i was observed. Getting this alignment wrong is the easiest way to make a broken model look fine.
degreesnumberDegrees of freedom for a student-t null, standardised to unit variance so it is comparable with the forecasts. Above two, because the variance to standardise by is infinite at or below it. Defaults to 5.
distributionnormal | student-tThe predictive distribution the forecasts were built under, which is what the simulated null draws from. Only used when `replications` is above zero. Defaults to normal.
expectedShortfallnumber[]Forecast tail means, positive losses, aligned the same way. Each must be at least its own value at risk, since a tail mean averages losses no smaller than the quantile. Omit to skip the expected-shortfall statistics.
replicationsintegerSimulate the expected-shortfall null this many times to attach p-values to those two statistics. Needs `expectedShortfall`. Zero, the default, reports the statistics without p-values. The coverage tests have closed-form p-values and are unaffected.
seedintegerSeed for the simulation, so a reported p-value can be reproduced. Defaults to 0.

conditional_volatility

Fit a volatility process and forecast from it

A GARCH(1,1) fitted by maximum likelihood over a return series, which is what to reach for when validate_risk_model rejects on independence: clustered breaches mean the model has no notion of volatility changing, and no rescaling fixes that. Returns the parameters, the persistence, the half-life of a shock, and a one-step-ahead volatility for every period — already aligned, so it goes straight to validate_risk_model as a forecast series without the caller offsetting anything. Also reports the horizon volatility against what square-root-of-time would give, which differs by tens of percent over a year and in both directions. The innovation tail is estimated rather than assumed normal, and the multiplier to turn the forecast series into a value at risk comes back with it — the standardised quantile, which is not the raw one.

ArgumentTypeMeaning
returnsrequirednumber[]One return per period, in order, oldest first. At least 100: below that the likelihood is nearly flat along the persistence direction and the fit reports whatever it started near.
confidencenumberConfidence for the conditional value at risk, expected shortfall and quantile multiplier. Defaults to 0.99.
drawbootstrap | parametricWhere the simulated innovations come from. 'bootstrap' resamples the model's own standardised residuals and assumes no tail shape; 'parametric' draws from the fitted distribution. Defaults to bootstrap, which needs at least 250 observations.
horizonintegerPeriods to aggregate the variance over, for the horizon figure and its comparison with square-root-of-time. Defaults to 10.
includeForecastsbooleanReturn the per-period volatility series. Defaults to true. Set false for the parameters alone, which is what a long history needs since the series is one number per observation.
innovationauto | normal | student-tShape assumed for the standardised residuals. 'auto' tests for a fat tail by likelihood ratio and fits one only if the data shows one; that verdict comes back in `fatTail`. Defaults to auto. The variance process says how the scale moves and says nothing about the shape drawn at that scale, which is why this is a separate choice.
pathsintegerSimulate the risk over `horizon` periods from this many paths, returning `horizonRisk`. Omit for none: the work is paths times horizon. This is the only honest route to a multi-period quantile, because the sum of the horizon's innovations is not a member of the family they were drawn from.
seedintegerSeed for the simulation, so two identical calls agree. Defaults to 0 rather than to randomness, because a tool annotated idempotent that is not is worse than one that admits it.
varianceTargetingbooleanFix the long-run variance to the sample variance and estimate only the two dynamic parameters. More robust on a short sample, because omega is the product of the long-run level and one minus the persistence, and on a persistent series that second factor is small and badly determined. Defaults to false.

Curves and bonds

A discount curve from the instruments that trade, and the bond analytics that hang off it — pricing, risk, spreads, and what a position earns over a holding period. Every calibration reports whether it reprices what it was built from.

bootstrap_discount_curve

Bootstrap a discount curve

Build a discount curve from deposits, rate futures and par swaps, and return a handle so it can be reused without resending the quotes. Reports the pillars it solved, the zero rate at each, and — the check that matters — whether the curve reprices the instruments it was built from, because a curve that does not is not slightly wrong, it means nothing, and the pillar values look ordinary either way. Every day count basis is required, with no default anywhere: a curve on the wrong basis answers a different question and looks normal doing it.

ArgumentTypeMeaning
basisrequiredACT_360 | ACT_365F | ACT_ACT_ISDA | THIRTY_360_BOND | THIRTY_E_360 | THIRTY_360_USThe day count basis of the curve itself, which is what its year fractions are measured on. Independent of each instrument's own basis, which stays with the instrument. Day count basis. Required, with no default anywhere: a bond on the wrong basis is wrong by a few basis points, which is the size of the spread being measured, so the answer looks normal and is to a different question. ACT_360 for money-market deposits, ACT_365F or ACT_ACT_ISDA for curves, THIRTY_360_BOND for a US corporate coupon.
referencerequiredstringThe curve's reference date: where it starts and where every year fraction on it is measured from. Required when quotes are supplied.
compoundingSIMPLE | ANNUAL | SEMI_ANNUAL | QUARTERLY | MONTHLY | CONTINUOUSHow a zero rate is compounded. CONTINUOUS is the curve's own convention and the default for anything derived from it; the others are for quoting.
depositsobject[]Money-market deposits, one pillar each.
futuresobject[]Rate futures, one pillar each.
interpolationLOG_LINEAR_DISCOUNT | LINEAR_ZERO | MONOTONE_CONVEXHow the curve is interpolated between pillars. LOG_LINEAR_DISCOUNT is the default and gives piecewise-constant forwards. LINEAR_ZERO is smoother in zero rates and rougher in forwards. MONOTONE_CONVEX keeps forwards positive and continuous, which matters when the curve is read for forwards rather than for discount factors.
swapsobject[]Par interest rate swaps, one pillar each.

discount_curve_rates

Read discount factors and rates off a curve

Discount factors, zero rates, instantaneous forwards and the forward rate between consecutive dates, at whatever dates you ask for. Works from a curve handle or from a quote set. A date beyond the curve's horizon is refused rather than extrapolated: past the longest instrument there is nothing behind the number.

ArgumentTypeMeaning
datesrequiredstring[]The dates to read the curve at, in the order you want them. The order matters: each point's forward rate is measured from the date before it.
basisACT_360 | ACT_365F | ACT_ACT_ISDA | THIRTY_360_BOND | THIRTY_E_360 | THIRTY_360_USThe day count basis of the curve itself, which is what its year fractions are measured on. Independent of each instrument's own basis, which stays with the instrument. Day count basis. Required, with no default anywhere: a bond on the wrong basis is wrong by a few basis points, which is the size of the spread being measured, so the answer looks normal and is to a different question. ACT_360 for money-market deposits, ACT_365F or ACT_ACT_ISDA for curves, THIRTY_360_BOND for a US corporate coupon.
compoundingSIMPLE | ANNUAL | SEMI_ANNUAL | QUARTERLY | MONTHLY | CONTINUOUSHow a zero rate is compounded. CONTINUOUS is the curve's own convention and the default for anything derived from it; the others are for quoting.
depositsobject[]Money-market deposits, one pillar each.
forwardCompoundingSIMPLE | ANNUAL | SEMI_ANNUAL | QUARTERLY | MONTHLY | CONTINUOUSCompounding for the forward rates between dates. Defaults to SIMPLE, which is how a forward is normally quoted.
futuresobject[]Rate futures, one pillar each.
handlestringA handle from bootstrap_discount_curve, in place of the instruments. Unlike the returns handle used by the portfolio tools, this one carries the curve itself — a curve is its pillars, which is two numbers per instrument — so nothing is lost by reusing it and every curve tool accepts it. It expires; bootstrap again if it does.
interpolationLOG_LINEAR_DISCOUNT | LINEAR_ZERO | MONOTONE_CONVEXHow the curve is interpolated between pillars. LOG_LINEAR_DISCOUNT is the default and gives piecewise-constant forwards. LINEAR_ZERO is smoother in zero rates and rougher in forwards. MONOTONE_CONVEX keeps forwards positive and continuous, which matters when the curve is read for forwards rather than for discount factors.
referencestringThe curve's reference date: where it starts and where every year fraction on it is measured from. Required when quotes are supplied.
swapsobject[]Par interest rate swaps, one pillar each.

bond_analytics

Price, yield, duration and convexity of a bond

Bond analytics from a yield, from a curve, or from both. Given a price it solves the yield; given a yield it prices. With a curve it also prices every cashflow at its own rate and reports the effective duration and convexity from shifting the curve. Both sets are returned when both are available, labelled and with the difference between them, because a yield-based duration and a curve-based one are answers to different questions and neither is wrong. Prices are per 100 of face.

ArgumentTypeMeaning
bondrequiredobjectA fixed-coupon bond. Prices are per 100 of face throughout, so a bond trading at a 20% premium is 120.
basisACT_360 | ACT_365F | ACT_ACT_ISDA | THIRTY_360_BOND | THIRTY_E_360 | THIRTY_360_USThe day count basis of the curve itself, which is what its year fractions are measured on. Independent of each instrument's own basis, which stays with the instrument. Day count basis. Required, with no default anywhere: a bond on the wrong basis is wrong by a few basis points, which is the size of the spread being measured, so the answer looks normal and is to a different question. ACT_360 for money-market deposits, ACT_365F or ACT_ACT_ISDA for curves, THIRTY_360_BOND for a US corporate coupon.
depositsobject[]Money-market deposits, one pillar each.
futuresobject[]Rate futures, one pillar each.
handlestringA handle from bootstrap_discount_curve, in place of the instruments. Unlike the returns handle used by the portfolio tools, this one carries the curve itself — a curve is its pillars, which is two numbers per instrument — so nothing is lost by reusing it and every curve tool accepts it. It expires; bootstrap again if it does.
interpolationLOG_LINEAR_DISCOUNT | LINEAR_ZERO | MONOTONE_CONVEXHow the curve is interpolated between pillars. LOG_LINEAR_DISCOUNT is the default and gives piecewise-constant forwards. LINEAR_ZERO is smoother in zero rates and rougher in forwards. MONOTONE_CONVEX keeps forwards positive and continuous, which matters when the curve is read for forwards rather than for discount factors.
pricenumberClean price per 100 of face. The yield is solved from it. Send this or a yieldToMaturity, not both.
referencestringThe curve's reference date: where it starts and where every year fraction on it is measured from. Required when quotes are supplied.
settlementstringSettlement date for the valuation. Defaults to the curve's reference date. Accrued interest is measured from the last coupon to this date.
shiftnumberRate shift for the bumped-curve sensitivities, as a decimal fraction. Defaults to 0.0001, one basis point, which is what the '01' in dv01 means. A larger shift measures a secant rather than a tangent, which is sometimes what is wanted and is never the same number.
swapsobject[]Par interest rate swaps, one pillar each.
yieldToMaturitynumberYield as a decimal fraction: 3% is 0.03. The price is computed from it.

bond_curve_risk

Key rate durations and curve shape risk

Where a bond's interest rate risk sits along the curve: a key rate duration per bucket, from a triangular bump centred on it; the level, slope and curvature durations, which are a coordinate system on curve moves rather than three unrelated numbers; and — when the curve came from quotes — the profit and loss of each quoted instrument, which is the hedge rather than a description of the risk. The key rate durations sum to the effective duration, and the residual is reported so a table that does not add up cannot be mistaken for one that does.

ArgumentTypeMeaning
bondrequiredobjectA fixed-coupon bond. Prices are per 100 of face throughout, so a bond trading at a 20% premium is 120.
basisACT_360 | ACT_365F | ACT_ACT_ISDA | THIRTY_360_BOND | THIRTY_E_360 | THIRTY_360_USThe day count basis of the curve itself, which is what its year fractions are measured on. Independent of each instrument's own basis, which stays with the instrument. Day count basis. Required, with no default anywhere: a bond on the wrong basis is wrong by a few basis points, which is the size of the spread being measured, so the answer looks normal and is to a different question. ACT_360 for money-market deposits, ACT_365F or ACT_ACT_ISDA for curves, THIRTY_360_BOND for a US corporate coupon.
bucketsnumber[]Bucket maturities in years, increasing. Defaults to the standard 0.5, 1, 2, 5, 10 and 30 year points that fall inside the curve. More buckets than pillars adds no information: the durations between pillars are interpolations of the ones at them.
depositsobject[]Money-market deposits, one pillar each.
futuresobject[]Rate futures, one pillar each.
handlestringA handle from bootstrap_discount_curve, in place of the instruments. Unlike the returns handle used by the portfolio tools, this one carries the curve itself — a curve is its pillars, which is two numbers per instrument — so nothing is lost by reusing it and every curve tool accepts it. It expires; bootstrap again if it does.
interpolationLOG_LINEAR_DISCOUNT | LINEAR_ZERO | MONOTONE_CONVEXHow the curve is interpolated between pillars. LOG_LINEAR_DISCOUNT is the default and gives piecewise-constant forwards. LINEAR_ZERO is smoother in zero rates and rougher in forwards. MONOTONE_CONVEX keeps forwards positive and continuous, which matters when the curve is read for forwards rather than for discount factors.
referencestringThe curve's reference date: where it starts and where every year fraction on it is measured from. Required when quotes are supplied.
settlementstringSettlement date for the valuation. Defaults to the curve's reference date. Accrued interest is measured from the last coupon to this date.
shiftnumberRate shift for the bumped-curve sensitivities, as a decimal fraction. Defaults to 0.0001, one basis point, which is what the '01' in dv01 means. A larger shift measures a secant rather than a tangent, which is sometimes what is wanted and is never the same number.
swapsobject[]Par interest rate swaps, one pillar each.

bond_spreads

Z-spread, I-spread and option-adjusted spread

The spread a bond's price implies over a curve. The Z-spread is the parallel shift to every zero rate that reprices it; the I-spread is the gap to the curve's par rate at its maturity, and the two differ by the shape of the curve. Give a first exercise date and a volatility and it also calibrates a short-rate lattice to the curve, values the embedded option, and reports the option-adjusted spread and the option cost — with whether the lattice reprices the curve it was calibrated to, because a tree that does not is not a model of that curve and every spread read off it would be wrong.

ArgumentTypeMeaning
bondrequiredobjectA fixed-coupon bond. Prices are per 100 of face throughout, so a bond trading at a 20% premium is 120.
pricerequirednumberObserved price per 100 of face.
basisACT_360 | ACT_365F | ACT_ACT_ISDA | THIRTY_360_BOND | THIRTY_E_360 | THIRTY_360_USThe day count basis of the curve itself, which is what its year fractions are measured on. Independent of each instrument's own basis, which stays with the instrument. Day count basis. Required, with no default anywhere: a bond on the wrong basis is wrong by a few basis points, which is the size of the spread being measured, so the answer looks normal and is to a different question. ACT_360 for money-market deposits, ACT_365F or ACT_ACT_ISDA for curves, THIRTY_360_BOND for a US corporate coupon.
callPricenumberExercise price per 100 of face. Defaults to 100.
cleanbooleanWhether `price` is clean, that is excludes accrued interest. Defaults to true, which is how bonds are quoted.
depositsobject[]Money-market deposits, one pillar each.
firstCallstringFirst date the option may be exercised. Supplying it turns on the lattice and the option-adjusted spread; leaving it out reports the two curve spreads only.
futuresobject[]Rate futures, one pillar each.
handlestringA handle from bootstrap_discount_curve, in place of the instruments. Unlike the returns handle used by the portfolio tools, this one carries the curve itself — a curve is its pillars, which is two numbers per instrument — so nothing is lost by reusing it and every curve tool accepts it. It expires; bootstrap again if it does.
holderOptionbooleanTrue for a put held by the holder rather than a call held by the issuer. Defaults to false. The sign of the option cost follows from this, so it is not cosmetic.
interpolationLOG_LINEAR_DISCOUNT | LINEAR_ZERO | MONOTONE_CONVEXHow the curve is interpolated between pillars. LOG_LINEAR_DISCOUNT is the default and gives piecewise-constant forwards. LINEAR_ZERO is smoother in zero rates and rougher in forwards. MONOTONE_CONVEX keeps forwards positive and continuous, which matters when the curve is read for forwards rather than for discount factors.
referencestringThe curve's reference date: where it starts and where every year fraction on it is measured from. Required when quotes are supplied.
settlementstringSettlement date for the valuation. Defaults to the curve's reference date. Accrued interest is measured from the last coupon to this date.
swapsobject[]Par interest rate swaps, one pillar each.
volatilitynumberShort rate volatility for the lattice, as a decimal fraction. Required with firstCall.

bond_carry_rolldown

Holding-period return: carry and roll-down

What a bond position earns between settlement and a horizon if nothing happens — and the split that matters, because 'nothing happens' means two different things. If the curve evolves to its own forwards the bond earns its funding cost and nothing else; that is an identity, not an approximation, and the result asserts it. Everything above the funding cost is roll-down: the bond ages, its remaining maturity shortens, and on an unchanged spot curve it is repriced off a lower point. On a curve running from 20bp to 220bp a ten-year bond held for a year earns 279 basis points, of which 50 is financing and 249 is roll-down. Both market meanings of 'carry' are reported because the word is used for both, and the conventional one can rank two positions backwards.

ArgumentTypeMeaning
bondrequiredobjectA fixed-coupon bond. Prices are per 100 of face throughout, so a bond trading at a 20% premium is 120.
horizonrequiredstringEnd of the holding period. Must fall after settlement and strictly before the bond's maturity: a redeemed bond has no price at the horizon, so there is no price change to decompose and the call is refused rather than answered with zero.
basisACT_360 | ACT_365F | ACT_ACT_ISDA | THIRTY_360_BOND | THIRTY_E_360 | THIRTY_360_USThe day count basis of the curve itself, which is what its year fractions are measured on. Independent of each instrument's own basis, which stays with the instrument. Day count basis. Required, with no default anywhere: a bond on the wrong basis is wrong by a few basis points, which is the size of the spread being measured, so the answer looks normal and is to a different question. ACT_360 for money-market deposits, ACT_365F or ACT_ACT_ISDA for curves, THIRTY_360_BOND for a US corporate coupon.
depositsobject[]Money-market deposits, one pillar each.
futuresobject[]Rate futures, one pillar each.
handlestringA handle from bootstrap_discount_curve, in place of the instruments. Unlike the returns handle used by the portfolio tools, this one carries the curve itself — a curve is its pillars, which is two numbers per instrument — so nothing is lost by reusing it and every curve tool accepts it. It expires; bootstrap again if it does.
interpolationLOG_LINEAR_DISCOUNT | LINEAR_ZERO | MONOTONE_CONVEXHow the curve is interpolated between pillars. LOG_LINEAR_DISCOUNT is the default and gives piecewise-constant forwards. LINEAR_ZERO is smoother in zero rates and rougher in forwards. MONOTONE_CONVEX keeps forwards positive and continuous, which matters when the curve is read for forwards rather than for discount factors.
referencestringThe curve's reference date: where it starts and where every year fraction on it is measured from. Required when quotes are supplied.
settlementstringSettlement date for the valuation. Defaults to the curve's reference date. Accrued interest is measured from the last coupon to this date.
swapsobject[]Par interest rate swaps, one pillar each.

Execution

What a trade cost, and how the next one should be spread out. The total is the least useful number; the split into delay, trading and opportunity is the one with a remedy attached.

decompose_implementation_shortfall

Split an order's cost into delay, trading and opportunity

Decompose what an order actually cost against the price at the moment it was decided on. The total is the least useful number in the result: delay is the price moving before the order reached the market, trading is the order's own footprint, opportunity is the part that never got done, and commission and fees are explicit. Each has a different remedy, so each is reported in currency and in basis points of the paper notional. Fill timestamps are not needed — the decomposition reads only quantities, prices and commissions. Whether delay is charged on the ordered or the executed quantity is a convention with no safe default: it moves cost between delay and opportunity without changing the total, and the basis used is named in the result.

ArgumentTypeMeaning
arrivalPricerequirednumberPrice when the order reached the market. This is the boundary between the delay component and the trading one.
fillsrequiredobject[]The fills, in the order they happened. Timestamps are not needed: the decomposition reads only the quantities, prices and commissions, and gives the same answer whatever the spacing.
finalPricerequirednumberPrice at the end of the window. What the unfilled quantity is marked against.
quantityrequirednumberQuantity the order was for, unsigned. Anything the fills do not cover is the unfilled part, and is charged as opportunity cost against the final price.
siderequiredbuy | sellDirection of the order. This is not cosmetic: a price rise between the decision and the fill is a cost to a buyer and a gain to a seller, and every component below changes sign with it.
decisionPricenumberPrice when the decision was taken. Defaults to the arrival price, which sets the delay component to zero — that is a statement that the order reached the market instantly, not an absence of data.
delayBasisorder | executedCharge delay on the quantity ordered ('order', the default) or the quantity executed ('executed'). The two give the same total and split it differently.
feesnumberFees in currency beyond the per-fill commissions. An explicit cost, reported apart from the implicit ones.
halfSpreadnumberHalf the quoted spread, if known. Carried into the result as a reference to read the trading component against.
symbolstringLabel for the instrument. Carried through, not used in the arithmetic.

optimal_execution_schedule

Schedule an order against impact and price risk

The Almgren-Chriss trajectory for a linear impact model: how much to trade in each period, what it is expected to cost, and the variance around that. At zero risk aversion the answer is a straight line — an equal slice each period, which is TWAP — and raising the aversion front-loads the schedule, paying more impact to spend less time exposed. The half-life says how front-loaded, and its elasticities say which input would move it. Permanent impact and fixed costs mostly change the cost rather than the shape — a fixed cost exactly so, permanent impact to within a term that shrinks with the period length. Volatility is an absolute price move per unit of root time, not a percentage, because it is traded off against an impact quoted in price per share.

ArgumentTypeMeaning
problemrequiredobject
riskAversionrequirednumberAversion to the variance of the cost, in inverse currency. Zero is risk neutrality and gives a straight line — an equal slice each period, which is TWAP. Raising it front-loads the schedule, which pays more impact to spend less time exposed to the price moving.

execution_cost_frontier

The cost-risk trade-off across risk aversions

Expected cost against the standard deviation of that cost, one point per risk aversion, each with the schedule that achieves it. A single optimal schedule answers a question the caller has already had to answer — how much cost is a unit of certainty worth — and this shows the trade-off instead of assuming it. Cost falls and risk rises as the aversion goes down; the aversions must be given in increasing order so the frontier reads along it.

ArgumentTypeMeaning
problemrequiredobject
riskAversionsrequirednumber[]Risk aversions to solve at, increasing. Spread them over orders of magnitude rather than linearly: the schedule changes with the square root of this, so a linear sweep spends most of its points in one corner.

Backtest validation

Whether a track record is evidence of anything, given how many things were tried to find it. Everything here will compute a number; several of these tools refuse instead, which is the point of them.

deflated_sharpe_ratio

A Sharpe ratio corrected for how many things were tried

The probability that the best of a set of trials has a true Sharpe ratio above zero, given how many trials there were and how much they varied. A Sharpe of 1.5 picked out of two hundred attempts is a different object from one committed to in advance, and nothing in the number says which it is. The correction uses the *effective* number of trials rather than the raw count, because variations of one idea are not independent bets: on forty trials driven by a common factor the effective count is 3.0 rather than 40, and the deflated figure 0.824 rather than 0.720, while on forty independent trials the two agree to the digit. Both are reported. Returns are per period, and so is every Sharpe ratio here.

ArgumentTypeMeaning
trialsrequirednumber[][]Returns of every trial, one row per period and one column per trial. Decimal fractions: a 1% period is 0.01. These are per-period returns, not annualised ones, and every Sharpe ratio derived from them is per period too.
effectiveMethodaverage | eigenvalue | participationWhich estimate of the effective trial count to deflate against. Defaults to 'eigenvalue', which counts the dimensions the trials actually span. All three are reported whichever is chosen, because they disagree — on forty trials driven by one factor they give 2.49, 3.00 and 1.08 — and a caller should see that rather than be handed one of them.
periodsPerYearnumberPeriods in a year, used only to annualise the figures that are reported both ways. 252 for daily equity data, 52 for weekly, 12 for monthly. Annualising weekly data with 252 overstates a Sharpe ratio by a factor of about 2.2, which does not look wrong enough to notice.
selectedintegerWhich trial to deflate, numbered from zero. Leave it out to take the best, which is the usual question — naming one that was chosen in advance asks something different and much weaker.

effective_trial_count

How many independent bets a set of trials really is

Three estimates of how many independent trials a correlated set amounts to, and the reduction against the raw count. Two hundred variations of one rule are not two hundred bets, and any multiple-testing correction applied as though they were is too harsh. The methods disagree and all three are returned: the average-correlation method assumes a single common correlation, the eigenvalue method counts the dimensions the trials span, and the participation ratio weights by how concentrated those dimensions are and is the most aggressive of the three.

ArgumentTypeMeaning
trialsrequirednumber[][]Returns of every trial, one row per period and one column per trial. Decimal fractions: a 1% period is 0.01. These are per-period returns, not annualised ones, and every Sharpe ratio derived from them is per period too.

minimum_track_record_length

How long a record must be to mean anything

The number of observations at which a Sharpe ratio of the given size, with the given higher moments, becomes distinguishable from the benchmark at the stated confidence. Skew and fat tails both lengthen it: negative skew in particular, because the estimator's error is larger exactly where the returns are. The Sharpe ratio here is per period — pass periodsPerYear to have the answer in years and the ratio echoed back annualised, so a mixed-up convention is visible in the result.

ArgumentTypeMeaning
sharperequirednumberObserved Sharpe ratio, per period. An annualised 1.0 on daily data is about 0.063 here. It has to exceed the benchmark: below it no length of record makes it significant, and the call is refused rather than answered with an infinity.
benchmarknumberSharpe ratio to beat, per period. Defaults to zero.
confidencenumberOne-sided confidence level. Defaults to 0.95.
excessKurtosisnumberExcess kurtosis: zero for a normal distribution. Given as excess rather than raw, because the two differ by three and a raw 3.0 entered here as excess quietly lengthens the answer. It is not independent of the skewness: every distribution satisfies kurtosis >= 1 + skewness^2, so an excess kurtosis below skewness^2 - 2 describes nothing and is refused rather than used. A skewness of -1.5 therefore needs an excess kurtosis of at least 0.25.
periodsPerYearnumberPeriods in a year, used only to annualise the figures that are reported both ways. 252 for daily equity data, 52 for weekly, 12 for monthly. Annualising weekly data with 252 overstates a Sharpe ratio by a factor of about 2.2, which does not look wrong enough to notice.
skewnessnumberSkewness of the returns. Defaults to zero.

backtest_overfitting_probability

How often the in-sample winner loses out of sample

Split the history into blocks, take every way of halving them, pick the best strategy on one half and see where it ranks on the other. The share of splits where it lands in the bottom half is the probability of backtest overfitting: near one half means the selection carries no information, and above it means it is actively misleading. The degradation regression of out-of-sample on in-sample performance comes with it — a slope at or below zero says a better backtest predicts a worse future. Needs at least five strategies, because with k of them the estimate lives on a k-point grid.

ArgumentTypeMeaning
trialsrequirednumber[][]Returns of every trial, one row per period and one column per trial. Decimal fractions: a 1% period is 0.01. These are per-period returns, not annualised ones, and every Sharpe ratio derived from them is per period too.
blocksintegerBlocks the history is cut into; must be even. Defaults to 16, which is 12,870 partitions. The count of partitions is C(n, n/2) and grows fast: twenty blocks is 184,756.

superior_predictive_ability

Whether any strategy really beats the benchmark

Hansen's test: given a benchmark and a set of candidates, whether the best of them beats it by more than the search itself would produce. This is the question people mean when they say a strategy beat the index, and comparing the winner to the benchmark directly answers a different and much easier one. Three p-values come back rather than one — a wide gap between the lower and upper bounds means the answer depends on which poor models are counted as contenders — and a Romano-Wolf stepdown names which individual candidates survive. The bootstrap is seeded and the seed is in the result, so a p-value can be reproduced from the result alone.

ArgumentTypeMeaning
trialsrequirednumber[][]Returns of every trial, one row per period and one column per trial. Decimal fractions: a 1% period is 0.01. These are per-period returns, not annualised ones, and every Sharpe ratio derived from them is per period too.
benchmarkintegerWhich column is the benchmark, numbered from zero. Defaults to the first. Every other column is tested against it.
bootstrapintegerStationary bootstrap replications. Defaults to 1000. The block length is chosen from the data's own serial correlation and reported.
seedintegerSeed for the bootstrap. Defaults to 0 rather than to randomness, so that the same call twice gives the same p-value. The seed used is in the result, so a figure can be reproduced from the result alone.

model_confidence_set

Which models cannot be told apart from the best

Hansen, Lunde and Nason's model confidence set: given a set of candidates and no incumbent among them, the subset that cannot be distinguished from the best at a stated level. This is the tool for ranking a parameter sweep, and the answer is usually uncomfortable — on thirty crossover rules over ten years with a real drift in the market, 29 of the 30 survive. The size of the set is the result, not a shortcoming of it. A smaller alpha gives a LARGER set, because this is a confidence region rather than a hypothesis test. Columns are returns with higher better.

ArgumentTypeMeaning
trialsrequirednumber[][]Returns of every trial, one row per period and one column per trial. Decimal fractions: a 1% period is 0.01. These are per-period returns, not annualised ones, and every Sharpe ratio derived from them is per period too.
alphanumberLevel for the reported set. Defaults to 0.10, following the paper. A smaller value gives a larger set. The p-values returned do not depend on it, so any other level can be read off them.
bootstrapintegerStationary bootstrap replications. Defaults to 1000. Rows are resampled together, so the correlation between models is kept and near-duplicates are not counted as independent tries.
seedintegerSeed for the bootstrap. Defaults to 0 rather than to randomness, so that the same call twice gives the same p-value. The seed used is in the result, so a figure can be reproduced from the result alone.
statisticmax | range'max' studentises each model against the average of the set; 'range' takes the largest studentised pair. Defaults to max, which gives the larger set and so the weaker claim — measured over fifteen borderline samples of ten models, 8.13 retained against 7.07.