Non-Deliverable Instruments
Non-deliverable (ND) instruments settle in a convertible currency rather than the restricted currency where cashflows accrue. This is common for emerging market currencies (BRL, INR, KRW, CNY, TWD) where currency controls limit deliverability.
Vade provides three ND instrument types:
- NDF -- Non-Deliverable Forward (single FX net settlement)
- NDIRS -- Non-Deliverable Interest Rate Swap (per-period FX conversion)
- NDXCS -- Non-Deliverable Cross-Currency Swap (ND leg with FX conversion)
All three share a unified FX fixing mechanism: a fx_fixings dict mapping
dates to known FXRates, with IRP-implied forward fallback for missing dates.
Setup
Build USD and BRL curves for the examples:
usd_curve = DiscountCurve(
{
datetime.date(2025, 6, 16): 1.0,
datetime.date(2026, 6, 16): 0.9615,
datetime.date(2027, 6, 16): 0.9246,
datetime.date(2028, 6, 16): 0.8890,
},
interpolation="log_linear",
convention="act360",
id="usd",
)
brl_curve = DiscountCurve(
{
datetime.date(2025, 6, 16): 1.0,
datetime.date(2026, 6, 16): 0.8929,
datetime.date(2027, 6, 16): 0.7972,
datetime.date(2028, 6, 16): 0.7118,
},
interpolation="log_linear",
convention="act360",
id="brl",
)
fxr = FXRates({"usdbrl": 5.20}, settlement=datetime.date(2025, 6, 16))NDF -- Non-Deliverable Forward
An NDF is the simplest ND instrument: a single forward FX exchange that settles as a net cash payment in the settlement currency.
Construction
ndf = NDF(
spec="usdbrl_ndf",
effective=datetime.date(2025, 6, 16),
delivery=datetime.date(2025, 12, 16),
notional=1_000_000.0,
contracted_rate=5.25,
)Pricing
The fair rate is the IRP-implied forward. NPV is the discounted net settlement:
fair_rate = ndf.rate(usd_curve, brl_curve, fxr)
npv = ndf.npv(usd_curve, brl_curve, fxr)
assert abs(float(fair_rate)) < 10
assert abs(float(npv)) < 1e8Cashflows
cf = ndf.cashflows(usd_curve, brl_curve, fxr)
assert len(cf) >= 1Spec-Based Construction
Five market convention specs are available:
for spec in ["usdbrl_ndf", "usdcny_ndf", "usdinr_ndf", "usdkrw_ndf", "usdtwd_ndf"]:
ndf_i = NDF(spec=spec, effective=datetime.date(2025, 6, 16),
delivery=datetime.date(2025, 12, 16), notional=1e6,
contracted_rate=5.25)
assert ndf_i is not NoneNDIRS -- Non-Deliverable Interest Rate Swap
An NDIRS is an IRS where both legs accrue in a restricted currency but settle in a convertible currency. Each period's cashflow is converted via an FX rate (from fixings or IRP-implied forward).
Construction
ndirs = NDIRS(
spec="usdbrl_ndirs",
effective=datetime.date(2025, 6, 16),
termination="2Y",
fixed_rate=10.0,
notional=1_000_000.0,
)3-Curve Pricing
NDIRS uses three curves:
- Settlement discount (USD) -- for NPV discounting
- Restricted forecast (BRL) -- for floating rate projection
- Restricted discount (BRL) -- for IRP forward derivation
par_rate = ndirs.rate(curves=[usd_curve, brl_curve, brl_curve], fx_rates=fxr)
npv = ndirs.npv(curves=[usd_curve, brl_curve, brl_curve], fx_rates=fxr)
assert 0 < float(par_rate) < 30
assert abs(float(npv)) < 1e8Partial FX Fixings
For past periods with known FX fixings, pass a date-keyed dict:
ndirs_fix = NDIRS(
spec="usdbrl_ndirs",
effective=datetime.date(2025, 6, 16),
termination="2Y",
fixed_rate=10.0,
fx_fixings={datetime.date(2025, 12, 16): 5.35},
)
npv_fix = ndirs_fix.npv(curves=[usd_curve, brl_curve, brl_curve], fx_rates=fxr)
assert abs(float(npv_fix)) < 1e8Cashflows with Settlement Columns
NDIRS cashflows include FX rate and settlement amount columns:
cf = ndirs.cashflows(curves=[usd_curve, brl_curve, brl_curve], fx_rates=fxr)
assert len(cf) > 0NDXCS -- Non-Deliverable Cross-Currency Swap
An NDXCS is a cross-currency swap where one leg is non-deliverable. Cashflows on the ND leg are converted via per-period FX fixings and settled in the convertible currency. Supports notional exchanges and MTM resets.
Construction
ndxcs = NDXCS(
effective=datetime.date(2025, 6, 16),
termination="2Y",
leg1_currency="USD",
leg2_currency="BRL",
settlement_currency="usd",
nd_leg=2,
pair="usdbrl",
leg1_notional=1_000_000.0,
leg2_notional=5_200_000.0,
initial_fx_rate=5.2,
frequency="q",
convention="act360",
notional_exchange=True,
)Pricing
NDXCS uses 4 curves (leg1 disc/forecast, leg2 disc/forecast) plus FXRates:
rate = ndxcs.rate(usd_curve, usd_curve, brl_curve, brl_curve, fxr)
npv = ndxcs.npv(usd_curve, usd_curve, brl_curve, brl_curve, fxr)
assert abs(float(rate)) < 500
assert abs(float(npv)) < 1e8Spec-Based Construction
Five market convention specs are available:
ndxcs_spec = NDXCS(
spec="usdbrl_ndxcs",
effective=datetime.date(2025, 6, 16),
termination="1Y",
leg1_notional=1_000_000.0,
leg2_notional=5_200_000.0,
initial_fx_rate=5.2,
)
assert ndxcs_spec is not NoneFX Fixings for Notional Exchanges
The same fx_fixings dict covers period cashflows, notional exchanges, and
MTM resets. Pass a known fixing for the exchange date:
ndxcs_fix = NDXCS(
effective=datetime.date(2025, 6, 16),
termination="1Y",
leg1_currency="USD",
leg2_currency="BRL",
settlement_currency="usd",
nd_leg=2,
pair="usdbrl",
leg1_notional=1_000_000.0,
leg2_notional=5_200_000.0,
initial_fx_rate=5.2,
fx_fixings={datetime.date(2025, 6, 16): 5.20},
)
npv_fix = ndxcs_fix.npv(usd_curve, usd_curve, brl_curve, brl_curve, fxr)
assert abs(float(npv_fix)) < 1e8Cashflows
cf = ndxcs.cashflows(usd_curve, usd_curve, brl_curve, brl_curve, fxr)
assert len(cf) > 0JSON Serialization
All ND instruments support JSON serialization:
json_str = ndf.to_json()
assert isinstance(json_str, str) and len(json_str) > 10
ndf_rt = NDF.from_json(json_str)
npv_rt = ndf_rt.npv(usd_curve, brl_curve, fxr)
assert abs(float(ndf.npv(usd_curve, brl_curve, fxr)) - float(npv_rt)) < 1e-6NDIRS also supports round-trip serialization:
ndirs_json = ndirs.to_json()
ndirs_rt = NDIRS.from_json(ndirs_json)
npv_orig = ndirs.npv(curves=[usd_curve, brl_curve, brl_curve], fx_rates=fxr)
npv_rt = ndirs_rt.npv(curves=[usd_curve, brl_curve, brl_curve], fx_rates=fxr)
assert abs(float(npv_orig) - float(npv_rt)) < 1e-6AD Support and Risk
All ND instruments return AD-enabled types for automatic differentiation. FXRates creates Dual variables, enabling delta and gamma computation:
rate_val = ndf.rate(usd_curve, brl_curve, fxr)
# rate_val is Dual when FXRates uses AD -- float(rate_val) extracts the real part
assert math.isfinite(float(rate_val))Cross-Currency Swaps
A [CrossCurrencySwap](../../api/instruments.md#xcs) (XCS) exchanges floating rate
Financing
Financing instruments fund positions through secured lending, structured products, and synthetic exposure. They form the plumbing of fixed income markets -- repos provide short-term funding against collateral, structured products (CLOs, CDOs, ABS) redistribute credit risk across tranches, and total return swaps deliver economic exposure without ownership transfer. Vade's financing module is planned for future development.