Valuing a CLP swap under USD collateral¶
Consider a five-year swap that receives 5.5% fixed and pays ICP floating on 935 million CLP, with USD collateral. Its value depends on the ICP projection curve, a USD-collateralized CLP discount curve and spot FX. We value the trade in USD, then reconstruct the result from its CLP cashflows.
The local loader supplies the illustrative USD/CLP bootstrap market dated 24 February 2026. Spot is 935 CLP per USD, so the notional equals USD 1 million at inception. Run the cells in order after the shared setup.
Computational study. Canonical notebook · Companion files and setup. Download this notebook.
This page renders saved outputs; the documentation build does not execute it. Run the canonical notebook from its own directory with the checkout-built binding to reproduce the computation. Each study records its market inputs and numerical assumptions.
import pandas as pd
import quantsupport as qs
from market_data import load_currency_market
market = load_currency_market()
ref = market.quotes.reference_date
print("Market reference date:", ref)
pd.DataFrame(
{"configured_curve": [curve.to_dict()["market_index"] for curve in market.curves]}
)
Market reference date: 2026-02-24
| configured_curve | |
|---|---|
| 0 | SOFR |
| 1 | {'Collateral': ['CLP', 'USD']} |
| 2 | ICP |
FX orientation¶
FxStore.add(base, quote, rate) stores quote-currency units per base unit.
We enter USD-to-CLP spot as 935, meaning one USD buys 935 CLP. Reverse lookup
returns 1 / 935, so 9,350,000 CLP converts to 10,000 USD.
The first currency in the FX pair and the context’s valuation base currency serve different roles. Here the CSA policy selects USD for the valuation, while both contractual legs pay CLP.
fx = qs.FxStore()
fx.add(qs.Currency.USD, qs.Currency.CLP, 935.0)
clp_to_usd = fx.rate(qs.Currency.CLP, qs.Currency.USD)
usd_to_clp = fx.rate(qs.Currency.USD, qs.Currency.CLP)
pd.DataFrame(
[
{
"from": "CLP",
"to": "USD",
"amount": 9_350_000,
"fx_rate": clp_to_usd,
"converted_amount": 9_350_000 * clp_to_usd,
},
{
"from": "USD",
"to": "CLP",
"amount": 10_000,
"fx_rate": usd_to_clp,
"converted_amount": 10_000 * usd_to_clp,
},
{
"from": "USD",
"to": "USD",
"amount": 10_000,
"fx_rate": fx.rate(qs.Currency.USD, qs.Currency.USD),
"converted_amount": 10_000 * fx.rate(qs.Currency.USD, qs.Currency.USD),
},
]
)
| from | to | amount | fx_rate | converted_amount | |
|---|---|---|---|---|---|
| 0 | CLP | USD | 9350000 | 0.00107 | 10000.0 |
| 1 | USD | CLP | 10000 | 935.00000 | 9350000.0 |
| 2 | USD | USD | 10000 | 1.00000 | 10000.0 |
Keep projection, collateral, and reporting roles explicit¶
We receive a 5.5% fixed coupon and pay ICP floating coupons on a five-year swap with 935 million CLP notional, equivalent to USD 1 million at today’s spot. Both contractual legs pay CLP; matching principal flows cancel between them. The USD CSA uses SOFR as its remuneration index and selects USD as the context’s base currency.
Market object |
Role |
|---|---|
|
Project the CLP floating coupons |
|
USD collateral remuneration and bootstrap dependency |
|
Discount CLP cashflows under USD collateral |
|
Convert CLP amounts into USD at spot |
The collateral-adjusted curve is built from FX-forward and cross-currency-swap quotes. It includes the cross-currency basis. Discounting on the ICP projection curve instead would change the collateral assumptions of the valuation.
collateral_index = qs.MarketIndex.collateral(qs.Currency.CLP, qs.Currency.USD)
swap = qs.Swap(
identifier="CLP-SWAP-USD-CSA-5Y",
start_date=ref,
maturity_date=ref + "5Y",
notional=935_000_000,
fixed_rate=0.055,
currency=qs.Currency.CLP,
market_index=qs.MarketIndex.ICP,
fixed_leg_frequency=qs.Frequency.Semiannual,
floating_leg_frequency=qs.Frequency.Semiannual,
)
trade = qs.Trade(swap, ref, qs.Side.LongReceive)
Let the native pricer convert into the base currency¶
Pass both the FX store and the USD CSA policy to PricingContext. Inside
with context:, valuation requests build the required curves and their dependencies. For this swap, the
policy makes result.price a USD PV, although result.cashflows retains
the original CLP payment amounts.
For each payment date, the pricer applies:
Here s_i is +1 for the received fixed leg and -1 for the paid floating leg.
The cashflow table already includes these leg signs and reverses initial
disbursements: for a Swap, leg 0 is fixed and leg 1 is floating. The following
calculation applies discount factors and the FX rate to reconcile the native PV.
All curve queries stay inside the active context; the numeric table can be
used after it closes.
context = qs.PricingContext(
quotes=market.quotes, curves=market.curves, fx=fx, csa_policy=market.csa_policy
)
with context:
result = context.evaluate(trade, [qs.Request.Value, qs.Request.Cashflows])
base_currency = context.base_currency
conversion_rate = context.fx.rate(swap.currency, base_currency)
discount_curve = context.curve(collateral_index)
cashflows = result.cashflows.copy()
cashflows["leg"] = cashflows["leg_index"].map(
{0: "receive fixed", 1: "pay floating"}
)
cashflows["signed_amount_clp"] = cashflows["amount"]
cashflows["discount_factor"] = cashflows["payment_date"].map(
discount_curve.discount_factor
)
cashflows["pv_clp"] = cashflows["signed_amount_clp"] * cashflows["discount_factor"]
cashflows["fx_clp_to_usd"] = conversion_rate
cashflows["pv_usd"] = cashflows["pv_clp"] * conversion_rate
cashflows.sort_values(["payment_date", "leg_index"])[
[
"payment_date",
"leg",
"currency",
"signed_amount_clp",
"discount_factor",
"fx_clp_to_usd",
"pv_usd",
]
].head(8)
| payment_date | leg | currency | signed_amount_clp | discount_factor | fx_clp_to_usd | pv_usd | |
|---|---|---|---|---|---|---|---|
| 0 | 2026-02-24 | receive fixed | CLP | -9.350000e+08 | 1.000000 | 0.00107 | -1000000.000000 |
| 12 | 2026-02-24 | pay floating | CLP | 9.350000e+08 | 1.000000 | 0.00107 | 1000000.000000 |
| 2 | 2026-08-24 | receive fixed | CLP | 2.585535e+07 | 0.963357 | 0.00107 | 26639.504550 |
| 14 | 2026-08-24 | pay floating | CLP | -2.327727e+07 | 0.963357 | 0.00107 | -23983.239411 |
| 3 | 2027-02-24 | receive fixed | CLP | 2.628389e+07 | 0.950521 | 0.00107 | 26720.201442 |
| 15 | 2027-02-24 | pay floating | CLP | -2.216951e+07 | 0.950521 | 0.00107 | -22537.521210 |
| 4 | 2027-08-24 | receive fixed | CLP | 2.585535e+07 | 0.929084 | 0.00107 | 25691.763794 |
| 16 | 2027-08-24 | pay floating | CLP | -2.112135e+07 | 0.929084 | 0.00107 | -20987.713675 |
Reconcile the position PV in both units¶
Summing the signed, discounted payments gives this USD-collateralized position expressed in CLP. Multiplying that amount by CLP-to-USD spot produces the native USD value. This is the same collateral agreement expressed in two currencies; valuing the swap under a CLP CSA would require a different discounting policy.
local_pv_clp = cashflows["pv_clp"].sum()
reconstructed_pv_usd = cashflows["pv_usd"].sum()
pd.DataFrame(
[
{
"measure": "PV expressed in CLP under USD collateral",
"currency": "CLP",
"value": local_pv_clp,
},
{
"measure": "Converted cashflow PV",
"currency": "USD",
"value": reconstructed_pv_usd,
},
{
"measure": "Native result.price",
"currency": str(base_currency),
"value": result.price,
},
{
"measure": "Reconciliation difference",
"currency": "USD",
"value": reconstructed_pv_usd - result.price,
},
]
)
| measure | currency | value | |
|---|---|---|---|
| 0 | PV expressed in CLP under USD collateral | CLP | 4.790493e+07 |
| 1 | Converted cashflow PV | USD | 5.123522e+04 |
| 2 | Native result.price | USD | 5.123522e+04 |
| 3 | Reconciliation difference | USD | -7.275958e-12 |
Principal exchanges¶
The matching fixed and floating principal exchanges have opposite signs and cancel at each date. We check that cancellation and isolate the coupon PV. Expressing the result in CLP or USD retains the same USD collateral agreement.
principal_flows = cashflows.loc[cashflows["type"].isin(["Disbursement", "Redemption"])]
principal_by_date = principal_flows.groupby("payment_date")["signed_amount_clp"].sum()
coupon_pv_usd = cashflows.loc[
~cashflows["type"].isin(["Disbursement", "Redemption"]), "pv_usd"
].sum()
print(f"USD-collateralized PV: CLP {local_pv_clp:,.2f} = USD {result.price:,.2f}.")
print(f"At {usd_to_clp:g} CLP per USD, one CLP is worth USD {conversion_rate:.9f}.")
print(f"Net principal PV: USD {principal_flows['pv_usd'].sum():.3e}.")
USD-collateralized PV: CLP 47,904,926.39 = USD 51,235.22.
At 935 CLP per USD, one CLP is worth USD 0.001069519.
Net principal PV: USD 0.000e+00.
The native result.price is already in USD: use it directly in a USD portfolio
report. Applying CLP-to-USD FX to it again would convert twice. Retain the CLP
currency labels when displaying contractual cashflows, and add separate USD
columns when presenting their converted values.
Continue with portfolio valuation and risk for aggregation, or valuation catalog for the analytics available on other contracts.