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");// 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 =`Floating + ${rateFormat(aaaFloatingRate - aaaGainBps/100)}%`; bbbEffectiveRate =`${rateFormat(bbbRates.fixed- bbbGainBps/100)}%`; } else { aaaEffectiveRate =`${rateFormat(aaaFixedRate - aaaGainBps/100)}%`; bbbEffectiveRate =`Floating + ${rateFormat(bbbRates.floating- bbbGainBps/100)}%`; }const rows = [ { party:"AAA Corp",directFixed:`${rateFormat(aaaFixedRate)}%`,directFloating:`Floating + ${rateFormat(aaaFloatingRate)}%`,effectiveCost: aaaEffectiveRate,gain:`${bpsFormat(aaaGainBps)} bps` }, { party:"BBB Corp",directFixed:`${rateFormat(bbbRates.fixed)}%`,directFloating:`Floating + ${rateFormat(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 =`Floating + ${rateFormat(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 =`Floating + ${rateFormat(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.
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
The party that agrees to pay the floating rate bears interest rate risk. In our example, one company ends up paying a floating rate (e.g., SOFR + spread) in exchange for receiving a fixed rate. If the benchmark rate (SOFR) rises unexpectedly, the company’s interest payments will increase.
This creates uncertainty in cash flows. The terms of the floating leg are fixed in the swap agreement (e.g., the reference benchmark and the spread), but the actual rate paid will reset periodically (e.g., every three or six months) to the prevailing market rate. The company does not renegotiate the terms, but rather accepts the new 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.