Rateslib
repository·main·Indexed 43 days ago
https://github.com/attack68/rateslibA high-performance Python library for professional fixed income analysis, version 2.7.1. It provides tools for interest rate volatility pricing, automatic differentiation using dual numbers, calendar and tenor manipulations, and curve calibration and composition via the Solver and CompositeCurve classes.
What's inside Rateslib
- Rateslib is a state-of-the-art fixed income library for Python. It is designed to provide advanced, flexible, and efficient fixed income analysis through a high-level, well-documented API. The library's architecture and object interactions are modeled after the requirements of multi-disciplined fixed income teams in global investment banks.
Understand IR Volatility Time to Expiry
mainIn
rateslib, Interest Rate (IR) volatility pricing objects (inheriting from_BaseIRSmile) calculate a natural measure of time to expiry ($t$) based on the difference between the instrument'sexpiryand the object'seval_date.By default, time to expiry is measured in Act365 calendar days using the formula:
$$t = \frac{days(expiry - eval\ date)}{365}$$
When a volatility value is yielded for a specific strike, it is assumed to be associated with this calculated time to expiry. This pair $(t, \sigma)$ is then used directly in pricing models like Black76 or Bachelier.
Licensing terms for Rateslib
mainRateslib is not open source. It is released under Dual Licensing Terms:
- Source-Available Non-Commercial Licence: For non-commercial use.
- Commercial Subscription Licence: Required for commercial use.
If you intend to use this library for commercial purposes, you must obtain a paid licence. Detailed licensing information can be found at rateslib.com/py/en/latest/i_licence.html.
Get started with Rateslib
mainTo begin using Rateslib, you should consult the official documentation for comprehensive guides and API references.
Documentation URL: https://rateslib.com/py/
Use weights to handle time interpolation in Cubes
mainInstead of applying
time_scalarto individual smiles,Cubes(likeIRSabrCubeorIRSplineCube) use aweightsargument to handle time interpolation between chosenexpiries.By passing a
pandas.Seriesto theweightsargument, you can apportion volatility to specific dates. This is commonly used to adjust for business days vs. calendar days.Note: It is assumed that on every given expiry, the time scalar equals one and the Cube is calibrated to market instruments.
from rateslib import IRSabrCube, calendars from pandas import Series from datetime import datetime as dt nyc = calendars.get("nyc") # Define weights for specific dates (e.g., setting non-business days to 0.0) weights = Series( index=[_ for _ in nyc.cal_date_range(dt(2001, 1, 1), dt(2001, 8, 1)) if nyc.is_non_bus_day(_)], data=0.0 ) irsc2 = IRSabrCube( eval_date=dt(2001, 1, 1), expiries=[dt(2001, 2, 1), dt(2001, 3, 1), dt(2001, 4, 1), dt(2001, 7, 1)], tenors=["1y"], alpha=0.35, beta=0.5, rho=-0.05, nu=0.45, irs_series="usd_irs", weights=weights, )Perform operations on CompositeCurves
mainBecause
CompositeCurveis composed of individual curves, it inherits the ability to perform transformation operations. You can call.shift(),.roll(), and.translate()directly on aCompositeCurveinstance, and the operation will be applied to the composite structure.Supported operations:
.shift(n).roll(duration).translate(date)
# Assuming composite_curve is already defined # Shift the entire composite structure shifted_comp = composite_curve.shift(50) # Roll the entire composite structure rolled_comp = composite_curve.roll("30d") # Translate the entire composite structure translated_comp = composite_curve.translate(dt(2022, 5, 1)) # Get rate from the transformed composite rate = translated_comp.rate(dt(2022, 6, 1), "1d")Combining multiple FXRates in FXForwards
mainThe
FXForwardsconstructor can accept a list ofFXRatesobjects (fx_rates=[fxr1, fxr2, ...]) to handle different settlement dates.Important Constraints:
- Separable/Acyclic Systems: The system of curves and rates must be solvable. If the dependencies between rates and curves form a cycle that cannot be resolved, the system will fail.
- Cyclic Systems: If you encounter cyclic dependencies, you may need to restructure the input by splitting the
FXRatesinto more granular objects (e.g., instead of one object with multiple rates, use multipleFXRatesobjects with single rates) to ensure the dependency graph is acyclic. - Unsolvable Systems: If the provided curves and rates do not provide enough information to bridge the required currency pairs, the system will be unsolvable.
# Combining multiple FXRates with different settlement dates fxr1 = FXRates({"eurusd": 1.05}, settlement=dt(2022, 1, 3)) fxr2 = FXRates({"usdcad": 1.1}, settlement=dt(2022, 1, 2)) fxf = FXForwards( fx_rates=[fxr1, fxr2], fx_curves={ ... } ) # The system resolves the rate for the target date across the provided components rate = fxf.rate("eurcad", dt(2022, 2, 1))Inject turns into spline curves using CompositeCurve
mainTo add specific 'turns' or local features to a smooth spline curve, use a
CompositeCurve. This involves creating aturn_curve(representing the local feature) and acubic_curve(the base spline), then combining them.When using
CompositeCurvein aSolver, ensure you include all constituent curves in thecurveslist and provide parameter guesses for all of them.turn_curve = Curve({ dt(2022, 12, 1): 1.0, dt(2022, 12, 31): 1.0, dt(2023, 1, 1): 1.0, dt(2023, 2, 1): 1.0, }, interpolation="log_linear") cubic_curve = Curve({ dt(2022, 12, 1): 1.0, dt(2022, 12, 21): 1.0, dt(2023, 1, 11): 1.0, dt(2023, 2, 1): 1.0, }, t = [ dt(2022, 12, 1), dt(2022, 12, 1), dt(2022, 12, 1), dt(2022, 12, 1), dt(2022, 12, 21), dt(2023, 1, 11), dt(2023, 2, 1), dt(2023, 2, 1), dt(2023, 2, 1), dt(2023, 2, 1), ]) composite_curve = CompositeCurve([turn_curve, cubic_curve])Optimize fixings calculation performance
mainTo improve the performance of
fixings_tablecalls, you can use theapproximate=Trueflag. Additionally, you can control curve caching behavior viadefaults.curve_caching.float_period.fixings_table(curve, approximate=True): Uses an approximation method to speed up calculation.defaults.curve_caching = False: Disables the global curve caching mechanism.
from rateslib import defaults # Disable caching defaults.curve_caching = False # Use approximation for speed float_period.fixings_table(curve, approximate=True)Retrieve and construct calendars
mainYou can retrieve calendars using
get_calendar()which fetches them from a hash table. You can also construct calendars manually using theCalclass by providing a list ofholidaysand aweek_mask. For multiple calendars, useUnionCalto combine them. To make a specific calendar configuration easily accessible viaget_calendar(), you can assign it todefaults.calendars.from rateslib import * # Get a calendar by code cal = get_calendar("ldn") # Construct a Cal directly cal = Cal(holidays=holidays_list, week_mask=[5,6]) # Get a parsed NamedCal (e.g., combining London and Target) cal = get_calendar("ldn,tgt") # Combine multiple calendars into a UnionCal c1 = Cal(holidays=get_calendar("ldn", named=False).holidays, week_mask=[5,6]) c2 = Cal(holidays=get_calendar("tgt", named=False).holidays, week_mask=[5,6]) u = UnionCal([c1, c2]) # Register a custom calendar to the defaults for easy retrieval defaults.calendars["ldn,tgt"] = get_calendar("ldn,tgt") cal = get_calendar("ldn,tgt")Calibrate an FX SABR Smile to market option data
mainYou can calibrate a volatility smile (e.g.,
FXSabrSmile) using aSolver. The solver takes a list ofpre_solvers(to handle underlying curve calibration first), the targetcurves(the smile), and a list of market instruments such asFXStraddle,FXRiskReversal, andFXBrokerFly.Common
option_argsfor calibration include:pair: The FX pair (e.g.,"eurusd").expiry: The option expiry date.calendar: Calendar string (e.g.,"tgt|fed").delta_type: Type of delta used for strikes (e.g.,"spot"or"forward").curves: The list of curves involved in the calculation.vol: The name of the volatility surface/smile to use.
smile = FXSabrSmile( nodes={"alpha": 0.05, "beta": 1.0, "rho": 0.01, "nu": 0.03}, eval_date=dt(2024, 5, 7), expiry=dt(2024, 5, 28), id="smile", pair="eurusd", ) option_args = dict( pair="eurusd", expiry=dt(2024, 5, 28), calendar="tgt|fed", delta_type="spot", curves=[None, "eurusd", None, "usd"], vol="smile", ) solver = Solver( pre_solvers=[pre_solver], curves=[smile], instruments=[ FXStraddle(strike="atm_delta", **option_args), FXRiskReversal(strike=("-25d", "25d"), **option_args), FXRiskReversal(strike=("-10d", "10d"), **option_args), FXBrokerFly(strike=(("-25d", "25d"), "atm_delta"), **option_args), FXBrokerFly(strike=(("-10d", "10d"), "atm_delta"), **option_args), ], s=[5.493, -0.157, -0.289, 0.071, 0.238], fx=fxf, id="smile", )Set up an FX Forward market and solve curves to market
mainTo model an FX market, you must define base currency
Curveobjects, anFXRatesobject for spot rates, and anFXForwardsobject to combine them. You can then use theSolverclass to calibrate these curves to market instruments likeIRS(Interest Rate Swaps) andFXSwap.# Define Curves usd = Curve({dt(2024, 5, 7): 1.0, dt(2024, 5, 30): 1.0}, calendar="nyc", id="usd") eur = Curve({dt(2024, 5, 7): 1.0, dt(2024, 5, 30): 1.0}, calendar="tgt", id="eur") eurusd = Curve({dt(2024, 5, 7): 1.0, dt(2024, 5, 30): 1.0}, id="eurusd") # Create an FX Forward market spot = dt(2024, 5, 9) fxr = FXRates({"eurusd": 1.0760}, settlement=spot) fxf = FXForwards( fx_rates=fxr, fx_curves={"eureur": eur, "usdusd": usd, "eurusd": eurusd}, ) # Solve the Curves to market pre_solver = Solver( curves=[eur, eurusd, usd], instruments=[ IRS(spot, "3W", spec="eur_irs", curves="eur"), IRS(spot, "3W", spec="usd_irs", curves="usd"), FXSwap(spot, "3W", pair="eurusd", curves=[None, "eurusd", None, "usd"]), ], s=[3.90, 5.32, 8.85], fx=fxf, id="fxf", )