Derivatives¶
Delta-1 instruments on indices, ETFs and equities: index and ETF futures, total return swaps, rate curves, term structures, and the pricing functions behind them.
derivatives ¶
The 'derivatives' package models exchange-traded and OTC Delta-1 derivatives that reference beacon indices, ETFs, and equities.
DerivativeBase ¶
DerivativeBase(
derivative_id: str,
underlying_id: str,
underlying_type: str,
currency: str,
expiry_date: str,
notional: float,
)
Bases: ABC
Abstract base for Delta-1 derivative instruments.
Holds the common contract terms (identifiers, currency, expiry, notional)
and the ACT/365 time-to-expiry helper. Concrete subclasses implement
:meth:fair_value and :meth:mark_to_market.
Initialise the common contract terms.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
derivative_id
|
str
|
Unique identifier for this derivative. |
required |
underlying_id
|
str
|
Identifier of the referenced underlying. |
required |
underlying_type
|
str
|
One of |
required |
currency
|
str
|
Contract currency (e.g. |
required |
expiry_date
|
str
|
Expiry date (YYYY-MM-DD). |
required |
notional
|
float
|
Contract notional; must be positive. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If any required field is empty/invalid, the underlying type is unrecognised, or notional is not positive. |
time_to_expiry ¶
Time to expiry in years using the ACT/365 convention.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
valuation_date
|
Timestamp
|
The date from which to measure. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Years to expiry, clamped to |
fair_value
abstractmethod
¶
Return the model fair value of the derivative.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spot_price
|
float
|
Current spot/level of the underlying. |
required |
valuation_date
|
Timestamp
|
The valuation date. |
required |
market_data
|
dict[str, Any]
|
Additional inputs keyed by name. Most are scalar rates
(e.g. |
required |
Returns:
| Type | Description |
|---|---|
float
|
The fair value in contract currency. |
mark_to_market
abstractmethod
¶
mark_to_market(
market_price: float,
spot_price: float,
valuation_date: Timestamp,
market_data: dict[str, Any],
) -> dict[str, float]
Mark the position to market against an observed market_price.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
market_price
|
float
|
Observed traded price of the derivative. |
required |
spot_price
|
float
|
Current spot/level of the underlying. |
required |
valuation_date
|
Timestamp
|
The valuation date. |
required |
market_data
|
dict[str, Any]
|
Additional inputs keyed by name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
A dictionary of mark-to-market results (e.g. fair value, PnL, |
dict[str, float]
|
basis) in contract currency. |
RateCurve
dataclass
¶
A zero-rate curve defined by pillar points.
Construction raises CalculationError if there are no pillars, the tenor
and rate counts differ, a tenor is negative, or the tenors are not
strictly increasing. :meth:from_pillars sorts them for you.
Attributes:
| Name | Type | Description |
|---|---|---|
tenors |
tuple[float, ...]
|
Pillar tenors in years, strictly increasing. |
rates |
tuple[float, ...]
|
Continuously compounded zero rate at each pillar. |
flat
classmethod
¶
A curve with the same rate at every tenor.
The bridge back to scalar-rate pricing: a flat curve returns exactly the rate it was given at every tenor, so pricing off it reproduces scalar-rate pricing bit for bit rather than approximately.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rate
|
float
|
The continuously compounded rate. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
RateCurve |
RateCurve
|
A single-pillar curve. |
from_pillars
classmethod
¶
Build a curve from a {tenor: rate} mapping, sorted by tenor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pillars
|
dict[float, float]
|
Tenor in years to continuously compounded zero rate. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
RateCurve |
RateCurve
|
The curve. |
Raises:
| Type | Description |
|---|---|
CalculationError
|
If pillars is empty, a tenor is negative, or two tenors are equal. |
zero_rate ¶
The zero rate at tenor, interpolated between pillars.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenor
|
float
|
Years from the valuation date. Must be non-negative. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
float |
float
|
The continuously compounded zero rate. Flat beyond the first |
float
|
and last pillar. |
Raises:
| Type | Description |
|---|---|
CalculationError
|
If tenor is negative. |
discount_factor ¶
Present value of one unit paid at tenor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenor
|
float
|
Years from the valuation date. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
float |
float
|
|
forward_rate ¶
The rate implied between two future dates.
The rate that makes discounting to end the same as discounting to start and then forward at this rate, which is what a financing leg resetting at start should be projected at.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
float
|
Start of the forward period, in years. |
required |
end
|
float
|
End of the forward period, in years. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
float |
float
|
Continuously compounded forward rate. |
Raises:
| Type | Description |
|---|---|
CalculationError
|
If end is not after start. |
shifted ¶
A copy with every pillar moved by bump.
The parallel shift a DV01 is measured against.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bump
|
float
|
Amount to add to every rate, in decimal. One basis point is
|
required |
Returns:
| Name | Type | Description |
|---|---|---|
RateCurve |
RateCurve
|
The shifted curve. The original is unchanged. |
with_pillar_bump ¶
A copy with one pillar moved, for a key-rate sensitivity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenor
|
float
|
The pillar to move. Must be an existing pillar: bumping a tenor that is not there would silently add a pillar and change the curve's shape rather than its level, which is not what a key-rate bump means. |
required |
bump
|
float
|
Amount to add to that pillar's rate. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
RateCurve |
RateCurve
|
The bumped curve. |
Raises:
| Type | Description |
|---|---|
CalculationError
|
If tenor is not a pillar. |
ETFFuture ¶
ETFFuture(
derivative_id: str,
underlying_id: str,
currency: str,
expiry_date: str,
contract_multiplier: float,
tick_size: float,
tick_value: float,
)
Bases: IndexFuture
A futures contract on an ETF.
Behaves like :class:IndexFuture but prices with discrete known dividends,
which better reflects an ETF's periodic cash distributions than a continuous
yield. When discrete dividends are supplied via the market_data key
"discrete_dividends" (a list of (time_to_ex_years, amount) tuples for
ex-dates within the tenor), fair value uses
F = (S - PV(divs)) * exp(r * T). Otherwise it falls back to the
continuous cost-of-carry model inherited from :class:IndexFuture.
Initialise an ETF future. See :class:IndexFuture for the args.
fair_value ¶
Discrete-dividend fair value, falling back to continuous carry.
If market_data["discrete_dividends"] is present and non-empty, prices
with the discrete-dividend model; otherwise defers to the continuous
cost-of-carry model of :class:IndexFuture.
IndexFuture ¶
IndexFuture(
derivative_id: str,
underlying_id: str,
currency: str,
expiry_date: str,
contract_multiplier: float,
tick_size: float,
tick_value: float,
underlying_type: str = "INDEX",
)
Bases: DerivativeBase
A cash-settled futures contract on an equity index.
Prices are quoted in index points; currency amounts are obtained by
multiplying by :attr:contract_multiplier. Fair value uses the
cost-of-carry model from :mod:beacon.derivatives.pricing.
Market-data inputs (passed via the market_data dict on valuation
methods) are read by key:
risk_free_rate: continuous risk-free rater(default 0)dividend_yield: continuous dividend yieldq(default 0)borrow_cost: continuous borrow/financing spreadc(default 0)
Initialise an index future.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
derivative_id
|
str
|
Unique identifier for the contract. |
required |
underlying_id
|
str
|
Identifier of the referenced index. |
required |
currency
|
str
|
Contract currency (e.g. |
required |
expiry_date
|
str
|
Expiry date (YYYY-MM-DD). |
required |
contract_multiplier
|
float
|
Currency value of one index point. |
required |
tick_size
|
float
|
Minimum price increment, in index points. |
required |
tick_value
|
float
|
Currency value of one tick. |
required |
underlying_type
|
str
|
Underlying instrument type; defaults to |
'INDEX'
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If any of contract_multiplier, tick_size or tick_value is non-positive (plus the base-class validations). |
fair_value ¶
Cost-of-carry fair value F = S * exp((r - q + c) * T) in points.
Returns spot_price when the contract is at or past expiry (T == 0).
basis ¶
Simple basis: futures_price - spot_price (index points).
annualised_basis ¶
Annualised implied financing rate ln(F / S) / T.
Implemented via :func:implied_repo_rate with zero dividend yield.
Raises:
| Type | Description |
|---|---|
ValueError
|
At or past expiry ( |
daily_settlement_pnl ¶
daily_settlement_pnl(
settle_today: float,
settle_yesterday: float,
contracts: float = 1.0,
) -> float
Variation-margin P&L for the day, in contract currency.
(settle_today - settle_yesterday) * contract_multiplier * contracts.
Positive contracts is a long position, negative is short.
roll_cost ¶
Cost of rolling from the front to the back contract: back - front.
Positive in contango (back above front), negative in backwardation.
mark_to_market ¶
mark_to_market(
market_price: float,
spot_price: float,
valuation_date: Timestamp,
market_data: dict[str, Any],
) -> dict[str, float]
Mark the contract against an observed market_price.
Returns a dict with fair_value (points), basis (market vs spot),
theoretical_edge (fair value minus market price), and
time_to_expiry (years).
TotalReturnSwap ¶
TotalReturnSwap(
derivative_id: str,
underlying_id: str,
currency: str,
start_date: str,
end_date: str,
notional: float,
spread_bps: float,
reference_rate: str,
payment_frequency: str,
reset_type: str = "UNFUNDED",
underlying_type: str = "INDEX",
)
Bases: DerivativeBase
A total return swap (TRS) on an index or equity basket.
The total-return receiver earns the price return of the underlying and pays
a financing leg. For an UNFUNDED swap the financing leg is
reference_rate + spread; for a FUNDED swap the principal is posted
up front and only the spread accrues.
market_data inputs (read by key on the valuation methods):
initial_price: reference priceS_0at inception/last reset (defaults to spot_price, i.e. zero return)reference_rate: the floating rate for the current period (default 0)last_reset_date: start of the current accrual period (defaults to the swap start date)dividends: what the underlying paid per unit sinceS_0, in its own points (default 0). They join the total return leg, so a price level plus its dividends values the swap as a total return level would. Leave them out when the level already counts them.
An expected dividend yield plays no part: the value is what has accrued since the last reset, so it counts the dividends actually paid.
The underlying is an index by default; pass underlying_type for an ETF or an equity basket. Financing accrues ACT/360.
Initialise a total return swap.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
derivative_id
|
str
|
Unique identifier for the swap. |
required |
underlying_id
|
str
|
Identifier of the referenced index/basket. |
required |
currency
|
str
|
Contract currency. |
required |
start_date
|
str
|
Swap start date (YYYY-MM-DD). |
required |
end_date
|
str
|
Swap maturity date (YYYY-MM-DD); used as the base expiry. |
required |
notional
|
float
|
Swap notional; must be positive. |
required |
spread_bps
|
float
|
Financing spread over the reference rate, in basis points. |
required |
reference_rate
|
str
|
Name/identifier of the floating reference rate
(e.g. |
required |
payment_frequency
|
str
|
One of |
required |
reset_type
|
str
|
|
'UNFUNDED'
|
underlying_type
|
str
|
What underlying_id refers to: |
'INDEX'
|
Raises:
| Type | Description |
|---|---|
ValueError
|
On empty dates, |
financing_cost ¶
financing_cost(
valuation_date: Timestamp,
last_reset_date: Timestamp,
reference_rate: float,
) -> float
Financing accrued since last_reset_date on an ACT/360 basis.
For an UNFUNDED swap the accrual rate is reference_rate + spread;
for a FUNDED swap only the spread accrues.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
valuation_date
|
Timestamp
|
The accrual end date. |
required |
last_reset_date
|
Timestamp
|
Start of the current accrual period. |
required |
reference_rate
|
float
|
Floating reference rate for the period (decimal). |
required |
Returns:
| Type | Description |
|---|---|
float
|
The accrued financing cost in contract currency. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If valuation_date precedes last_reset_date. |
dv01 ¶
dv01(
valuation_date: Timestamp,
last_reset_date: Timestamp,
reference_rate: float = 0.0,
) -> float
Change in the receiver's value for a one-basis-point rate rise.
Computed by bumping the reference rate by one basis point and
revaluing the accrued financing, rather than by the closed form. The
two agree exactly here, since financing is linear in the rate
(-notional * 1bp * financing_duration).
The sign is negative for a total-return receiver, and that is not a convention choice. The receiver pays financing, so a higher rate makes their position worth less. Reporting DV01 as a positive magnitude is common, but it loses the one piece of information a risk report most needs: which way this position hurts.
A FUNDED swap returns 0.0. Only the spread accrues on one, and the
spread does not move with the reference rate, so the position genuinely
has no sensitivity to it, rather than a small one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
valuation_date
|
Timestamp
|
The accrual end date. |
required |
last_reset_date
|
Timestamp
|
Start of the current accrual period. |
required |
reference_rate
|
float
|
The floating rate the bump is applied to. The answer does not depend on its level, since financing is linear, but it is accepted so the call reads the same as the others. |
0.0
|
Returns:
| Name | Type | Description |
|---|---|---|
float |
float
|
Value change per +1bp, in contract currency. Negative for a |
float
|
receiver on an unfunded swap. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If valuation_date precedes last_reset_date. |
financing_duration ¶
The accrual year fraction the DV01 scales with, ACT/360.
Exposed because it is the whole of the DV01 story: the sensitivity is notional × 1bp × this, so a reader who wants to check the number by hand needs it rather than having to rederive the day count.
Raises:
| Type | Description |
|---|---|
ValueError
|
If valuation_date precedes last_reset_date. |
fair_value ¶
Total-return-receiver P&L: total return leg minus accrued financing.
receiver_pnl = notional * ((S_t + D) / S_0 - 1) - accrued_financing,
with S_0, the dividends paid D, the reference rate and the last
reset date read from market_data as described on the class.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
total_return_leg ¶
What the total return leg has earned since initial_price: the level's change plus the dividends paid per unit, on the notional.
Raises:
| Type | Description |
|---|---|
ValueError
|
If dividends is negative. |
mark_to_market ¶
mark_to_market(
market_price: float,
spot_price: float,
valuation_date: Timestamp,
market_data: dict[str, Any],
) -> dict[str, float]
Decompose the swap P&L into its legs.
market_price is unused (a TRS has no separately quoted price); it is
accepted to satisfy the :class:DerivativeBase interface.
Returns a dict with total_return_leg, financing_leg,
net_mtm and accrued_days.
FuturesQuote
dataclass
¶
One expiry and the price the market puts on it.
Attributes:
| Name | Type | Description |
|---|---|---|
expiry |
Timestamp
|
Contract expiry date. |
market_price |
float | None
|
Traded price. None when only a theoretical value is wanted, in which case basis and implied repo are not reported for this pillar rather than being invented. |
label |
str
|
Optional contract code, for display. |
TermStructure
dataclass
¶
TermStructure(
underlying: str,
spot: float,
valuation_date: Timestamp,
quotes: list[FuturesQuote],
curve: RateCurve,
dividend_yield: float = 0.0,
borrow_cost: float = 0.0,
_sorted: list[FuturesQuote] = list(),
)
A strip of futures on one underlying, valued off one curve.
Fair values use continuous cost of carry, with each expiry financed at the
curve's zero rate for its ACT/365 time to expiry. Construction raises
CalculationError if there are no quotes, spot is not positive, or an
expiry is before valuation_date.
Attributes:
| Name | Type | Description |
|---|---|---|
underlying |
str
|
Identifier of the underlying. |
spot |
float
|
Spot price at valuation_date. |
valuation_date |
Timestamp
|
The date everything is measured from. |
quotes |
list[FuturesQuote]
|
The expiries, in any order; they are sorted on construction. |
curve |
RateCurve
|
Financing curve. A flat curve reproduces scalar-rate pricing exactly. |
dividend_yield |
float
|
Continuous dividend yield on the underlying. |
borrow_cost |
float
|
Continuous borrow spread. |
theoretical_prices ¶
Fair value at each expiry, off the curve.
Returns:
| Type | Description |
|---|---|
Series
|
pd.Series: Indexed by expiry date. |
basis ¶
Market minus theoretical, per expiry.
Positive means the contract trades rich to the model.
implied_repo ¶
The financing rate each quoted price implies.
(ln(F / S) + q * T) / T per expiry, using the strip's dividend
yield. The borrow cost is not subtracted, so it shows up inside the
implied rate.
NaN for expiries with no quote, and for an expiry today: a zero year fraction carries no information about a rate, and dividing by it would manufacture one.
Returns:
| Type | Description |
|---|---|
Series
|
pd.Series: Continuously compounded rates, indexed by expiry. |
cost_of_carry_fair_value ¶
cost_of_carry_fair_value(
spot: float,
risk_free_rate: float,
dividend_yield: float,
time_to_expiry_years: float,
borrow_cost: float = 0.0,
) -> float
Fair forward/futures value under continuous cost of carry.
F = S * exp((r - q + c) * T)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spot
|
float
|
Current spot price |
required |
risk_free_rate
|
float
|
Continuously compounded risk-free rate |
required |
dividend_yield
|
float
|
Continuous dividend yield |
required |
time_to_expiry_years
|
float
|
Time to expiry |
required |
borrow_cost
|
float
|
Continuous borrow/financing spread |
0.0
|
Returns:
| Type | Description |
|---|---|
float
|
The fair value |
Raises:
| Type | Description |
|---|---|
ValueError
|
If spot or time_to_expiry_years is negative. |
discrete_dividend_fair_value ¶
discrete_dividend_fair_value(
spot: float,
risk_free_rate: float,
time_to_expiry_years: float,
dividends: list[tuple[float, float]],
) -> float
Fair forward/futures value with discrete cash dividends.
F = (S - PV(divs)) * exp(r * T) where each dividend is discounted at the
risk-free rate to today: PV = amount * exp(-r * t_ex).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spot
|
float
|
Current spot price |
required |
risk_free_rate
|
float
|
Continuously compounded risk-free rate |
required |
time_to_expiry_years
|
float
|
Time to expiry |
required |
dividends
|
list[tuple[float, float]]
|
List of |
required |
Returns:
| Type | Description |
|---|---|
float
|
The fair value |
Raises:
| Type | Description |
|---|---|
ValueError
|
If spot or time_to_expiry_years is negative. |
futures_roll_return ¶
futures_roll_return(
front_price: float,
back_price: float,
front_expiry: Timestamp,
back_expiry: Timestamp,
) -> float
Annualised simple roll return from rolling a front contract to a back one.
roll = (front / back - 1) / dt where dt is the ACT/365 year fraction
between the two expiries. Positive in backwardation (front above back), negative in
contango.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
front_price
|
float
|
Price of the near (front) contract (must be positive). |
required |
back_price
|
float
|
Price of the far (back) contract (must be positive). |
required |
front_expiry
|
Timestamp
|
Expiry of the front contract. |
required |
back_expiry
|
Timestamp
|
Expiry of the back contract (must be after front_expiry). |
required |
Returns:
| Type | Description |
|---|---|
float
|
The annualised roll return as a decimal. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If either price is non-positive, or back_expiry is not strictly after front_expiry. |
implied_repo_rate ¶
implied_repo_rate(
futures_price: float,
spot: float,
dividend_yield: float,
time_to_expiry_years: float,
) -> float
Continuously compounded financing rate implied by a futures price.
Inverts the cost-of-carry relationship:
r_implied = (ln(F / S) + q * T) / T
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
futures_price
|
float
|
Observed futures price |
required |
spot
|
float
|
Current spot price |
required |
dividend_yield
|
float
|
Continuous dividend yield |
required |
time_to_expiry_years
|
float
|
Time to expiry |
required |
Returns:
| Type | Description |
|---|---|
float
|
The implied repo (financing) rate. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If time_to_expiry_years, spot or futures_price is non-positive. |
trs_breakeven_spread ¶
trs_breakeven_spread(
futures_price: float,
spot: float,
risk_free_rate: float,
time_to_expiry_years: float,
dividend_yield: float,
) -> float
Financing spread at which a total return swap matches futures economics.
The futures price embeds an implied financing rate (:func:implied_repo_rate).
A TRS financed at r + spread reproduces those economics when the spread
equals the gap between the implied financing rate and the risk-free rate:
spread = implied_repo_rate(F, S, q, T) - r
A fairly priced future (financed exactly at r) gives a breakeven spread
of zero.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
futures_price
|
float
|
Observed futures price |
required |
spot
|
float
|
Current spot price |
required |
risk_free_rate
|
float
|
Continuously compounded risk-free rate |
required |
time_to_expiry_years
|
float
|
Time to expiry |
required |
dividend_yield
|
float
|
Continuous dividend yield |
required |
Returns:
| Type | Description |
|---|---|
float
|
The breakeven financing spread as a decimal. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If time_to_expiry_years, spot or futures_price is non-positive. |
sensitivity_grid ¶
sensitivity_grid(
spot: float,
tenors: list[float],
rates: list[float],
dividend_yield: float = 0.0,
borrow_cost: float = 0.0,
) -> pd.DataFrame
Fair value across a tenor × rate grid.
What a position is worth if the curve is somewhere else and expiry is further out: the two axes a Delta-1 desk actually moves along, laid out so the shape is visible at once rather than one revaluation at a time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spot
|
float
|
Spot price of the underlying. |
required |
tenors
|
list[float]
|
Times to expiry in years, one per row. |
required |
rates
|
list[float]
|
Continuously compounded financing rates, one per column. |
required |
dividend_yield
|
float
|
Continuous dividend yield. |
0.0
|
borrow_cost
|
float
|
Continuous borrow spread. |
0.0
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
pd.DataFrame: Fair values, tenors on the index and rates on the |
DataFrame
|
columns, both labelled with their values. |
Raises:
| Type | Description |
|---|---|
CalculationError
|
If either axis is empty. |
base ¶
DerivativeBase: abstract base class for all Delta-1 derivative instruments.
DerivativeBase ¶
DerivativeBase(
derivative_id: str,
underlying_id: str,
underlying_type: str,
currency: str,
expiry_date: str,
notional: float,
)
Bases: ABC
Abstract base for Delta-1 derivative instruments.
Holds the common contract terms (identifiers, currency, expiry, notional)
and the ACT/365 time-to-expiry helper. Concrete subclasses implement
:meth:fair_value and :meth:mark_to_market.
Initialise the common contract terms.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
derivative_id
|
str
|
Unique identifier for this derivative. |
required |
underlying_id
|
str
|
Identifier of the referenced underlying. |
required |
underlying_type
|
str
|
One of |
required |
currency
|
str
|
Contract currency (e.g. |
required |
expiry_date
|
str
|
Expiry date (YYYY-MM-DD). |
required |
notional
|
float
|
Contract notional; must be positive. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If any required field is empty/invalid, the underlying type is unrecognised, or notional is not positive. |
time_to_expiry ¶
Time to expiry in years using the ACT/365 convention.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
valuation_date
|
Timestamp
|
The date from which to measure. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Years to expiry, clamped to |
fair_value
abstractmethod
¶
Return the model fair value of the derivative.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spot_price
|
float
|
Current spot/level of the underlying. |
required |
valuation_date
|
Timestamp
|
The valuation date. |
required |
market_data
|
dict[str, Any]
|
Additional inputs keyed by name. Most are scalar rates
(e.g. |
required |
Returns:
| Type | Description |
|---|---|
float
|
The fair value in contract currency. |
mark_to_market
abstractmethod
¶
mark_to_market(
market_price: float,
spot_price: float,
valuation_date: Timestamp,
market_data: dict[str, Any],
) -> dict[str, float]
Mark the position to market against an observed market_price.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
market_price
|
float
|
Observed traded price of the derivative. |
required |
spot_price
|
float
|
Current spot/level of the underlying. |
required |
valuation_date
|
Timestamp
|
The valuation date. |
required |
market_data
|
dict[str, Any]
|
Additional inputs keyed by name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
A dictionary of mark-to-market results (e.g. fair value, PnL, |
dict[str, float]
|
basis) in contract currency. |
curves ¶
Interest-rate curves.
A curve is asked for a rate at a tenor, and the answer (a plain float) goes
into a function from beacon.derivatives.pricing, which takes rates as
scalars.
Rates are continuously compounded zero rates, matching what the pricing functions expect, so a flat curve and the scalar rate it replaces are the same number and produce the same answer to the last bit.
Interpolation, and what happens off the ends¶
Linear in the zero rate between pillars: the conventional choice, and the one whose failure modes are understood. Beyond the first and last pillar the curve is flat, holding the nearest pillar's rate rather than continuing its slope. Extrapolating a slope off the end of a curve is how a two-year rate becomes a negative thirty-year rate: it is arithmetically reasonable and financially nonsense, and the error appears far from the code that caused it.
RateCurve
dataclass
¶
A zero-rate curve defined by pillar points.
Construction raises CalculationError if there are no pillars, the tenor
and rate counts differ, a tenor is negative, or the tenors are not
strictly increasing. :meth:from_pillars sorts them for you.
Attributes:
| Name | Type | Description |
|---|---|---|
tenors |
tuple[float, ...]
|
Pillar tenors in years, strictly increasing. |
rates |
tuple[float, ...]
|
Continuously compounded zero rate at each pillar. |
flat
classmethod
¶
A curve with the same rate at every tenor.
The bridge back to scalar-rate pricing: a flat curve returns exactly the rate it was given at every tenor, so pricing off it reproduces scalar-rate pricing bit for bit rather than approximately.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rate
|
float
|
The continuously compounded rate. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
RateCurve |
RateCurve
|
A single-pillar curve. |
from_pillars
classmethod
¶
Build a curve from a {tenor: rate} mapping, sorted by tenor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pillars
|
dict[float, float]
|
Tenor in years to continuously compounded zero rate. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
RateCurve |
RateCurve
|
The curve. |
Raises:
| Type | Description |
|---|---|
CalculationError
|
If pillars is empty, a tenor is negative, or two tenors are equal. |
zero_rate ¶
The zero rate at tenor, interpolated between pillars.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenor
|
float
|
Years from the valuation date. Must be non-negative. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
float |
float
|
The continuously compounded zero rate. Flat beyond the first |
float
|
and last pillar. |
Raises:
| Type | Description |
|---|---|
CalculationError
|
If tenor is negative. |
discount_factor ¶
Present value of one unit paid at tenor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenor
|
float
|
Years from the valuation date. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
float |
float
|
|
forward_rate ¶
The rate implied between two future dates.
The rate that makes discounting to end the same as discounting to start and then forward at this rate, which is what a financing leg resetting at start should be projected at.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
float
|
Start of the forward period, in years. |
required |
end
|
float
|
End of the forward period, in years. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
float |
float
|
Continuously compounded forward rate. |
Raises:
| Type | Description |
|---|---|
CalculationError
|
If end is not after start. |
shifted ¶
A copy with every pillar moved by bump.
The parallel shift a DV01 is measured against.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bump
|
float
|
Amount to add to every rate, in decimal. One basis point is
|
required |
Returns:
| Name | Type | Description |
|---|---|---|
RateCurve |
RateCurve
|
The shifted curve. The original is unchanged. |
with_pillar_bump ¶
A copy with one pillar moved, for a key-rate sensitivity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenor
|
float
|
The pillar to move. Must be an existing pillar: bumping a tenor that is not there would silently add a pillar and change the curve's shape rather than its level, which is not what a key-rate bump means. |
required |
bump
|
float
|
Amount to add to that pillar's rate. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
RateCurve |
RateCurve
|
The bumped curve. |
Raises:
| Type | Description |
|---|---|
CalculationError
|
If tenor is not a pillar. |
forwards ¶
Forward contracts referencing beacon instruments.
A placeholder: nothing is implemented here yet. An EquityForward is planned.
futures ¶
Futures contracts referencing beacon instruments: IndexFuture (on an index) and ETFFuture (on an ETF).
IndexFuture ¶
IndexFuture(
derivative_id: str,
underlying_id: str,
currency: str,
expiry_date: str,
contract_multiplier: float,
tick_size: float,
tick_value: float,
underlying_type: str = "INDEX",
)
Bases: DerivativeBase
A cash-settled futures contract on an equity index.
Prices are quoted in index points; currency amounts are obtained by
multiplying by :attr:contract_multiplier. Fair value uses the
cost-of-carry model from :mod:beacon.derivatives.pricing.
Market-data inputs (passed via the market_data dict on valuation
methods) are read by key:
risk_free_rate: continuous risk-free rater(default 0)dividend_yield: continuous dividend yieldq(default 0)borrow_cost: continuous borrow/financing spreadc(default 0)
Initialise an index future.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
derivative_id
|
str
|
Unique identifier for the contract. |
required |
underlying_id
|
str
|
Identifier of the referenced index. |
required |
currency
|
str
|
Contract currency (e.g. |
required |
expiry_date
|
str
|
Expiry date (YYYY-MM-DD). |
required |
contract_multiplier
|
float
|
Currency value of one index point. |
required |
tick_size
|
float
|
Minimum price increment, in index points. |
required |
tick_value
|
float
|
Currency value of one tick. |
required |
underlying_type
|
str
|
Underlying instrument type; defaults to |
'INDEX'
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If any of contract_multiplier, tick_size or tick_value is non-positive (plus the base-class validations). |
fair_value ¶
Cost-of-carry fair value F = S * exp((r - q + c) * T) in points.
Returns spot_price when the contract is at or past expiry (T == 0).
basis ¶
Simple basis: futures_price - spot_price (index points).
annualised_basis ¶
Annualised implied financing rate ln(F / S) / T.
Implemented via :func:implied_repo_rate with zero dividend yield.
Raises:
| Type | Description |
|---|---|
ValueError
|
At or past expiry ( |
daily_settlement_pnl ¶
daily_settlement_pnl(
settle_today: float,
settle_yesterday: float,
contracts: float = 1.0,
) -> float
Variation-margin P&L for the day, in contract currency.
(settle_today - settle_yesterday) * contract_multiplier * contracts.
Positive contracts is a long position, negative is short.
roll_cost ¶
Cost of rolling from the front to the back contract: back - front.
Positive in contango (back above front), negative in backwardation.
mark_to_market ¶
mark_to_market(
market_price: float,
spot_price: float,
valuation_date: Timestamp,
market_data: dict[str, Any],
) -> dict[str, float]
Mark the contract against an observed market_price.
Returns a dict with fair_value (points), basis (market vs spot),
theoretical_edge (fair value minus market price), and
time_to_expiry (years).
ETFFuture ¶
ETFFuture(
derivative_id: str,
underlying_id: str,
currency: str,
expiry_date: str,
contract_multiplier: float,
tick_size: float,
tick_value: float,
)
Bases: IndexFuture
A futures contract on an ETF.
Behaves like :class:IndexFuture but prices with discrete known dividends,
which better reflects an ETF's periodic cash distributions than a continuous
yield. When discrete dividends are supplied via the market_data key
"discrete_dividends" (a list of (time_to_ex_years, amount) tuples for
ex-dates within the tenor), fair value uses
F = (S - PV(divs)) * exp(r * T). Otherwise it falls back to the
continuous cost-of-carry model inherited from :class:IndexFuture.
Initialise an ETF future. See :class:IndexFuture for the args.
fair_value ¶
Discrete-dividend fair value, falling back to continuous carry.
If market_data["discrete_dividends"] is present and non-empty, prices
with the discrete-dividend model; otherwise defers to the continuous
cost-of-carry model of :class:IndexFuture.
pricing ¶
Pure, stateless pricing functions for Delta-1 derivatives.
These functions implement standard textbook cost-of-carry relationships and
have zero dependencies on the rest of Beacon (only the standard library and
pandas Timestamps for date arithmetic). All rates are continuously compounded
and expressed as annual decimals (e.g. 0.05 for 5%); times are in years.
cost_of_carry_fair_value ¶
cost_of_carry_fair_value(
spot: float,
risk_free_rate: float,
dividend_yield: float,
time_to_expiry_years: float,
borrow_cost: float = 0.0,
) -> float
Fair forward/futures value under continuous cost of carry.
F = S * exp((r - q + c) * T)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spot
|
float
|
Current spot price |
required |
risk_free_rate
|
float
|
Continuously compounded risk-free rate |
required |
dividend_yield
|
float
|
Continuous dividend yield |
required |
time_to_expiry_years
|
float
|
Time to expiry |
required |
borrow_cost
|
float
|
Continuous borrow/financing spread |
0.0
|
Returns:
| Type | Description |
|---|---|
float
|
The fair value |
Raises:
| Type | Description |
|---|---|
ValueError
|
If spot or time_to_expiry_years is negative. |
discrete_dividend_fair_value ¶
discrete_dividend_fair_value(
spot: float,
risk_free_rate: float,
time_to_expiry_years: float,
dividends: list[tuple[float, float]],
) -> float
Fair forward/futures value with discrete cash dividends.
F = (S - PV(divs)) * exp(r * T) where each dividend is discounted at the
risk-free rate to today: PV = amount * exp(-r * t_ex).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spot
|
float
|
Current spot price |
required |
risk_free_rate
|
float
|
Continuously compounded risk-free rate |
required |
time_to_expiry_years
|
float
|
Time to expiry |
required |
dividends
|
list[tuple[float, float]]
|
List of |
required |
Returns:
| Type | Description |
|---|---|
float
|
The fair value |
Raises:
| Type | Description |
|---|---|
ValueError
|
If spot or time_to_expiry_years is negative. |
implied_repo_rate ¶
implied_repo_rate(
futures_price: float,
spot: float,
dividend_yield: float,
time_to_expiry_years: float,
) -> float
Continuously compounded financing rate implied by a futures price.
Inverts the cost-of-carry relationship:
r_implied = (ln(F / S) + q * T) / T
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
futures_price
|
float
|
Observed futures price |
required |
spot
|
float
|
Current spot price |
required |
dividend_yield
|
float
|
Continuous dividend yield |
required |
time_to_expiry_years
|
float
|
Time to expiry |
required |
Returns:
| Type | Description |
|---|---|
float
|
The implied repo (financing) rate. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If time_to_expiry_years, spot or futures_price is non-positive. |
futures_roll_return ¶
futures_roll_return(
front_price: float,
back_price: float,
front_expiry: Timestamp,
back_expiry: Timestamp,
) -> float
Annualised simple roll return from rolling a front contract to a back one.
roll = (front / back - 1) / dt where dt is the ACT/365 year fraction
between the two expiries. Positive in backwardation (front above back), negative in
contango.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
front_price
|
float
|
Price of the near (front) contract (must be positive). |
required |
back_price
|
float
|
Price of the far (back) contract (must be positive). |
required |
front_expiry
|
Timestamp
|
Expiry of the front contract. |
required |
back_expiry
|
Timestamp
|
Expiry of the back contract (must be after front_expiry). |
required |
Returns:
| Type | Description |
|---|---|
float
|
The annualised roll return as a decimal. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If either price is non-positive, or back_expiry is not strictly after front_expiry. |
trs_breakeven_spread ¶
trs_breakeven_spread(
futures_price: float,
spot: float,
risk_free_rate: float,
time_to_expiry_years: float,
dividend_yield: float,
) -> float
Financing spread at which a total return swap matches futures economics.
The futures price embeds an implied financing rate (:func:implied_repo_rate).
A TRS financed at r + spread reproduces those economics when the spread
equals the gap between the implied financing rate and the risk-free rate:
spread = implied_repo_rate(F, S, q, T) - r
A fairly priced future (financed exactly at r) gives a breakeven spread
of zero.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
futures_price
|
float
|
Observed futures price |
required |
spot
|
float
|
Current spot price |
required |
risk_free_rate
|
float
|
Continuously compounded risk-free rate |
required |
time_to_expiry_years
|
float
|
Time to expiry |
required |
dividend_yield
|
float
|
Continuous dividend yield |
required |
Returns:
| Type | Description |
|---|---|
float
|
The breakeven financing spread as a decimal. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If time_to_expiry_years, spot or futures_price is non-positive. |
swaps ¶
Swap contracts referencing beacon instruments: TotalReturnSwap.
TotalReturnSwap ¶
TotalReturnSwap(
derivative_id: str,
underlying_id: str,
currency: str,
start_date: str,
end_date: str,
notional: float,
spread_bps: float,
reference_rate: str,
payment_frequency: str,
reset_type: str = "UNFUNDED",
underlying_type: str = "INDEX",
)
Bases: DerivativeBase
A total return swap (TRS) on an index or equity basket.
The total-return receiver earns the price return of the underlying and pays
a financing leg. For an UNFUNDED swap the financing leg is
reference_rate + spread; for a FUNDED swap the principal is posted
up front and only the spread accrues.
market_data inputs (read by key on the valuation methods):
initial_price: reference priceS_0at inception/last reset (defaults to spot_price, i.e. zero return)reference_rate: the floating rate for the current period (default 0)last_reset_date: start of the current accrual period (defaults to the swap start date)dividends: what the underlying paid per unit sinceS_0, in its own points (default 0). They join the total return leg, so a price level plus its dividends values the swap as a total return level would. Leave them out when the level already counts them.
An expected dividend yield plays no part: the value is what has accrued since the last reset, so it counts the dividends actually paid.
The underlying is an index by default; pass underlying_type for an ETF or an equity basket. Financing accrues ACT/360.
Initialise a total return swap.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
derivative_id
|
str
|
Unique identifier for the swap. |
required |
underlying_id
|
str
|
Identifier of the referenced index/basket. |
required |
currency
|
str
|
Contract currency. |
required |
start_date
|
str
|
Swap start date (YYYY-MM-DD). |
required |
end_date
|
str
|
Swap maturity date (YYYY-MM-DD); used as the base expiry. |
required |
notional
|
float
|
Swap notional; must be positive. |
required |
spread_bps
|
float
|
Financing spread over the reference rate, in basis points. |
required |
reference_rate
|
str
|
Name/identifier of the floating reference rate
(e.g. |
required |
payment_frequency
|
str
|
One of |
required |
reset_type
|
str
|
|
'UNFUNDED'
|
underlying_type
|
str
|
What underlying_id refers to: |
'INDEX'
|
Raises:
| Type | Description |
|---|---|
ValueError
|
On empty dates, |
financing_cost ¶
financing_cost(
valuation_date: Timestamp,
last_reset_date: Timestamp,
reference_rate: float,
) -> float
Financing accrued since last_reset_date on an ACT/360 basis.
For an UNFUNDED swap the accrual rate is reference_rate + spread;
for a FUNDED swap only the spread accrues.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
valuation_date
|
Timestamp
|
The accrual end date. |
required |
last_reset_date
|
Timestamp
|
Start of the current accrual period. |
required |
reference_rate
|
float
|
Floating reference rate for the period (decimal). |
required |
Returns:
| Type | Description |
|---|---|
float
|
The accrued financing cost in contract currency. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If valuation_date precedes last_reset_date. |
dv01 ¶
dv01(
valuation_date: Timestamp,
last_reset_date: Timestamp,
reference_rate: float = 0.0,
) -> float
Change in the receiver's value for a one-basis-point rate rise.
Computed by bumping the reference rate by one basis point and
revaluing the accrued financing, rather than by the closed form. The
two agree exactly here, since financing is linear in the rate
(-notional * 1bp * financing_duration).
The sign is negative for a total-return receiver, and that is not a convention choice. The receiver pays financing, so a higher rate makes their position worth less. Reporting DV01 as a positive magnitude is common, but it loses the one piece of information a risk report most needs: which way this position hurts.
A FUNDED swap returns 0.0. Only the spread accrues on one, and the
spread does not move with the reference rate, so the position genuinely
has no sensitivity to it, rather than a small one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
valuation_date
|
Timestamp
|
The accrual end date. |
required |
last_reset_date
|
Timestamp
|
Start of the current accrual period. |
required |
reference_rate
|
float
|
The floating rate the bump is applied to. The answer does not depend on its level, since financing is linear, but it is accepted so the call reads the same as the others. |
0.0
|
Returns:
| Name | Type | Description |
|---|---|---|
float |
float
|
Value change per +1bp, in contract currency. Negative for a |
float
|
receiver on an unfunded swap. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If valuation_date precedes last_reset_date. |
financing_duration ¶
The accrual year fraction the DV01 scales with, ACT/360.
Exposed because it is the whole of the DV01 story: the sensitivity is notional × 1bp × this, so a reader who wants to check the number by hand needs it rather than having to rederive the day count.
Raises:
| Type | Description |
|---|---|
ValueError
|
If valuation_date precedes last_reset_date. |
fair_value ¶
Total-return-receiver P&L: total return leg minus accrued financing.
receiver_pnl = notional * ((S_t + D) / S_0 - 1) - accrued_financing,
with S_0, the dividends paid D, the reference rate and the last
reset date read from market_data as described on the class.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
total_return_leg ¶
What the total return leg has earned since initial_price: the level's change plus the dividends paid per unit, on the notional.
Raises:
| Type | Description |
|---|---|
ValueError
|
If dividends is negative. |
mark_to_market ¶
mark_to_market(
market_price: float,
spot_price: float,
valuation_date: Timestamp,
market_data: dict[str, Any],
) -> dict[str, float]
Decompose the swap P&L into its legs.
market_price is unused (a TRS has no separately quoted price); it is
accepted to satisfy the :class:DerivativeBase interface.
Returns a dict with total_return_leg, financing_leg,
net_mtm and accrued_days.
term_structure ¶
Several expiries on one underlying, and what they say about each other.
A single futures price is not very informative. A strip of them is: the shape of the basis across expiries is where financing assumptions, dividend expectations and plain supply-and-demand show up, and none of that is visible one contract at a time.
Two views of the same disagreement, and it is worth being clear that they are the same disagreement:
- Basis: market price minus theoretical price. Answers "how much is this contract off my model", in price terms.
- Implied repo: the financing rate that would make the model agree with the market. Answers "what would I have to believe for this price to be right", in rate terms.
A rich contract has a positive basis and an implied repo above the curve (plus any borrow cost, which the implied repo absorbs). They cannot disagree about direction.
FuturesQuote
dataclass
¶
One expiry and the price the market puts on it.
Attributes:
| Name | Type | Description |
|---|---|---|
expiry |
Timestamp
|
Contract expiry date. |
market_price |
float | None
|
Traded price. None when only a theoretical value is wanted, in which case basis and implied repo are not reported for this pillar rather than being invented. |
label |
str
|
Optional contract code, for display. |
TermStructure
dataclass
¶
TermStructure(
underlying: str,
spot: float,
valuation_date: Timestamp,
quotes: list[FuturesQuote],
curve: RateCurve,
dividend_yield: float = 0.0,
borrow_cost: float = 0.0,
_sorted: list[FuturesQuote] = list(),
)
A strip of futures on one underlying, valued off one curve.
Fair values use continuous cost of carry, with each expiry financed at the
curve's zero rate for its ACT/365 time to expiry. Construction raises
CalculationError if there are no quotes, spot is not positive, or an
expiry is before valuation_date.
Attributes:
| Name | Type | Description |
|---|---|---|
underlying |
str
|
Identifier of the underlying. |
spot |
float
|
Spot price at valuation_date. |
valuation_date |
Timestamp
|
The date everything is measured from. |
quotes |
list[FuturesQuote]
|
The expiries, in any order; they are sorted on construction. |
curve |
RateCurve
|
Financing curve. A flat curve reproduces scalar-rate pricing exactly. |
dividend_yield |
float
|
Continuous dividend yield on the underlying. |
borrow_cost |
float
|
Continuous borrow spread. |
theoretical_prices ¶
Fair value at each expiry, off the curve.
Returns:
| Type | Description |
|---|---|
Series
|
pd.Series: Indexed by expiry date. |
basis ¶
Market minus theoretical, per expiry.
Positive means the contract trades rich to the model.
implied_repo ¶
The financing rate each quoted price implies.
(ln(F / S) + q * T) / T per expiry, using the strip's dividend
yield. The borrow cost is not subtracted, so it shows up inside the
implied rate.
NaN for expiries with no quote, and for an expiry today: a zero year fraction carries no information about a rate, and dividing by it would manufacture one.
Returns:
| Type | Description |
|---|---|
Series
|
pd.Series: Continuously compounded rates, indexed by expiry. |
sensitivity_grid ¶
sensitivity_grid(
spot: float,
tenors: list[float],
rates: list[float],
dividend_yield: float = 0.0,
borrow_cost: float = 0.0,
) -> pd.DataFrame
Fair value across a tenor × rate grid.
What a position is worth if the curve is somewhere else and expiry is further out: the two axes a Delta-1 desk actually moves along, laid out so the shape is visible at once rather than one revaluation at a time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spot
|
float
|
Spot price of the underlying. |
required |
tenors
|
list[float]
|
Times to expiry in years, one per row. |
required |
rates
|
list[float]
|
Continuously compounded financing rates, one per column. |
required |
dividend_yield
|
float
|
Continuous dividend yield. |
0.0
|
borrow_cost
|
float
|
Continuous borrow spread. |
0.0
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
pd.DataFrame: Fair values, tenors on the index and rates on the |
DataFrame
|
columns, both labelled with their values. |
Raises:
| Type | Description |
|---|---|
CalculationError
|
If either axis is empty. |
valuation ¶
A futures contract, a total return swap and a roll valued from their terms, with everything shown beside the price: the carry split into its parts, a sensitivity grid, a swap's financing schedule, its fair spread and its breakeven against futures.
The formulas are beacon.derivatives.pricing's; this module puts a curve's
rates and a contract's dates into them. Carry is shown as the price effect
of each rate, each priced with that rate alone. The parts do not sum to the
total exactly, because carry compounds rather than adds; the residual is
given rather than spread across them.
Carry
dataclass
¶
A futures price's carry: its total, the price effect of each rate on its own, and what compounding leaves between them.
FuturesValuation
dataclass
¶
FuturesValuation(
fair_value: float,
time_to_expiry: float,
financing_rate: float,
carry: Carry,
contract_value: float,
basis: float | None,
implied_repo: float | None,
sensitivity: DataFrame,
)
A futures contract valued from its terms.
Attributes:
| Name | Type | Description |
|---|---|---|
fair_value |
float
|
Its theoretical price. |
time_to_expiry |
float
|
In years. |
financing_rate |
float
|
The curve's rate to expiry. |
carry |
Carry
|
The carry, split by rate. |
contract_value |
float
|
The fair value times the multiplier and contracts. |
basis |
float | None
|
The market price less the fair value, when quoted. |
implied_repo |
float | None
|
The financing rate the market price implies. |
sensitivity |
DataFrame
|
Fair value across tenors (rows) and rates (columns). |
Accrual
dataclass
¶
Accrual(
start: Timestamp,
end: Timestamp,
days: int,
rate: float,
accrual_fraction: float,
amount: float,
)
One financing period of a swap.
SwapValuation
dataclass
¶
SwapValuation(
accrual_days: int,
accrual_fraction: float,
total_return_leg: float,
financing_leg: float,
present_value: float,
dv01: float,
fair_spread_bps: float | None,
schedule: list[Accrual],
breakeven: list[dict[str, float]] = list(),
)
A total return swap valued at a date.
Attributes:
| Name | Type | Description |
|---|---|---|
accrual_days |
int
|
Days since the last reset. |
accrual_fraction |
float
|
Their ACT/360 year fraction. |
total_return_leg |
float
|
What the underlying returned on the notional. |
financing_leg |
float
|
The financing accrued since the last reset. |
present_value |
float
|
The first less the second. |
dv01 |
float
|
The financing leg's change for a basis point. |
fair_spread_bps |
float | None
|
The spread at which the swap is worth nothing today; None when nothing has accrued. |
schedule |
list[Accrual]
|
Each financing period from the last reset to maturity. |
breakeven |
list[dict[str, float]]
|
The spread at which the swap matches each futures price. |
Roll
dataclass
¶
Rolling from one contract to the next, both priced off the same spot and curve: the carry roll rather than a market one.
years_between ¶
The year fraction from start to end, by calendar days.
tenor_of ¶
Year fraction to expiry, ACT/365, from two dates or as given.
Dates win when both are present: a tenor typed by hand can silently disagree with the expiry beside it.
Raises:
| Type | Description |
|---|---|
InvalidArgumentError
|
If the expiry is before the valuation date, no tenor can be found, or the tenor is negative. |
carry_of ¶
carry_of(
spot: float,
rate: float,
tenor: float,
dividend_yield: float,
borrow_cost: float,
fair_value: float,
) -> Carry
The carry from spot to fair_value, split by rate.
value_future ¶
value_future(
spot: float,
tenor: float,
curve: RateCurve,
dividend_yield: float = 0.0,
borrow_cost: float = 0.0,
dividends: list[tuple[float, float]] | None = None,
market_price: float | None = None,
contract_multiplier: float = 1.0,
contracts: float = 1.0,
grid_tenors: list[float] | None = None,
grid_rates: list[float] | None = None,
) -> FuturesValuation
A futures contract on spot, tenor years out, financed on curve.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spot
|
float
|
The underlying's price. |
required |
tenor
|
float
|
Years to expiry. |
required |
curve
|
RateCurve
|
The financing curve. |
required |
dividend_yield
|
float
|
A continuous yield, used without dividends. |
0.0
|
borrow_cost
|
float
|
The cost of borrowing the underlying. |
0.0
|
dividends
|
list[tuple[float, float]] | None
|
Discrete dividends as (years from now, amount); priced off them instead of the yield when given. |
None
|
market_price
|
float | None
|
A quote to measure the basis and implied repo from. |
None
|
contract_multiplier
|
float
|
Value per point. |
1.0
|
contracts
|
float
|
How many. |
1.0
|
grid_tenors
|
list[float] | None
|
The sensitivity grid's tenors; multiples of tenor when None. |
None
|
grid_rates
|
list[float] | None
|
Its rates; spreads around the curve's when None. |
None
|
value_swap ¶
value_swap(
swap: TotalReturnSwap,
valuation: Timestamp,
last_reset: Timestamp,
curve: RateCurve,
fixed_rate: float,
spot: float,
initial_price: float,
dividends: float = 0.0,
futures_prices: list[float] | None = None,
time_to_expiry: float | None = None,
dividend_yield: float = 0.0,
) -> SwapValuation
swap valued at valuation, its current period fixed at fixed_rate since last_reset and the later ones projected off curve.
financing_schedule ¶
financing_schedule(
swap: TotalReturnSwap,
valuation: Timestamp,
last_reset: Timestamp,
curve: RateCurve,
fixed_rate: float,
) -> list[Accrual]
Each financing period from the last reset to maturity.
The current period accrues at the rate fixed at its reset; each later one at the curve's forward rate over it, so a flat curve reproduces the fixed rate and a shaped one prices later periods off the later curve.
roll_between ¶
roll_between(
spot: float,
valuation: Timestamp,
front_expiry: Timestamp,
back_expiry: Timestamp,
curve: RateCurve,
dividend_yield: float = 0.0,
) -> Roll
The roll from the front_expiry contract to the back_expiry one.
Raises:
| Type | Description |
|---|---|
InvalidArgumentError
|
If the back expiry is not after the front. |