Currency swaps
A currency swap allows two parties to exchange borrowing obligations denominated in different currencies. A key feature is that the two parties exchange the principal at the start of the swap and return it at the end. Companies with different credit profiles often face varying borrowing costs across currency markets. This opportunity for mutual gain exists when the companies have a comparative advantage in different credit markets, meaning the difference in their borrowing rates is not the same across currencies. Such advantages can arise from many factors, including credit quality, market access, and even differing corporate tax treatments across jurisdictions. The swap allows them to collectively exploit this inefficiency.
This tool demonstrates two distinct swap structures:
Standard Swap (Intermediary Bears FX Risk): A fully-hedged structure where the financial intermediary absorbs all foreign exchange risk. Both corporations receive a guaranteed, single-currency borrowing cost. The user can control how the total system gain (Quality Spread Differential) is allocated among all three parties.
Asymmetric Swap (Company Bears FX Risk): An advanced structure where the intermediary operates a “pass-through” on one currency leg, concentrating its profit on the other leg. One company receives a fully-hedged single-currency outcome, while the other company is left with a blended multi-currency obligation and therefore bears foreign exchange risk.
1. Underlying Borrowing Rates
First, set the direct borrowing costs for each company in both currency markets. The tool determines the direction of the comparative advantage automatically: US Corp borrows in the market where the spread between the two companies is largest and swaps into the other currency, while EU Corp does the opposite.
US Corp Borrowing Rates
EU Corp Borrowing Rates
2. Swap Structure Selection
Choose the swap structure to explore:
3. Define Swap Parameters
// Conditional UI rendering with proper heading
swapParamsUI = {
if (swapScenario === "standard") {
return htl.html`<div>
<h4 style="margin-top: 0; color: #495057;">Gain Allocation</h4>
<p style="font-size: 0.9rem; color: #6c757d; margin-bottom: 1rem;">
In this fully-hedged structure, both companies receive a single-currency outcome.
Distribute the total system gain among all three parties:
</p>
</div>`;
} else {
return htl.html`<div>
<h4 style="margin-top: 0; color: #495057;">Swap Configuration</h4>
<p style="font-size: 0.9rem; color: #6c757d; margin-bottom: 1rem;">
In this structure, the intermediary takes a pass-through position on one currency leg,
concentrating all profit on the other leg. One company receives a fully-hedged outcome,
while the other bears FX risk with a multi-currency obligation.
</p>
</div>`;
}
}// Coupled sliders: US Corp + EU Corp gains can never exceed the total gain
viewof standardCorpGains = {
const maxGain = Math.max(0, gains.totalGainBps);
const container = htl.html`<div></div>`;
const usSlider = Inputs.range([0, maxGain], {
value: maxGain * 0.4,
step: 1,
label: "US Corp gain (bps)"
});
const euSlider = Inputs.range([0, maxGain], {
value: maxGain * 0.4,
step: 1,
label: "EU Corp gain (bps)"
});
container.appendChild(usSlider);
container.appendChild(euSlider);
container.value = [usSlider.value, euSlider.value];
usSlider.addEventListener('input', () => {
const maxEu = Math.max(0, maxGain - usSlider.value);
if (euSlider.value > maxEu) {
euSlider.value = maxEu;
euSlider.dispatchEvent(new Event('input'));
}
container.value = [usSlider.value, euSlider.value];
container.dispatchEvent(new Event('input'));
});
euSlider.addEventListener('input', () => {
const maxUs = Math.max(0, maxGain - euSlider.value);
if (usSlider.value > maxUs) {
usSlider.value = maxUs;
usSlider.dispatchEvent(new Event('input'));
}
container.value = [usSlider.value, euSlider.value];
container.dispatchEvent(new Event('input'));
});
return container;
}// Coupled sliders: hedged-party + intermediary gains can never exceed the
// total gain, so the risk-bearing party's residual gain stays non-negative
viewof asymmetricGains = {
const maxGain = Math.max(0, gains.totalGainBps);
const container = htl.html`<div></div>`;
const hedgedSlider = Inputs.range([0, maxGain], {
value: maxGain * 0.4,
step: 1,
label: "Fully-hedged party gain (bps)"
});
const intSlider = Inputs.range([0, maxGain], {
value: maxGain * 0.3,
step: 1,
label: "Intermediary gain on profitable leg (bps)"
});
container.appendChild(hedgedSlider);
container.appendChild(intSlider);
container.value = [hedgedSlider.value, intSlider.value];
hedgedSlider.addEventListener('input', () => {
const maxInt = Math.max(0, maxGain - hedgedSlider.value);
if (intSlider.value > maxInt) {
intSlider.value = maxInt;
intSlider.dispatchEvent(new Event('input'));
}
container.value = [hedgedSlider.value, intSlider.value];
container.dispatchEvent(new Event('input'));
});
intSlider.addEventListener('input', () => {
const maxHedged = Math.max(0, maxGain - intSlider.value);
if (hedgedSlider.value > maxHedged) {
hedgedSlider.value = maxHedged;
hedgedSlider.dispatchEvent(new Event('input'));
}
container.value = [hedgedSlider.value, intSlider.value];
container.dispatchEvent(new Event('input'));
});
return container;
}// Conditionally display standard swap controls
standardControlsDisplay = {
if (swapScenario === "standard") {
return htl.html`<div>
<div style="margin-bottom: 1rem;">
${viewof splitEqually}
</div>
${splitEqually
? htl.html`<div>${viewof standardIntermediaryGain}</div>`
: htl.html`<div>${viewof standardCorpGains}</div>`
}
</div>`;
}
return htl.html``;
}// Calculate final gain allocations based on scenario
finalGains = {
const { totalGainBps, usdSpread, eurSpread } = gains;
if (swapScenario === "standard") {
// Standard swap: calculate gains based on user allocation
const usGain = splitEqually
? (Math.max(0, totalGainBps - standardIntermediaryGain) / 2)
: standardCorpGains[0];
const euGain = splitEqually
? (Math.max(0, totalGainBps - standardIntermediaryGain) / 2)
: standardCorpGains[1];
const intGain = totalGainBps - usGain - euGain;
return {
scenario: "standard",
usCorpGainBps: usGain,
euCorpGainBps: euGain,
intermediaryGainBps: intGain,
hedgedParty: null,
riskBearingParty: null
};
} else {
// Asymmetric swap: calculate based on hedged party selection
const hedged = hedgedParty;
const hedgedGain = asymmetricGains[0];
const intGain = asymmetricGains[1];
// The risk-bearing party's gain is residual
const riskBearingGain = totalGainBps - hedgedGain - intGain;
return {
scenario: "asymmetric",
usCorpGainBps: hedged === "US Corp" ? hedgedGain : riskBearingGain,
euCorpGainBps: hedged === "EU Corp" ? hedgedGain : riskBearingGain,
intermediaryGainBps: intGain,
hedgedParty: hedged,
riskBearingParty: hedged === "US Corp" ? "EU Corp" : "US Corp"
};
}
}// STAGE 3: Calculate all outcomes and generate views
outcomes = {
const { totalGainBps, usdSpread, eurSpread } = gains;
const rateFormat = d3.format(".2f");
const effectiveCostFormat = d3.format(".3f");
const bpsFormat = d3.format(",.0f");
const { scenario, usCorpGainBps, euCorpGainBps, intermediaryGainBps, hedgedParty, riskBearingParty } = finalGains;
// --- Calculate effective rates based on scenario ---
let usEffectiveCostText, euEffectiveCostText, usPaysText, usReceivesText, euPaysText, euReceivesText;
let intermediaryGainText;
let usHasFXRisk = false;
let euHasFXRisk = false;
let usCorpGainDisplay, euCorpGainDisplay, interpretationText;
// Direction of comparative advantage: US Corp borrows in the market where
// the spread between the two companies is largest (ccyA) and swaps into the
// other currency (ccyB). When the EUR spread exceeds the USD spread, the
// roles of the two currencies are reversed.
const reversed = eurSpread > usdSpread;
const ccyA = reversed ? "EUR" : "USD";
const ccyB = reversed ? "USD" : "EUR";
const usRateA = reversed ? usCorpRates.eur : usCorpRates.usd;
const usRateB = reversed ? usCorpRates.usd : usCorpRates.eur;
const euRateA = reversed ? euCorpRates.eur : euCorpRates.usd;
const euRateB = reversed ? euCorpRates.usd : euCorpRates.eur;
const spreadA = euRateA - usRateA;
const spreadB = euRateB - usRateB;
if (scenario === "standard") {
const usEffectiveRateB = usRateB - (usCorpGainBps / 100);
const euEffectiveRateA = euRateA - (euCorpGainBps / 100);
usEffectiveCostText = `${effectiveCostFormat(usEffectiveRateB)}% (${ccyB})`;
euEffectiveCostText = `${effectiveCostFormat(euEffectiveRateA)}% (${ccyA})`;
usPaysText = usEffectiveCostText;
usReceivesText = `${rateFormat(usRateA)}% (${ccyA})`;
euPaysText = euEffectiveCostText;
euReceivesText = `${rateFormat(euRateB)}% (${ccyB})`;
const intGainABps = (spreadA * 100) - euCorpGainBps;
const intGainBBps = (-spreadB * 100) - usCorpGainBps;
intermediaryGainText = `${bpsFormat(intGainABps)} bps (${ccyA}) + ${bpsFormat(intGainBBps)} bps (${ccyB})`;
usCorpGainDisplay = htl.html`<b>${bpsFormat(usCorpGainBps)} bps</b>`;
euCorpGainDisplay = htl.html`<b>${bpsFormat(euCorpGainBps)} bps</b>`;
interpretationText = htl.html`<p>In this fully-hedged structure, both corporations have successfully transformed the currency of their debt while achieving a lower interest rate than they could have obtained directly. The intermediary absorbs all foreign exchange risk, and in return, earns a spread. The final "Effective Cost" for each company is a fixed, single-currency obligation, providing them with certainty about their future financing costs.</p>`;
} else { // Asymmetric scenario
if (hedgedParty === "US Corp") {
usHasFXRisk = false;
euHasFXRisk = true;
const usEffectiveRateB = usRateB - (usCorpGainBps / 100);
usEffectiveCostText = `${effectiveCostFormat(usEffectiveRateB)}% (${ccyB})`;
usPaysText = usEffectiveCostText;
usReceivesText = `${rateFormat(usRateA)}% (${ccyA})`;
const int_receives_B_from_us = usEffectiveRateB;
const int_pays_B_to_eu = int_receives_B_from_us - (intermediaryGainBps / 100);
const int_receives_A_from_eu = usRateA;
euPaysText = `${rateFormat(int_receives_A_from_eu)}% (${ccyA})`;
euReceivesText = `${rateFormat(int_pays_B_to_eu)}% (${ccyB})`;
const eu_final_A_cost = int_receives_A_from_eu;
const eu_final_B_cost = euRateB - int_pays_B_to_eu;
euEffectiveCostText = `${effectiveCostFormat(eu_final_A_cost)}% (${ccyA}) & ${effectiveCostFormat(eu_final_B_cost)}% (${ccyB})`;
intermediaryGainText = `${bpsFormat(intermediaryGainBps)} bps (on ${ccyB} leg) & 0 bps (on ${ccyA} leg)`;
usCorpGainDisplay = htl.html`<b>${bpsFormat(usCorpGainBps)} bps</b>`;
const legAGainBps = (euRateA - eu_final_A_cost) * 100;
const legBLossBps = -eu_final_B_cost * 100;
euCorpGainDisplay = htl.html`<b>${bpsFormat(euCorpGainBps)} bps</b><br><small style="font-weight: normal; color: #495057;">(${legAGainBps >= 0 ? '+' : ''}${bpsFormat(legAGainBps)} bps ${ccyA} & ${legBLossBps >= 0 ? '+' : ''}${bpsFormat(legBLossBps)} bps ${ccyB})</small>`;
} else { // hedgedParty === "EU Corp"
usHasFXRisk = true;
euHasFXRisk = false;
const euEffectiveRateA = euRateA - (euCorpGainBps / 100);
euEffectiveCostText = `${effectiveCostFormat(euEffectiveRateA)}% (${ccyA})`;
euPaysText = euEffectiveCostText;
euReceivesText = `${rateFormat(euRateB)}% (${ccyB})`;
const int_receives_A_from_eu = euEffectiveRateA;
const int_pays_A_to_us = int_receives_A_from_eu - (intermediaryGainBps / 100);
const int_receives_B_from_us = euRateB;
usPaysText = `${rateFormat(int_receives_B_from_us)}% (${ccyB})`;
usReceivesText = `${rateFormat(int_pays_A_to_us)}% (${ccyA})`;
const us_final_B_cost = int_receives_B_from_us;
const us_final_A_cost = usRateA - int_pays_A_to_us;
usEffectiveCostText = `${effectiveCostFormat(us_final_A_cost)}% (${ccyA}) & ${effectiveCostFormat(us_final_B_cost)}% (${ccyB})`;
intermediaryGainText = `${bpsFormat(intermediaryGainBps)} bps (on ${ccyA} leg) & 0 bps (on ${ccyB} leg)`;
euCorpGainDisplay = htl.html`<b>${bpsFormat(euCorpGainBps)} bps</b>`;
const legBGainBps = (usRateB - us_final_B_cost) * 100;
const legALossBps = -us_final_A_cost * 100;
usCorpGainDisplay = htl.html`<b>${bpsFormat(usCorpGainBps)} bps</b><br><small style="font-weight: normal; color: #495057;">(${legALossBps >= 0 ? '+' : ''}${bpsFormat(legALossBps)} bps ${ccyA} & ${legBGainBps >= 0 ? '+' : ''}${bpsFormat(legBGainBps)} bps ${ccyB})</small>`;
}
interpretationText = htl.html`<div>
<p>This structure demonstrates a critical trade-off between cost-saving and risk.</p>
<ul>
<li>The <b>hedged party</b> (${hedgedParty}) achieves a guaranteed, single-currency borrowing cost that is lower than its direct alternative. It is completely insulated from foreign exchange risk.</li>
<li>The <b>risk-bearing party</b> (${riskBearingParty}) secures a portion of the swap's gains but is left with a synthetic, multi-currency liability. Its final financing cost is not fixed; it is now a blend of USD and EUR obligations. The ultimate cost of this position will fluctuate with the USD/EUR exchange rate, creating both the potential for further gains or unexpected losses. This exposure is the price it pays for its share of the swap's benefits.</li>
</ul>
</div>`;
}
// --- BUILD HTML VIEWS ---
const gainDisplay = (() => {
if (totalGainBps < 0.1) {
return htl.html`<div class="no-gain-card">
<div class="no-gain-header">No Net System Gain</div>
<div class="no-gain-value">${bpsFormat(totalGainBps)} bps</div>
<p class="no-gain-explanation">The borrowing spreads are nearly identical in both currency markets.</p>
</div>`;
}
const gainExplanation = `This gain arises because the borrowing spread between the two companies in the ${ccyA} market (${rateFormat(spreadA*100)} bps) exceeds the spread in the ${ccyB} market (${rateFormat(spreadB*100)} bps). US Corp therefore has a comparative advantage in ${ccyA} and borrows ${ccyA}, while EU Corp has a comparative advantage in ${ccyB} and borrows ${ccyB}; the swap converts each loan into the other currency.`;
return htl.html`<div class="gain-card">
<div class="gain-header">Net System Gain (Quality Spread Differential)</div>
<div class="gain-value">${bpsFormat(totalGainBps)} basis points</div>
<p class="gain-explanation">${gainExplanation}</p>
</div>`;
})();
const allocationWarning = (intermediaryGainBps < -0.1 || usCorpGainBps < -0.1 || euCorpGainBps < -0.1)
? htl.html`<div class="warning-card">⚠️ The allocated gains exceed the total available gain; at least one party ends up with a loss.</div>`
: null;
const usCorpBorrowsText = `${rateFormat(usRateA)}% (${ccyA})`;
const euCorpBorrowsText = `${rateFormat(euRateB)}% (${ccyB})`;
const principalStartDiagram = htl.html`<div class="diagram-card"><h3>Principal Exchange at Inception</h3><svg viewBox="0 0 1000 180" style="width: 100%; max-width: 1000px; height: auto; margin: 0 auto; display: block;">
<defs>
<marker id="arrowBlue" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto"><polygon points="0 0, 10 3, 0 6" fill="#1f77b4" /></marker>
<marker id="arrowRed" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto"><polygon points="0 0, 10 3, 0 6" fill="#d62728" /></marker>
</defs>
<text x="50" y="95" font-size="15" font-weight="600" text-anchor="middle">US Corp</text>
<line x1="110" y1="85" x2="330" y2="85" stroke="#1f77b4" stroke-width="2.5" marker-end="url(#arrowBlue)"/><text x="220" y="78" font-size="13" fill="#1f77b4" text-anchor="middle">Principal (${ccyA})</text>
<line x1="330" y1="105" x2="110" y2="105" stroke="#d62728" stroke-width="2.5" marker-end="url(#arrowRed)"/><text x="220" y="122" font-size="13" fill="#d62728" text-anchor="middle">Principal (${ccyB})</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="#1f77b4" stroke-width="2.5" marker-end="url(#arrowBlue)"/><text x="610" y="78" font-size="13" fill="#1f77b4" text-anchor="middle">Principal (${ccyA})</text>
<line x1="740" y1="105" x2="480" y2="105" stroke="#d62728" stroke-width="2.5" marker-end="url(#arrowRed)"/><text x="610" y="122" font-size="13" fill="#d62728" text-anchor="middle">Principal (${ccyB})</text>
<text x="800" y="95" font-size="15" font-weight="600" text-anchor="middle">EU Corp</text>
</svg></div>`;
const principalEndDiagram = htl.html`<div class="diagram-card"><h3>Principal Exchange at Maturity</h3><svg viewBox="0 0 1000 180" style="width: 100%; max-width: 1000px; height: auto; margin: 0 auto; display: block;">
<defs>
<marker id="arrowBlue" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto"><polygon points="0 0, 10 3, 0 6" fill="#1f77b4" /></marker>
<marker id="arrowRed" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto"><polygon points="0 0, 10 3, 0 6" fill="#d62728" /></marker>
</defs>
<text x="50" y="95" font-size="15" font-weight="600" text-anchor="middle">US Corp</text>
<line x1="330" y1="85" x2="110" y2="85" stroke="#1f77b4" stroke-width="2.5" marker-end="url(#arrowBlue)"/><text x="220" y="78" font-size="13" fill="#1f77b4" text-anchor="middle">Principal (${ccyA})</text>
<line x1="110" y1="105" x2="330" y2="105" stroke="#d62728" stroke-width="2.5" marker-end="url(#arrowRed)"/><text x="220" y="122" font-size="13" fill="#d62728" text-anchor="middle">Principal (${ccyB})</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="105" x2="740" y2="105" stroke="#d62728" stroke-width="2.5" marker-end="url(#arrowRed)"/><text x="610" y="122" font-size="13" fill="#d62728" text-anchor="middle">Principal (${ccyB})</text>
<line x1="740" y1="85" x2="480" y2="85" stroke="#1f77b4" stroke-width="2.5" marker-end="url(#arrowBlue)"/><text x="610" y="78" font-size="13" fill="#1f77b4" text-anchor="middle">Principal (${ccyA})</text>
<text x="800" y="95" font-size="15" font-weight="600" text-anchor="middle">EU Corp</text>
</svg></div>`;
const swapDiagram = htl.html`<div class="diagram-card"><h3>Interest 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">US 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">${usCorpBorrowsText}</text>
<line x1="110" y1="85" x2="330" y2="85" stroke="#2ca02c" stroke-width="2.5" marker-end="url(#arrowGreen)"/><text x="220" y="78" font-size="13" fill="#2ca02c" text-anchor="middle">${usPaysText}</text>
<line x1="330" y1="105" x2="110" y2="105" stroke="#ff7f0e" stroke-width="2.5" marker-end="url(#arrowOrange)"/><text x="220" y="122" font-size="13" fill="#ff7f0e" text-anchor="middle">${usReceivesText}</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="#ff7f0e" stroke-width="2.5" marker-end="url(#arrowOrange)"/><text x="610" y="78" font-size="13" fill="#ff7f0e" text-anchor="middle">${euReceivesText}</text>
<line x1="740" y1="105" x2="480" y2="105" stroke="#2ca02c" stroke-width="2.5" marker-end="url(#arrowGreen)"/><text x="610" y="122" font-size="13" fill="#2ca02c" text-anchor="middle">${euPaysText}</text>
<text x="800" y="95" font-size="15" font-weight="600" text-anchor="middle">EU 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">${euCorpBorrowsText}</text>
</svg></div>`;
const totalAllocatedGain = usCorpGainBps + euCorpGainBps + intermediaryGainBps;
const resultsTable = htl.html`<div class="results-table-wrapper">
<h3>All-in Costs and Gains</h3>
<table>
<thead>
<tr>
<th>Party</th>
<th>Direct Cost (USD)</th>
<th>Direct Cost (EUR)</th>
<th>Effective Cost with Swap</th>
<th>Gain</th>
${scenario === "asymmetric" ? htl.html`<th>FX Risk</th>` : ""}
</tr>
</thead>
<tbody>
<tr style="${usHasFXRisk ? 'background-color: #fff3cd;' : ''}">
<td><b>US Corp</b></td>
<td>${rateFormat(usCorpRates.usd)}%</td>
<td>${rateFormat(usCorpRates.eur)}%</td>
<td><b>${usEffectiveCostText}</b></td>
<td>${usCorpGainDisplay}</td>
${scenario === "asymmetric" ? htl.html`<td>${usHasFXRisk ? htl.html`<span style="color: #856404;">⚠️ Exposed</span>` : '✓ Hedged'}</td>` : ""}
</tr>
<tr style="${euHasFXRisk ? 'background-color: #fff3cd;' : ''}">
<td><b>EU Corp</b></td>
<td>${rateFormat(euCorpRates.usd)}%</td>
<td>${rateFormat(euCorpRates.eur)}%</td>
<td><b>${euEffectiveCostText}</b></td>
<td>${euCorpGainDisplay}</td>
${scenario === "asymmetric" ? htl.html`<td>${euHasFXRisk ? htl.html`<span style="color: #856404;">⚠️ Exposed</span>` : '✓ Hedged'}</td>` : ""}
</tr>
<tr>
<td><b>Intermediary</b></td>
<td>–</td>
<td>–</td>
<td>${intermediaryGainText}</td>
<td><b>${bpsFormat(intermediaryGainBps)} bps</b></td>
${scenario === "asymmetric" ? htl.html`<td>–</td>` : ""}
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4" style="text-align: right; font-weight: bold;">Total Allocated Gain</td>
<td><b>${bpsFormat(totalAllocatedGain)} bps</b></td>
${scenario === "asymmetric" ? htl.html`<td></td>` : ""}
</tr>
</tfoot>
</table>
</div>`;
return { gainDisplay, allocationWarning, principalStartDiagram, swapDiagram, principalEndDiagram, resultsTable, interpretationText };
}4. Swap Diagram and Outcomes
5. Interpretation of Results
NoteReference
This page accompanies Chapter 7 of Hull (2022).
References
Hull, John. 2022. Options, Futures, and Other Derivatives. 11th ed. Pearson.