An interest rate swap allows two parties to exchange interest payment obligations, typically swapping fixed-rate payments for floating-rate payments. The floating rate is a benchmark, such as the Secured Overnight Financing Rate (SOFR), plus a spread. Companies with different credit ratings face different borrowing costs in fixed and floating rate markets. When the spread between their rates differs across markets, both parties can benefit by borrowing where they have a comparative advantage and then swapping their obligations.
How the swap works
Consider two companies seeking to borrow funds:
AAA Corp has excellent credit and can borrow at lower rates in both markets
BBB Corp has weaker credit and faces higher borrowing costs
// STAGE 1: Calculate total gain from the input rates.// This breaks the circular dependency.gains = {const fixedSpread = bbbRates.fixed- aaaFixedRate;const floatingSpread = bbbRates.floating- aaaFloatingRate;const reversedSwap = floatingSpread > fixedSpread;const totalGainBps =Math.abs(fixedSpread - floatingSpread) *100;return { fixedSpread, floatingSpread, reversedSwap, totalGainBps };}
// STAGE 3: Final Views. // This block takes all inputs and the calculated gains and produces all the HTML views.views = {// Deconstruct the gains objectconst { fixedSpread, floatingSpread, reversedSwap, totalGainBps } = gains;// Formattersconst bpsFormat = d3.format(",.0f");const rateFormat = d3.format(".2f");// Renders a spread over the floating benchmark with the correct sign,// e.g. -0.1 -> "Floating − 0.10%" and 0.6 -> "Floating + 0.60%".const floatLabel = (s) => s <0?`Floating − ${rateFormat(Math.abs(s))}%`:`Floating + ${rateFormat(s)}%`;// Intermediary Gainconst intermediaryGainBps =Math.max(0, totalGainBps - aaaGainBps - bbbGainBps);// --- DYNAMIC TEXT ---const introText = reversedSwap? htl.html`<p>While AAA Corp has an absolute advantage in both markets, the key insight is that the rate differential between the companies may differ across fixed and floating markets. In this case, the comparative advantage is reversed. We will assume AAA Corp wishes to borrow at a <b>fixed rate</b> and BBB Corp wishes to borrow at a <b>floating rate</b> to take advantage of the situation. The difference in spreads creates an arbitrage opportunity that both parties can exploit through a swap arrangement to achieve their desired financing at a lower cost.</p>`: htl.html`<p>While AAA Corp has an absolute advantage in both markets, the key insight is that the rate differential between the companies may differ across fixed and floating markets. This example assumes AAA Corp wishes to borrow at a <b>floating rate</b>, while BBB Corp wishes to borrow at a <b>fixed rate</b>. The difference in spreads creates an arbitrage opportunity that both parties can exploit through a swap arrangement to achieve their desired financing at a lower cost.</p>`;const mechanicsText = reversedSwap? htl.html`<ol><li><b>AAA Corp</b> borrows at the <b>floating rate</b>...</li><li><b>BBB Corp</b> borrows at the <b>fixed rate</b>...</li><li>Through the swap, AAA Corp pays fixed to the intermediary and receives floating, converting its floating-rate loan into a net <b>fixed obligation</b> at an improved rate.</li><li>BBB Corp pays floating to the intermediary and receives fixed, ending up with a net <b>floating obligation</b> at an improved rate.</li><li>The financial intermediary captures the difference...</li></ol>`: htl.html`<ol><li><b>AAA Corp</b> borrows at the <b>fixed rate</b>...</li><li><b>BBB Corp</b> borrows at the <b>floating rate</b>...</li><li>Through the swap, AAA Corp pays floating to the intermediary and receives fixed, ending up with a net <b>floating obligation</b> at an improved rate.</li><li>BBB Corp pays fixed to the intermediary and receives floating, converting its floating-rate loan into a net <b>fixed obligation</b> at an improved rate.</li><li>The financial intermediary captures the difference...</li></ol>`;// --- DYNAMIC UI COMPONENTS ---const gainDisplay = (() => {if (totalGainBps <=0.001) {return htl.html`<div class="no-gain-card"><div class="no-gain-header">No Gain from Swap</div><div class="no-gain-value">${bpsFormat(totalGainBps)} basis points</div><p class="no-gain-explanation">There is no arbitrage opportunity because the fixed-rate and floating-rate spreads are identical.</p></div>`; }const gainExplanation = reversedSwap ?`This gain arises because the difference in floating-rate spreads (${rateFormat(floatingSpread)}%) exceeds the difference in fixed-rate spreads (${rateFormat(fixedSpread)}%).`:`This gain arises because the difference in fixed-rate spreads (${rateFormat(fixedSpread)}%) exceeds the difference in floating-rate spreads (${rateFormat(floatingSpread)}%).`;return htl.html`<div class="gain-card"><div class="gain-header">Total Gain from Swap</div><div class="gain-value">${bpsFormat(totalGainBps)} basis points</div><p class="gain-explanation">${gainExplanation}</p></div>`; })();const allocationWarning = (totalGainBps >0&& aaaGainBps + bbbGainBps > totalGainBps)? htl.html`<div class="warning-card">⚠️ Total allocated gains (${bpsFormat(aaaGainBps + bbbGainBps)} bps) exceed available gain (${bpsFormat(totalGainBps)} bps). Intermediary gain is ${bpsFormat(intermediaryGainBps)} bps.</div>`:null;const resultsTable = (() => {let aaaEffectiveRate, bbbEffectiveRate;if (!reversedSwap) { aaaEffectiveRate =floatLabel(aaaFloatingRate - aaaGainBps/100); bbbEffectiveRate =`${rateFormat(bbbRates.fixed- bbbGainBps/100)}%`; } else { aaaEffectiveRate =`${rateFormat(aaaFixedRate - aaaGainBps/100)}%`; bbbEffectiveRate =floatLabel(bbbRates.floating- bbbGainBps/100); }const rows = [ { party:"AAA Corp",directFixed:`${rateFormat(aaaFixedRate)}%`,directFloating:floatLabel(aaaFloatingRate),effectiveCost: aaaEffectiveRate,gain:`${bpsFormat(aaaGainBps)} bps` }, { party:"BBB Corp",directFixed:`${rateFormat(bbbRates.fixed)}%`,directFloating:floatLabel(bbbRates.floating),effectiveCost: bbbEffectiveRate,gain:`${bpsFormat(bbbGainBps)} bps` }, { party:"Financial Intermediary",directFixed:"–",directFloating:"–",effectiveCost:"–",gain:`${bpsFormat(intermediaryGainBps)} bps` } ];const totalAllocatedGain = aaaGainBps + bbbGainBps + intermediaryGainBps;return htl.html`<table class="results-table"><thead><tr><th>Party</th><th>Direct Fixed Cost</th><th>Direct Floating Cost</th><th>Effective Cost with Swap</th><th>Gain</th></tr></thead><tbody>${rows.map(({party, directFixed, directFloating, effectiveCost, gain}) => htl.html`<tr><td>${party}</td><td>${directFixed}</td><td>${directFloating}</td><td><b>${effectiveCost}</b></td><td><b>${gain}</b></td></tr>`)}</tbody><tfoot><tr><td colspan="4" style="text-align: right; font-weight: bold;">Total Allocated Gain</td><td style="font-weight: bold;">${bpsFormat(totalAllocatedGain)} bps</td></tr></tfoot></table>`; })();const swapDiagram = (() => {let aaaBorrows, bbbBorrows, aaaPays, aaaReceives, bbbPays, bbbReceives;if (!reversedSwap) {// This is the standard case where the fixed-rate spread is larger than the floating-rate spread.// AAA Corp has a comparative advantage in the fixed-rate market but wishes to borrow floating.// BBB Corp has a comparative advantage in the floating-rate market but wishes to borrow fixed. aaaBorrows =`${rateFormat(aaaFixedRate)}%`;// Borrows fixed bbbBorrows =floatLabel(bbbRates.floating);// Borrows floating// Calculate the fixed rates for the swap legs that the intermediary will quote.const aaaReceivesRate = aaaFixedRate - aaaFloatingRate + (aaaGainBps /100);const bbbPaysRate = bbbRates.fixed- bbbRates.floating- (bbbGainBps /100); aaaPays ="Floating"; aaaReceives =`${rateFormat(aaaReceivesRate)}%`; bbbPays =`${rateFormat(bbbPaysRate)}%`; bbbReceives ="Floating"; } else {// This is the "reversed" case where the floating-rate spread is larger.// AAA Corp has a comparative advantage in the floating-rate market but wishes to borrow fixed.// BBB Corp has a comparative advantage in the fixed-rate market but wishes to borrow floating. aaaBorrows =floatLabel(aaaFloatingRate);// Borrows floating bbbBorrows =`${rateFormat(bbbRates.fixed)}%`;// Borrows fixed// Calculate the fixed rates for the swap legs that the intermediary will quote.const aaaPaysRate = aaaFixedRate - aaaFloatingRate - (aaaGainBps /100);const bbbReceivesRate = bbbRates.fixed- bbbRates.floating+ (bbbGainBps /100); aaaPays =`${rateFormat(aaaPaysRate)}%`; aaaReceives ="Floating"; bbbPays ="Floating"; bbbReceives =`${rateFormat(bbbReceivesRate)}%`; }return htl.html`<div class="diagram-card"><h3>Swap Payment Flows</h3><svg viewBox="0 0 1000 180" style="width: 100%; max-width: 1000px; height: auto; margin: 0 auto; display: block;"> <defs> <marker id="arrowBlack" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto"> <polygon points="0 0, 10 3, 0 6" fill="#333" /> </marker> <marker id="arrowGreen" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto"> <polygon points="0 0, 10 3, 0 6" fill="#2ca02c" /> </marker> <marker id="arrowOrange" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto"> <polygon points="0 0, 10 3, 0 6" fill="#ff7f0e" /> </marker> </defs> <text x="50" y="95" font-size="15" font-weight="600" text-anchor="middle">AAA Corp</text> <line x1="50" y1="75" x2="50" y2="25" stroke="#333" stroke-width="2.5" marker-end="url(#arrowBlack)"/> <text x="60" y="50" font-size="13" fill="#333">${aaaBorrows}</text> <line x1="110" y1="85" x2="330" y2="85" stroke="#2ca02c" stroke-width="2.5" marker-end="url(#arrowGreen)"/> <text x="210" y="78" font-size="13" fill="#2ca02c" text-anchor="middle">${aaaPays}</text> <line x1="330" y1="105" x2="110" y2="105" stroke="#ff7f0e" stroke-width="2.5" marker-end="url(#arrowOrange)"/> <text x="210" y="122" font-size="13" fill="#ff7f0e" text-anchor="middle">${aaaReceives}</text> <rect x="330" y="70" width="150" height="50" fill="#f8f9fa" stroke="#495057" stroke-width="2" rx="5"/> <text x="405" y="92" font-size="14" font-weight="600" text-anchor="middle">Financial</text> <text x="405" y="109" font-size="14" font-weight="600" text-anchor="middle">Intermediary</text> <line x1="480" y1="85" x2="740" y2="85" stroke="#2ca02c" stroke-width="2.5" marker-end="url(#arrowGreen)"/> <text x="600" y="78" font-size="13" fill="#2ca02c" text-anchor="middle">${bbbReceives}</text> <line x1="740" y1="105" x2="480" y2="105" stroke="#ff7f0e" stroke-width="2.5" marker-end="url(#arrowOrange)"/> <text x="600" y="122" font-size="13" fill="#ff7f0e" text-anchor="middle">${bbbPays}</text> <text x="800" y="95" font-size="15" font-weight="600" text-anchor="middle">BBB Corp</text> <line x1="800" y1="75" x2="800" y2="25" stroke="#333" stroke-width="2.5" marker-end="url(#arrowBlack)"/> <text x="815" y="50" font-size="13" fill="#333">${bbbBorrows}</text> </svg></div>`; })();return { introText, mechanicsText, gainDisplay, allocationWarning, resultsTable, swapDiagram };}
html`${views.introText}`
The total gain from the swap equals the difference in spreads between the two markets. This gain can then be allocated among the two companies and any financial intermediary facilitating the swap.
Tip
How to explore
Enter the borrowing rates for both companies in fixed and floating markets.
Observe the total gain (in basis points) available from the swap.
Use the allocation sliders to distribute the gain among AAA Corp, BBB Corp, and the financial intermediary.
Watch how the all-in costs update in real-time for each party.
The flow diagram below shows the actual interest rate payments between parties.
The key insight is that both parties end up better off than if they had borrowed directly in their desired market, and the intermediary earns a fee for enabling this mutually beneficial arrangement.
Criticism of the comparative-advantage argument
The argument presented above should be treated with caution. If the spread differential between the fixed and floating markets were a genuine arbitrage opportunity, we would expect it to have been competed away long ago, given how long the swap market has existed. The reason it persists lies in the nature of the underlying loan contracts.
The fixed rates offered to the two companies are long-term rates (for example, five-year rates), whereas the floating-rate quotes apply only until the next reset date. At each rollover, the lender can revise the spread it charges over the benchmark, or even refuse to renew the loan, if the borrower’s creditworthiness has deteriorated. Providers of fixed-rate financing have no such option. Because the probability of default by a lower-rated company such as BBB Corp increases faster over time than that of a highly rated company, the spread between the two companies’ rates is naturally wider in the fixed-rate market than in the floating-rate market.
This has two important consequences:
BBB Corp’s fixed rate is not truly locked in. Its apparent all-in fixed cost holds only as long as it can keep rolling over its floating-rate borrowing at the same spread. If its credit quality declines and the spread on its loan rises, its all-in cost rises with it. Since the market expects that spread to increase on average over the life of the swap, BBB Corp’s expected borrowing cost is higher than the swap arithmetic suggests.
AAA Corp locks in its favourable floating rate for the full life of the swap, which appears to be a good deal, but in exchange it bears the risk of a default by its swap counterparty (unless collateral is posted), a risk it would not bear if it simply borrowed floating-rate funds directly.
In short, the apparent “gain” from the swap is largely compensation for risks the parties take on, rather than a free lunch.
Risks in Interest Rate Swaps
While swaps are powerful tools for financial management, they are not without risks. The two primary risks are counterparty risk and interest rate risk.
Counterparty Risk
A swap is an over-the-counter (OTC) agreement between two parties. This introduces counterparty risk, which is the risk that one of the parties will default on its payment obligations. For example, if the financial intermediary in our example were to fail, both AAA Corp and BBB Corp would lose the benefits of the swap. Their financing costs would revert to their less favorable direct borrowing options.
To mitigate this risk, large corporations and financial institutions often trade through a central clearing house or require collateral (known as margin) to be posted. The fee earned by a financial intermediary is, in part, compensation for assuming and managing this counterparty risk.
Interest Rate Risk
Both parties to a swap are exposed to interest rate risk, although in different ways:
The floating-rate payer faces cash-flow uncertainty. If the benchmark rate (e.g., SOFR) rises unexpectedly, its interest payments increase.
The fixed-rate payer has certain cash flows, but bears risk on the value of its position: if market rates fall, it is locked into paying an above-market rate and the swap takes on a negative value from its perspective.
The terms of the floating leg are fixed in the swap agreement (the reference benchmark and the spread), but the actual rate paid resets periodically (e.g., every three or six months) to the prevailing market rate. Neither party renegotiates the terms; each accepts the rate determined by the market at each reset date. This exposure to fluctuating rates is a key consideration for any entity entering into a swap.