Repricing Overnight and Tomorrow-Next FX Forward Points with QuantLib
Summary
The document presents a QuantLib Python question about building an FX swap curve from overnight and tomorrow-next quotes and reproducing the input forward points. It supplies a setup with a trade date, spot settlement lag, spot rate, collateral curve, several short-dated FX swap quotes, and corresponding rate helpers. The curve is then constructed as a piecewise linear zero curve.
The example computes a spot-lag adjustment from the ratio of discount factors on the FX curve and collateral curve, then uses that adjustment with the spot rate and curve discount factors to calculate implied forward points at curve nodes. The author reports that this adjustment returns the quoted points, but asks whether the initial pricing difficulty is a bug or a misunderstanding. No accepted answer, independent validation, or explanation of conventions is included, so the document is a concrete calibration and repricing example rather than a resolved guide. Its usefulness depends on checking date, settlement, collateral, and quote conventions in the reader’s own setup.
Key ideas
- The example builds an FX swap curve from short-dated ON and TN quotes using QuantLib rate helpers.
- It applies a spot settlement adjustment derived from collateral and FX curve discount factors.
- Implied forward points are recovered from the adjusted spot rate and curve discount factors.
- The question does not include a definitive explanation or independent validation of the approach.
Tags
Full text
# Pricing ON and TN FX Fwd Points using QuantLib Python
# Pricing ON and TN FX Fwd Points using QuantLib Python
I'm able to use FxSwapRateHelper to build FX Swap curve with ON, TN tenor without error. However I'm struggled with reprice inputted ON/TN fwd points. Is this a bug or am I missing something please?
```
# Trade date setup
trade_date = ql.Date(3, 1, 2025)
spot_lag=2
ql.Settings.instance().evaluationDate = trade_date
calendar = ql.UnitedStates(0)
spot_sett=calendar.advance(trade_date,spot_lag,ql.Days)
business_convention_base = ql.ModifiedFollowing
end_of_month = False
# Spot FX rate
spot_rate = ql.SimpleQuote(1.2000)
spot_handle = ql.QuoteHandle(spot_rate)
# Collateral curve
collateral_curve = ql.YieldTermStructureHandle(ql.FlatForward(trade_date, ql.QuoteHandle(ql.SimpleQuote(0.03)), ql.Actual360()))
# FX swap fwd point quotes
fxswap_quotes = [ql.SimpleQuote(0.004), ql.SimpleQuote(0.01), ql.SimpleQuote(0.027),ql.SimpleQuote(0.189)]
fxswap_handles = [ql.QuoteHandle(q) for q in fxswap_quotes]
# Spot lag and maturities
dffxswapsFXspotlag = [0,1,2,2]
dffxswapsmaturity = [ql.Period(1, ql.Days), ql.Period(1, ql.Days), ql.Period(1, ql.Days),ql.Period(1, ql.Weeks)]
# Create FxSwapRateHelper objects
fxSwapHelpers = [
ql.FxSwapRateHelper(
quote,
spot_handle,
maturity,
int(spot_lag),
calendar,
business_convention_base,
end_of_month,
True, # Base currency collateralized
collateral_curve
)
for spot_lag, quote, maturity in zip(dffxswapsFXspotlag, fxswap_handles, dffxswapsmaturity)
]
curve =ql.PiecewiseLinearZero(0,calendar, fxSwapHelpers, ql.Actual360())
# spot lag rate adj gives back correct inputted points
spot_lag_adj=curve.discount(spot_sett)/collateral_curve.discount(spot_sett)
for i,j in enumerate(curve.nodes()):
print((spot_lag_adj*spot_handle.value()*collateral_curve.discount(curve.nodes()[i][0])/curve.discount(curve.nodes()[i][0]))-spot_handle.value())
```Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.