<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>interest rates | Joey O'Brien</title><link>https://obrienjoey.github.io/tags/interest-rates/</link><atom:link href="https://obrienjoey.github.io/tags/interest-rates/index.xml" rel="self" type="application/rss+xml"/><description>interest rates</description><generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>en-us</language><copyright>© 2026 Joey O'Brien</copyright><lastBuildDate>Wed, 15 Jul 2026 00:00:00 +0000</lastBuildDate><image><url>https://obrienjoey.github.io/img/og-banner.png</url><title>interest rates</title><link>https://obrienjoey.github.io/tags/interest-rates/</link></image><item><title>Bootstrapping in the Open-Source Risk Engine</title><link>https://obrienjoey.github.io/post/ore_sofr_bootstrap/</link><pubDate>Wed, 15 Jul 2026 00:00:00 +0000</pubDate><guid>https://obrienjoey.github.io/post/ore_sofr_bootstrap/</guid><description>&lt;p>Open Source Risk Engine (ORE) is a powerful, production-grade risk analysis and pricing engine built on top of QuantLib. Having supported multiple clients through vendor replacement processes, we have seen first-hand that interest rate curve bootstrapping is always a critical first step. Reconciling a new open-source library against legacy vendor systems is an iterative, detailed task, and establishing a consistent curve bootstrap is the foundation upon which all downstream valuation and risk metrics depend.&lt;/p>
&lt;p>Because ORE is entirely open-source, it offers unmatched transparency for quantitative finance professionals. Rather than dealing with a proprietary &amp;ldquo;black box&amp;rdquo;, developers and analysts can inspect every calculation, schedule rule, and day-count convention directly in the source code. A prime example of this transparency is ORE&amp;rsquo;s official &lt;a href="https://github.com/OpenSourceRisk/Engine/tree/master/Examples/CurveBuilding">CurveBuilding Examples on GitHub&lt;/a>, which showcase how ORE constructs interest rate and inflation curves across different currencies and instruments.&lt;/p>
&lt;p>In this post, we pull from these developer examples to walk through how to build a single USD Secured Overnight Financing Rate (SOFR) curve, which acts as both the discounting and forecasting index in the post-LIBOR USD market, and verify the consistency of the bootstrap by repricing the calibration instruments to zero present value (PV).&lt;/p>
&lt;p>No C++ compilation is required. You can install the package and run the entire process in a few lines of Python:&lt;/p>
&lt;pre>&lt;code class="language-bash">pip install open-source-risk-engine matplotlib
&lt;/code>&lt;/pre>
&lt;hr>
&lt;h2 id="todaysmarket">1. Mapping the Model — &lt;code>todaysmarket.xml&lt;/code>&lt;/h2>
&lt;p>To understand how ORE resolves your market data, it is helpful to look at the XML config dependency tree. The execution logic flows downward through this hierarchy, making the configuration mapping the natural starting point:&lt;/p>
&lt;pre>&lt;code class="language-text"> ore.xml
│
└──&amp;gt; todaysmarket.xml
│
└──&amp;gt; curveconfig.xml
│
├──&amp;gt; conventions.xml
└──&amp;gt; market.txt
&lt;/code>&lt;/pre>
&lt;ol>
&lt;li>&lt;strong>&lt;code>ore.xml&lt;/code>&lt;/strong>: The master entry point that points ORE to the output directory, logs, portfolio file, and sub-configuration files.&lt;/li>
&lt;li>&lt;strong>&lt;code>todaysmarket.xml&lt;/code>&lt;/strong>: The top-level mapping guide (detailed below). It tells ORE what curves we will build for this run, how to resolve them against configurations in &lt;code>curveconfig.xml&lt;/code>, and what curves should be used for discounting and forwarding roles for each currency and index.&lt;/li>
&lt;li>&lt;strong>&lt;code>curveconfig.xml&lt;/code>&lt;/strong>: Defines the recipe for building each individual curve (detailed in &lt;a href="#curve-configuration">Section 4&lt;/a>).&lt;/li>
&lt;li>&lt;strong>&lt;code>conventions.xml&lt;/code>&lt;/strong> (detailed in &lt;a href="#conventions">Section 2&lt;/a>) + &lt;strong>&lt;code>market.txt&lt;/code>&lt;/strong> (detailed in &lt;a href="#market-data">Section 3&lt;/a>): Hold the underlying conventions details and numerical rate values.&lt;/li>
&lt;/ol>
&lt;p>For our single-curve USD SOFR build, &lt;code>todaysmarket.xml&lt;/code> maps both the &lt;strong>discounting curve&lt;/strong> and the &lt;strong>index forwarding curve&lt;/strong> roles to the &lt;code>USD-SOFR&lt;/code> curve identifier:&lt;/p>
&lt;pre>&lt;code class="language-xml">&amp;lt;TodaysMarket&amp;gt;
&amp;lt;Configuration id=&amp;quot;default&amp;quot;&amp;gt;
&amp;lt;DiscountingCurvesId&amp;gt;default&amp;lt;/DiscountingCurvesId&amp;gt;
&amp;lt;IndexForwardingCurvesId&amp;gt;default&amp;lt;/IndexForwardingCurvesId&amp;gt;
&amp;lt;/Configuration&amp;gt;
&amp;lt;DiscountingCurves&amp;gt;
&amp;lt;DiscountingCurve currency=&amp;quot;USD&amp;quot;&amp;gt;USD-SOFR&amp;lt;/DiscountingCurve&amp;gt;
&amp;lt;/DiscountingCurves&amp;gt;
&amp;lt;IndexForwardingCurves&amp;gt;
&amp;lt;IndexForwardingCurve index=&amp;quot;USD-SOFR&amp;quot;&amp;gt;USD-SOFR&amp;lt;/IndexForwardingCurve&amp;gt;
&amp;lt;/IndexForwardingCurves&amp;gt;
&amp;lt;/TodaysMarket&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>This explicit mapping informs ORE that &lt;code>USD-SOFR&lt;/code> is the reference curve for both discounting cashflows and projecting future daily SOFR coupon fixings.&lt;/p>
&lt;h2 id="conventions">2. Conventions — &lt;code>conventions.xml&lt;/code>&lt;/h2>
&lt;p>Before feeding market quotes to the curve builder, ORE needs to know the financial conventions of the underlying instruments. Every swap coupon payment lag, day count fraction, and business day calendar mismatch will lead to pricing discrepancies if these details are not perfectly specified.&lt;/p>
&lt;p>Indeed, a solid understanding of these conventions is key to successful interest rate modelling. For a comprehensive reference on global interest rate market conventions, see the guide by Marc P. A. Henrard: &lt;strong>&lt;a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=5099269">Interest Rate Instruments and Market Conventions Guide - Post LIBOR edition&lt;/a>&lt;/strong>.&lt;/p>
&lt;p>For the underlying mathematics of interest rate curve construction, interpolation methods, and multi-curve bootstrapping, the classic paper by Ferdinando M. Ametrano and Marco Bianchetti serves as the reference text: &lt;strong>&lt;a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2219548">Everything You Always Wanted to Know About Multiple Interest Rate Curve Bootstrapping but Were Afraid to Ask&lt;/a>&lt;/strong>. It is highly recommended reading if you want to dive deep into the bootstrapping mechanics.&lt;/p>
&lt;p>For a standard USD SOFR curve build, we combine money market (MM) overnight deposit conventions for the short end and Overnight Indexed Swap (OIS) conventions for the longer tenors. Note, some practitioners would also use SOFR MM Futures as the second component of the bootstrap rather than going directly to OIS Swaps, this is entirely possible in ORE also. The conventions are defined in &lt;code>conventions.xml&lt;/code>:&lt;/p>
&lt;pre>&lt;code class="language-xml">&amp;lt;Conventions&amp;gt;
&amp;lt;Deposit&amp;gt;
&amp;lt;Id&amp;gt;USD-ON-SOFR-DEPOSIT&amp;lt;/Id&amp;gt;
&amp;lt;IndexBased&amp;gt;true&amp;lt;/IndexBased&amp;gt;
&amp;lt;Index&amp;gt;USD-SOFR&amp;lt;/Index&amp;gt;
&amp;lt;/Deposit&amp;gt;
&amp;lt;OIS&amp;gt;
&amp;lt;Id&amp;gt;USD-SOFR-OIS&amp;lt;/Id&amp;gt;
&amp;lt;SpotLag&amp;gt;0&amp;lt;/SpotLag&amp;gt;
&amp;lt;Index&amp;gt;USD-SOFR&amp;lt;/Index&amp;gt;
&amp;lt;FixedDayCounter&amp;gt;A360&amp;lt;/FixedDayCounter&amp;gt;
&amp;lt;PaymentLag&amp;gt;2&amp;lt;/PaymentLag&amp;gt;
&amp;lt;EOM&amp;gt;false&amp;lt;/EOM&amp;gt;
&amp;lt;FixedFrequency&amp;gt;Annual&amp;lt;/FixedFrequency&amp;gt;
&amp;lt;FixedConvention&amp;gt;MF&amp;lt;/FixedConvention&amp;gt;
&amp;lt;FixedPaymentConvention&amp;gt;MF&amp;lt;/FixedPaymentConvention&amp;gt;
&amp;lt;Rule&amp;gt;Backward&amp;lt;/Rule&amp;gt;
&amp;lt;/OIS&amp;gt;
&amp;lt;/Conventions&amp;gt;
&lt;/code>&lt;/pre>
&lt;h3 id="deconstructing-conventions">Deconstructing conventions&lt;/h3>
&lt;p>In ORE, curve conventions are mapped out with fine-grained parameters:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Overnight Deposit (&lt;code>USD-ON-SOFR-DEPOSIT&lt;/code>)&lt;/strong>: An index-based deposit linking directly to the &lt;code>USD-SOFR&lt;/code> index.&lt;/li>
&lt;li>&lt;strong>OIS Conventions (&lt;code>USD-SOFR-OIS&lt;/code>)&lt;/strong>:
&lt;ul>
&lt;li>&lt;strong>&lt;code>&amp;lt;SpotLag&amp;gt;&lt;/code>&lt;/strong>: Set to &lt;code>0&lt;/code> days, meaning the swap starts immediately on the settlement date.&lt;/li>
&lt;li>&lt;strong>&lt;code>&amp;lt;PaymentLag&amp;gt;&lt;/code>&lt;/strong>: Set to &lt;code>2&lt;/code> business days, meaning payments occur 2 days after the accrual period ends.&lt;/li>
&lt;li>&lt;strong>&lt;code>&amp;lt;FixedDayCounter&amp;gt;&lt;/code>&lt;/strong>: Set to &lt;code>A360&lt;/code> (Actual/360) day count basis.&lt;/li>
&lt;li>&lt;strong>&lt;code>&amp;lt;FixedConvention&amp;gt;&lt;/code>&lt;/strong> and &lt;strong>&lt;code>&amp;lt;FixedPaymentConvention&amp;gt;&lt;/code>&lt;/strong>: Set to &lt;code>MF&lt;/code> (Modified Following business day rule).&lt;/li>
&lt;li>&lt;strong>&lt;code>&amp;lt;Rule&amp;gt;&lt;/code>&lt;/strong>: Set to &lt;code>Backward&lt;/code> schedule generation.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="market-data">3. Market Data — &lt;code>market.txt&lt;/code>&lt;/h2>
&lt;p>Next, we define our market quotes. In a realistic curve build, we start the SOFR curve using the Overnight Money Market (MM) deposit rate helper at the very short end ($T+0$), followed by OIS swaps for the longer tenors. The data is provided in a simple space-delimited text format:&lt;/p>
&lt;pre>&lt;code class="language-text"># Node Instrument Type Quote
2023-01-31 MM/RATE/USD/SOFR/0D/1D 0.0430000000
2023-01-31 IR_SWAP/RATE/USD/SOFR/0D/1D/1M 0.0456640000
2023-01-31 IR_SWAP/RATE/USD/SOFR/0D/1D/3M 0.0468210000
2023-01-31 IR_SWAP/RATE/USD/SOFR/0D/1D/6M 0.0483440000
2023-01-31 IR_SWAP/RATE/USD/SOFR/0D/1D/1Y 0.0487100000
2023-01-31 IR_SWAP/RATE/USD/SOFR/0D/1D/2Y 0.0427805000
2023-01-31 IR_SWAP/RATE/USD/SOFR/0D/1D/5Y 0.0346100000
2023-01-31 IR_SWAP/RATE/USD/SOFR/0D/1D/10Y 0.0324600000
2023-01-31 IR_SWAP/RATE/USD/SOFR/0D/1D/30Y 0.0300290000
&lt;/code>&lt;/pre>
&lt;h3 id="quote-string-representation--conventions-control">Quote String Representation &amp;amp; Conventions Control&lt;/h3>
&lt;p>In ORE, market data quotes follow a structured string format that helps developers identify the instrument type, currency, index, and tenor:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>MM/RATE/USD/SOFR/0D/1D&lt;/code>&lt;/strong>: Represents a Money Market (&lt;code>MM&lt;/code>) rate for the &lt;code>USD&lt;/code> currency, tied to &lt;code>SOFR&lt;/code> overnight (starting immediately, term of &lt;code>1D&lt;/code>).&lt;/li>
&lt;li>&lt;strong>&lt;code>IR_SWAP/RATE/USD/SOFR/0D/1D/30Y&lt;/code>&lt;/strong>: Represents an Interest Rate Swap (&lt;code>IR_SWAP&lt;/code>) rate for the &lt;code>USD&lt;/code> currency, tied to &lt;code>SOFR&lt;/code> overnight index with a tenor of &lt;code>30Y&lt;/code>.&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>Important&lt;/strong>: A common point of confusion when setting up ORE is assuming that ORE parses these quote strings to determine pricing behavior. &lt;strong>This is not the case.&lt;/strong>&lt;/p>
&lt;p>While the quote string contains parameters like the tenor (&lt;code>30Y&lt;/code>) or settlement terms (&lt;code>0D/1D&lt;/code>), the string serves strictly as a key identifier to match the market data row with the curve configuration. The actual financial behavior—such as compounding logic, schedule generation, payment lags, calendars, and rolling conventions—is driven entirely by the conventions defined in &lt;code>conventions.xml&lt;/code> rather than parsed directly from the market data quote string itself.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="curve-configuration">4. Curve Configuration — &lt;code>curveconfig.xml&lt;/code>&lt;/h2>
&lt;p>With conventions and quotes in hand, we assemble the curve recipe in &lt;code>curveconfig.xml&lt;/code>. Because we are using two different types of instruments (a Deposit at the short end and Swaps for the rest of the curve), our configuration defines multiple &lt;code>&amp;lt;Simple&amp;gt;&lt;/code> segments:&lt;/p>
&lt;pre>&lt;code class="language-xml">&amp;lt;CurveConfiguration&amp;gt;
&amp;lt;YieldCurves&amp;gt;
&amp;lt;YieldCurve&amp;gt;
&amp;lt;CurveId&amp;gt;USD-SOFR&amp;lt;/CurveId&amp;gt;
&amp;lt;CurveDescription&amp;gt;USD SOFR OIS discount curve&amp;lt;/CurveDescription&amp;gt;
&amp;lt;Currency&amp;gt;USD&amp;lt;/Currency&amp;gt;
&amp;lt;DiscountCurve&amp;gt;USD-SOFR&amp;lt;/DiscountCurve&amp;gt;
&amp;lt;Segments&amp;gt;
&amp;lt;Simple&amp;gt;
&amp;lt;Type&amp;gt;Deposit&amp;lt;/Type&amp;gt;
&amp;lt;Quotes&amp;gt;
&amp;lt;Quote&amp;gt;MM/RATE/USD/SOFR/0D/1D&amp;lt;/Quote&amp;gt;
&amp;lt;/Quotes&amp;gt;
&amp;lt;Conventions&amp;gt;USD-ON-SOFR-DEPOSIT&amp;lt;/Conventions&amp;gt;
&amp;lt;ProjectionCurve&amp;gt;USD-SOFR&amp;lt;/ProjectionCurve&amp;gt;
&amp;lt;/Simple&amp;gt;
&amp;lt;Simple&amp;gt;
&amp;lt;Type&amp;gt;OIS&amp;lt;/Type&amp;gt;
&amp;lt;Quotes&amp;gt;
&amp;lt;Quote optional=&amp;quot;true&amp;quot;&amp;gt;IR_SWAP/RATE/USD/SOFR/0D/1D/1M&amp;lt;/Quote&amp;gt;
&amp;lt;Quote optional=&amp;quot;true&amp;quot;&amp;gt;IR_SWAP/RATE/USD/SOFR/0D/1D/3M&amp;lt;/Quote&amp;gt;
&amp;lt;Quote optional=&amp;quot;true&amp;quot;&amp;gt;IR_SWAP/RATE/USD/SOFR/0D/1D/6M&amp;lt;/Quote&amp;gt;
&amp;lt;Quote optional=&amp;quot;true&amp;quot;&amp;gt;IR_SWAP/RATE/USD/SOFR/0D/1D/1Y&amp;lt;/Quote&amp;gt;
&amp;lt;Quote optional=&amp;quot;true&amp;quot;&amp;gt;IR_SWAP/RATE/USD/SOFR/0D/1D/2Y&amp;lt;/Quote&amp;gt;
&amp;lt;Quote optional=&amp;quot;true&amp;quot;&amp;gt;IR_SWAP/RATE/USD/SOFR/0D/1D/5Y&amp;lt;/Quote&amp;gt;
&amp;lt;Quote optional=&amp;quot;true&amp;quot;&amp;gt;IR_SWAP/RATE/USD/SOFR/0D/1D/10Y&amp;lt;/Quote&amp;gt;
&amp;lt;Quote optional=&amp;quot;true&amp;quot;&amp;gt;IR_SWAP/RATE/USD/SOFR/0D/1D/30Y&amp;lt;/Quote&amp;gt;
&amp;lt;/Quotes&amp;gt;
&amp;lt;Conventions&amp;gt;USD-SOFR-OIS&amp;lt;/Conventions&amp;gt;
&amp;lt;/Simple&amp;gt;
&amp;lt;/Segments&amp;gt;
&amp;lt;InterpolationVariable&amp;gt;Discount&amp;lt;/InterpolationVariable&amp;gt;
&amp;lt;InterpolationMethod&amp;gt;LogLinear&amp;lt;/InterpolationMethod&amp;gt;
&amp;lt;YieldCurveDayCounter&amp;gt;A365&amp;lt;/YieldCurveDayCounter&amp;gt;
&amp;lt;Tolerance&amp;gt;0.0000000000010000&amp;lt;/Tolerance&amp;gt;
&amp;lt;Extrapolation&amp;gt;true&amp;lt;/Extrapolation&amp;gt;
&amp;lt;/YieldCurve&amp;gt;
&amp;lt;/YieldCurves&amp;gt;
&amp;lt;/CurveConfiguration&amp;gt;
&lt;/code>&lt;/pre>
&lt;h3 id="unmatched-control-over-curve-building">Unmatched Control Over Curve Building&lt;/h3>
&lt;p>One of ORE&amp;rsquo;s core strengths is the level of mathematical control it gives you over the curve construction process. Rather than restricting you to a single hard-coded solver, ORE exposes configuration fields for every stage of the interpolation and bootstrapping math:&lt;/p>
&lt;h4 id="a-interpolation-variables">A. Interpolation Variables&lt;/h4>
&lt;p>You can choose the domain on which interpolation is performed (&lt;code>&amp;lt;InterpolationVariable&amp;gt;&lt;/code>):&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>Discount&lt;/code>&lt;/strong> (Default): Interpolates discount factors directly.&lt;/li>
&lt;li>&lt;strong>&lt;code>Zero&lt;/code>&lt;/strong>: Interpolates continuously compounded zero rates.&lt;/li>
&lt;li>&lt;strong>&lt;code>Forward&lt;/code>&lt;/strong>: Interpolates instantaneous forward rates.&lt;/li>
&lt;/ul>
&lt;h4 id="b-interpolation-methods">B. Interpolation Methods&lt;/h4>
&lt;p>ORE supports a wide variety of interpolation algorithms (&lt;code>&amp;lt;InterpolationMethod&amp;gt;&lt;/code>), letting you select the method that best aligns with your risk and pricing needs:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>Linear&lt;/code>&lt;/strong> / &lt;strong>&lt;code>LogLinear&lt;/code>&lt;/strong>: Simple and robust. &lt;code>LogLinear&lt;/code> interpolation on &lt;code>Discount&lt;/code> factors is equivalent to assuming piecewise-constant forward rates (flat forwards)—a standard market choice.&lt;/li>
&lt;li>&lt;strong>&lt;code>NaturalCubic&lt;/code>&lt;/strong> / &lt;strong>&lt;code>FinancialCubic&lt;/code>&lt;/strong>: Smoother cubic spline variants. &lt;code>FinancialCubic&lt;/code> ensures zero second derivative at the left edge and zero first derivative at the right edge.&lt;/li>
&lt;li>&lt;strong>&lt;code>ConvexMonotone&lt;/code>&lt;/strong>: Hagan &amp;amp; West&amp;rsquo;s method, designed to preserve convexity and monotonicity of forward rates.&lt;/li>
&lt;li>&lt;strong>&lt;code>LogNaturalCubic&lt;/code>&lt;/strong> / &lt;strong>&lt;code>LogFinancialCubic&lt;/code>&lt;/strong> / &lt;strong>&lt;code>LogCubicSpline&lt;/code>&lt;/strong>: Cubic splines applied in the natural log domain of the target variable.&lt;/li>
&lt;li>&lt;strong>&lt;code>BackwardFlat&lt;/code>&lt;/strong>: Piecewise constant, right-continuous interpolation.&lt;/li>
&lt;/ul>
&lt;h4 id="c-handling-the-t_0-reference-date">C. Handling the $t_0$ Reference Date&lt;/h4>
&lt;p>The optional &lt;code>&amp;lt;ExcludeT0FromInterpolation&amp;gt;&lt;/code> element (set to &lt;code>True&lt;/code> or &lt;code>False&lt;/code>) lets you exclude the synthetic time-zero ($t_0$) reference point (where $DF=1.0$) from the interpolation grid. When set to &lt;code>True&lt;/code>, the curve interpolates strictly on actual market pillar dates, using flat zero/forward rates between $t_0$ and the first pillar. This avoids forcing a synthetic anchor point that can distort the short end of the curve.&lt;/p>
&lt;h4 id="d-bootstrapping-precision--performance">D. Bootstrapping Precision &amp;amp; Performance&lt;/h4>
&lt;p>Under the optional &lt;code>&amp;lt;BootstrapConfig&amp;gt;&lt;/code> node, ORE exposes parameters for the iterative root-finding procedure:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>&amp;lt;Accuracy&amp;gt;&lt;/code>&lt;/strong> (Default: &lt;code>1e-12&lt;/code>): The desired tolerance for the root-finding solver to match market quotes.&lt;/li>
&lt;li>&lt;strong>&lt;code>&amp;lt;GlobalAccuracy&amp;gt;&lt;/code>&lt;/strong>: Tolerable fallback accuracy if target accuracy cannot be met.&lt;/li>
&lt;li>&lt;strong>&lt;code>&amp;lt;DontThrow&amp;gt;&lt;/code>&lt;/strong>: If set to &lt;code>True&lt;/code>, ORE will continue execution using the best fit found rather than throwing an exception if the global accuracy check fails.&lt;/li>
&lt;li>&lt;strong>&lt;code>&amp;lt;MaxAttempts&amp;gt;&lt;/code>&lt;/strong> (Default: &lt;code>5&lt;/code>): Maximum attempts/seed trials for fitting complex curves (like Fitted Bond curves using Nelson-Siegel or Svensson methods).&lt;/li>
&lt;li>&lt;strong>&lt;code>&amp;lt;ExtrapolationMethod&amp;gt;&lt;/code>&lt;/strong>: Controls curve tails using &lt;code>ContinuousForward&lt;/code> (flat instantaneous forwards) or &lt;code>DiscreteForward&lt;/code> (flat daily forwards).&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="5-bootstrapping-and-plotting-in-python">5. Bootstrapping and Plotting in Python&lt;/h2>
&lt;p>We can execute the entire calibration run and extract the zero rates directly in a Python script. ORE reads our master execution config (&lt;code>ore.xml&lt;/code>) and calibrates the curve.&lt;/p>
&lt;p>Here is the Python script to run the bootstrapping and plot the zero curve:&lt;/p>
&lt;pre>&lt;code class="language-python">import os
import ORE as ore
import csv
import matplotlib.pyplot as plt
from pathlib import Path
# Set up base path relative to this script
BASE_DIR = Path(__file__).parent.resolve()
INPUT_DIR = BASE_DIR / &amp;quot;Input&amp;quot;
OUTPUT_DIR = BASE_DIR / &amp;quot;Output&amp;quot;
os.makedirs(OUTPUT_DIR, exist_ok=True)
# 1. Run the ORE App
params = ore.Parameters()
params.fromFile(str(INPUT_DIR / &amp;quot;ore.xml&amp;quot;))
app = ore.OREApp(params)
app.run()
print(&amp;quot;\n--- ORE Run Completed Successfully ---\n&amp;quot;)
# 2. Extract bootstrapped curve rates
analytic = app.getAnalytic(&amp;quot;NPV&amp;quot;)
market = analytic.getMarket()
curve = market.discountCurve(&amp;quot;USD&amp;quot;)
tenors = {
&amp;quot;1M&amp;quot;: 1/12,
&amp;quot;3M&amp;quot;: 0.25,
&amp;quot;6M&amp;quot;: 0.5,
&amp;quot;1Y&amp;quot;: 1.0,
&amp;quot;2Y&amp;quot;: 2.0,
&amp;quot;5Y&amp;quot;: 5.0,
&amp;quot;10Y&amp;quot;: 10.0,
&amp;quot;30Y&amp;quot;: 30.0
}
times = []
zero_rates = []
print(&amp;quot;Discount Factors and Zero Rates (as of 2023-01-31):&amp;quot;)
print(f&amp;quot;{'Tenor':&amp;lt;8} {'Time (y)':&amp;lt;10} {'Discount Factor':&amp;lt;18} {'Zero Rate (%)':&amp;lt;15}&amp;quot;)
print(&amp;quot;-&amp;quot; * 55)
for name, t in tenors.items():
df = curve.discount(t)
zero = curve.zeroRate(t, ore.Compounded, ore.Annual).rate()
times.append(t)
zero_rates.append(zero * 100)
print(f&amp;quot;{name:&amp;lt;8} {t:&amp;lt;10.4f} {df:&amp;lt;18.8f} {zero*100:&amp;lt;15.4f}%&amp;quot;)
# 3. Plot the zero curve
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(times, zero_rates, marker=&amp;quot;o&amp;quot;, linewidth=2, color=&amp;quot;steelblue&amp;quot;, label=&amp;quot;USD SOFR Zero Rate&amp;quot;)
ax.set_xlabel(&amp;quot;Time (years)&amp;quot;)
ax.set_ylabel(&amp;quot;Zero Rate (%)&amp;quot;)
ax.set_title(&amp;quot;Bootstrapped USD SOFR Zero Curve (As of 2023-01-31)&amp;quot;)
ax.legend()
ax.grid(True, linestyle=&amp;quot;--&amp;quot;, alpha=0.5)
plt.tight_layout()
plt.savefig(&amp;quot;zero_curve.png&amp;quot;, dpi=150)
plt.show()
print(&amp;quot;Zero curve saved to zero_curve.png&amp;quot;)
&lt;/code>&lt;/pre>
&lt;p>When we run this script, we obtain the zero-rate curve plot shown below:&lt;/p>
&lt;figure>
&lt;a data-fancybox="" href="zero_curve.png" data-caption="Bootstrapped USD SOFR Zero Curve (As of 2023-01-31)">
&lt;img data-src="zero_curve.png" class="lazyload" alt="" >&lt;/a>
&lt;figcaption>
Bootstrapped USD SOFR Zero Curve (As of 2023-01-31)
&lt;/figcaption>
&lt;/figure>
&lt;hr>
&lt;h2 id="6-under-the-hood-ore-calibration-reports">6. Under the Hood: ORE Calibration Reports&lt;/h2>
&lt;p>One of the most powerful features added in recent ORE releases is the automatic generation of detailed calibration reports. In the execution output, you will find &lt;code>todaysmarketcalibration.csv&lt;/code> and &lt;code>todaysmarketcalibration_cashflows.csv&lt;/code> under the &lt;code>Output&lt;/code> directory.&lt;/p>
&lt;p>For anyone trying to understand the mechanics of the bootstrap, &lt;strong>&lt;code>todaysmarketcalibration_cashflows.csv&lt;/code> is an absolute goldmine.&lt;/strong>&lt;/p>
&lt;p>Instead of treating the bootstrap as a black-box mathematical solver, ORE writes out the complete cashflow schedule of every rate helper instrument utilized in the curve calibration. For each instrument (e.g., our USD SOFR OIS swaps), the report details:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Pillar Dates&lt;/strong> and Accrual Start/End Dates.&lt;/li>
&lt;li>&lt;strong>Projected Interest Amounts&lt;/strong> and Accrual Fractions.&lt;/li>
&lt;li>&lt;strong>Fixing Dates&lt;/strong> and Forward Rate Fixing Values.&lt;/li>
&lt;li>&lt;strong>Discount Factors&lt;/strong> and &lt;strong>Present Values (PV)&lt;/strong> of both legs.&lt;/li>
&lt;/ul>
&lt;p>Having direct visibility into these details significantly speeds up the implementation and debugging process. Day-count fraction errors or payment lag mismatches become instantly noticeable as you inspect the exact schedules and discount factors used.&lt;/p>
&lt;p>To see this in action, here is an extract of the cashflows for the &lt;strong>2Y OIS Swap&lt;/strong> (market fixed quote: &lt;code>4.27805%&lt;/code>) from the report. It shows how the Fixed and Floating legs are structured:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Leg&lt;/th>
&lt;th style="text-align:left">Pay Date&lt;/th>
&lt;th style="text-align:left">Accrual Start&lt;/th>
&lt;th style="text-align:left">Accrual End&lt;/th>
&lt;th style="text-align:left">Accrual Fraction&lt;/th>
&lt;th style="text-align:left">Rate (%)&lt;/th>
&lt;th style="text-align:left">Discount Factor&lt;/th>
&lt;th style="text-align:left">Present Value (USD)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Fixed&lt;/strong>&lt;/td>
&lt;td style="text-align:left">2024-02-02&lt;/td>
&lt;td style="text-align:left">2023-01-31&lt;/td>
&lt;td style="text-align:left">2024-01-31&lt;/td>
&lt;td style="text-align:left">1.013889&lt;/td>
&lt;td style="text-align:left">4.27805%&lt;/td>
&lt;td style="text-align:left">0.952687&lt;/td>
&lt;td style="text-align:left">41,322.50&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Fixed&lt;/strong>&lt;/td>
&lt;td style="text-align:left">2025-02-04&lt;/td>
&lt;td style="text-align:left">2024-01-31&lt;/td>
&lt;td style="text-align:left">2025-01-31&lt;/td>
&lt;td style="text-align:left">1.016667&lt;/td>
&lt;td style="text-align:left">4.27805%&lt;/td>
&lt;td style="text-align:left">0.918343&lt;/td>
&lt;td style="text-align:left">39,941.96&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Floating&lt;/strong> ¹&lt;/td>
&lt;td style="text-align:left">2024-02-02&lt;/td>
&lt;td style="text-align:left">2023-01-31&lt;/td>
&lt;td style="text-align:left">2024-01-31&lt;/td>
&lt;td style="text-align:left">1.013889&lt;/td>
&lt;td style="text-align:left">4.87100%&lt;/td>
&lt;td style="text-align:left">0.952687&lt;/td>
&lt;td style="text-align:left">-47,049.92&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Floating&lt;/strong> ¹&lt;/td>
&lt;td style="text-align:left">2025-02-04&lt;/td>
&lt;td style="text-align:left">2024-01-31&lt;/td>
&lt;td style="text-align:left">2025-01-31&lt;/td>
&lt;td style="text-align:left">1.016667&lt;/td>
&lt;td style="text-align:left">3.66461%&lt;/td>
&lt;td style="text-align:left">0.918343&lt;/td>
&lt;td style="text-align:left">-34,214.54&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>¹ On an OIS floating leg, no single overnight rate is fixed in advance. Instead, the daily SOFR fixings are compounded over each accrual period. The rates shown above (4.87100% for Period 1 and 3.66461% for Period 2) are the &lt;strong>equivalent flat rate&lt;/strong> that would produce the same compounded interest amount over the period—sometimes called the projected par coupon rate. Period 1&amp;rsquo;s rate exactly matches the 1Y market quote (4.871%), which makes sense: the 1Y OIS calibration instrument was already bootstrapped, and its projected compounded rate &lt;em>is&lt;/em> the 1Y fair rate. Period 2&amp;rsquo;s rate (3.665%) is what the bootstrapper must &lt;em>solve for&lt;/em> to make the 2Y swap price at par.&lt;/p>
&lt;/blockquote>
&lt;p>Summing the present values:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Fixed Leg PV&lt;/strong>: $+81,264.46$ USD&lt;/li>
&lt;li>&lt;strong>Floating Leg PV&lt;/strong>: $-81,264.46$ USD&lt;/li>
&lt;li>&lt;strong>Net Swap NPV&lt;/strong>: &lt;strong>$0.00$ USD&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>This demonstrates the mathematical core of the bootstrap: the solver finds the equivalent compounded forward rate for the second period (&lt;code>3.66461%&lt;/code>) such that the floating leg PV exactly matches the fixed leg PV.&lt;/p>
&lt;hr>
&lt;h2 id="date-derivation">7. From Conventions to Dates — A Worked Example&lt;/h2>
&lt;p>The cashflow report above is where we can see the exact output of ORE&amp;rsquo;s date math. Rather than being magic numbers, every single date and accrual fraction here is a direct, deterministic consequence of the as-of date, the instrument tenor, and the conventions.&lt;/p>
&lt;p>For our 2Y USD SOFR swap, ORE picks up the conventions from the &lt;code>&amp;lt;Conventions&amp;gt;USD-SOFR-OIS&amp;lt;/Conventions&amp;gt;&lt;/code> node in &lt;code>curveconfig.xml&lt;/code>. This refers back to the matching &lt;code>&amp;lt;OIS&amp;gt;&lt;/code> convention block in &lt;code>conventions.xml&lt;/code> containing &lt;code>SpotLag&lt;/code>, &lt;code>PaymentLag&lt;/code>, &lt;code>FixedDayCounter&lt;/code>, &lt;code>Rule&lt;/code>, etc.&lt;/p>
&lt;p>Here is how ORE resolves the dates step-by-step for the 2Y instrument:&lt;/p>
&lt;h3 id="step-1--determine-the-start-date-spotlag--0">Step 1 — Determine the Start Date (&lt;code>SpotLag = 0&lt;/code>)&lt;/h3>
&lt;p>Our market data &lt;code>as-of&lt;/code> date is &lt;strong>2023-01-31&lt;/strong>. Since &lt;code>&amp;lt;SpotLag&amp;gt;&lt;/code> is set to &lt;code>0&lt;/code>, there is no settlement delay. The swap starts immediately on the trade date:&lt;/p>
&lt;p>$$\text{Start Date} = \text{2023-01-31} + 0 \ \text{business days} = \textbf{2023-01-31}$$&lt;/p>
&lt;h3 id="step-2--determine-the-end-date-tenor--2y">Step 2 — Determine the End Date (Tenor = 2Y)&lt;/h3>
&lt;p>Adding the 2Y tenor to our start date gives the unadjusted end date:&lt;/p>
&lt;p>$$\text{Unadjusted End} = \text{2023-01-31} + 2Y = \text{2025-01-31}$$&lt;/p>
&lt;p>Since January 31, 2025 is a Friday (a valid business day), no business day adjustment is needed. The maturity date is &lt;strong>2025-01-31&lt;/strong>.&lt;/p>
&lt;h3 id="step-3--generate-the-schedule-rule--backward">Step 3 — Generate the Schedule (&lt;code>Rule = Backward&lt;/code>)&lt;/h3>
&lt;p>Because the schedule rule is set to &lt;code>Backward&lt;/code>, ORE builds the schedule by stepping back from the maturity date in annual increments (based on &lt;code>&amp;lt;FixedFrequency&amp;gt;Annual&amp;lt;/FixedFrequency&amp;gt;&lt;/code>):&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Step&lt;/th>
&lt;th style="text-align:left">Date&lt;/th>
&lt;th style="text-align:left">Adjustment&lt;/th>
&lt;th style="text-align:left">Result&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">Maturity&lt;/td>
&lt;td style="text-align:left">2025-01-31&lt;/td>
&lt;td style="text-align:left">—&lt;/td>
&lt;td style="text-align:left">&lt;strong>2025-01-31&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">−1Y&lt;/td>
&lt;td style="text-align:left">2024-01-31&lt;/td>
&lt;td style="text-align:left">Valid business day&lt;/td>
&lt;td style="text-align:left">&lt;strong>2024-01-31&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">−2Y&lt;/td>
&lt;td style="text-align:left">2023-01-31&lt;/td>
&lt;td style="text-align:left">Valid business day (= Start)&lt;/td>
&lt;td style="text-align:left">&lt;strong>2023-01-31&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>This gives us two accrual periods:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Period 1&lt;/strong>: &lt;code>2023-01-31&lt;/code> to &lt;code>2024-01-31&lt;/code>&lt;/li>
&lt;li>&lt;strong>Period 2&lt;/strong>: &lt;code>2024-01-31&lt;/code> to &lt;code>2025-01-31&lt;/code>&lt;/li>
&lt;/ul>
&lt;h3 id="step-4--calculate-payment-dates-paymentlag--2">Step 4 — Calculate Payment Dates (&lt;code>PaymentLag = 2&lt;/code>)&lt;/h3>
&lt;p>Payments are made 2 business days after the end of each accrual period, adjusted using the &lt;strong>Modified Following&lt;/strong> (&lt;code>MF&lt;/code>) business day convention:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Accrual End&lt;/th>
&lt;th style="text-align:left">+2 bd&lt;/th>
&lt;th style="text-align:left">Payment Date&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">2024-01-31 (Wed)&lt;/td>
&lt;td style="text-align:left">→ 2024-02-01 (Thu) → 2024-02-02 (Fri)&lt;/td>
&lt;td style="text-align:left">&lt;strong>2024-02-02&lt;/strong> ✓&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">2025-01-31 (Fri)&lt;/td>
&lt;td style="text-align:left">→ 2025-02-03 (Mon) → 2025-02-04 (Tue)&lt;/td>
&lt;td style="text-align:left">&lt;strong>2025-02-04&lt;/strong> ✓&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>These dates match the &lt;code>PayDate&lt;/code> values in our cashflow report exactly.&lt;/p>
&lt;h3 id="step-5--calculate-accrual-fractions-fixeddaycounter--a360">Step 5 — Calculate Accrual Fractions (&lt;code>FixedDayCounter = A360&lt;/code>)&lt;/h3>
&lt;p>Using the Actual/360 convention, we divide the actual number of calendar days in the period by 360:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Period&lt;/th>
&lt;th style="text-align:left">Start&lt;/th>
&lt;th style="text-align:left">End&lt;/th>
&lt;th style="text-align:left">Actual Days&lt;/th>
&lt;th style="text-align:left">Fraction (days/360)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">1&lt;/td>
&lt;td style="text-align:left">2023-01-31&lt;/td>
&lt;td style="text-align:left">2024-01-31&lt;/td>
&lt;td style="text-align:left">365&lt;/td>
&lt;td style="text-align:left">$365 / 360 = \mathbf{1.013889}$ ✓&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">2&lt;/td>
&lt;td style="text-align:left">2024-01-31&lt;/td>
&lt;td style="text-align:left">2025-01-31&lt;/td>
&lt;td style="text-align:left">366&lt;/td>
&lt;td style="text-align:left">$366 / 360 = \mathbf{1.016667}$ ✓&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Note that 2024 is a leap year, so the second period contains 366 calendar days, yielding the slightly larger accrual fraction seen in the report.&lt;/p>
&lt;h3 id="step-6--calculate-the-fixed-coupon-amount">Step 6 — Calculate the Fixed Coupon Amount&lt;/h3>
&lt;p>With a fixed rate of &lt;code>4.27805%&lt;/code> and a $1,000,000 notional, the coupon for the first period is:&lt;/p>
&lt;p>$$\text{Coupon}_1 = 1{,}000{,}000 \times 0.0427805 \times 1.013889 = \mathbf{$43{,}374.67}\text{ USD}$$&lt;/p>
&lt;p>Discounting this cashflow with the bootstrapped 1Y discount factor of &lt;code>0.952687&lt;/code> gives:&lt;/p>
&lt;p>$$\text{PV}_1 = 43{,}374.67 \times 0.952687 = \mathbf{$41{,}322.50}\text{ USD}$$&lt;/p>
&lt;p>Both figures reconcile perfectly with the values in the ORE calibration report. Everything falls out cleanly from just a few parameters: the start date, the tenor, spot lag, frequency, payment lag, and day count convention.&lt;/p>
&lt;hr>
&lt;h2 id="8-verification--the-zero-pv-repricing-check">8. Verification — The Zero-PV Repricing Check&lt;/h2>
&lt;p>A successful bootstrap means that the constructed curve must perfectly replicate the market prices of the instruments used to build it. To prove this, we construct a portfolio of matching OIS swaps in &lt;code>portfolio.xml&lt;/code> (e.g., matching the 1M, 1Y, and 5Y points with the respective market fixed rates) and price them against our newly constructed curve:&lt;/p>
&lt;pre>&lt;code class="language-xml">&amp;lt;Portfolio&amp;gt;
&amp;lt;Trade id=&amp;quot;OIS_5Y&amp;quot;&amp;gt;
&amp;lt;TradeType&amp;gt;Swap&amp;lt;/TradeType&amp;gt;
&amp;lt;Envelope&amp;gt;
&amp;lt;CounterParty&amp;gt;CPTY_A&amp;lt;/CounterParty&amp;gt;
&amp;lt;NettingSetId&amp;gt;CPTY_A&amp;lt;/NettingSetId&amp;gt;
&amp;lt;AdditionalFields/&amp;gt;
&amp;lt;/Envelope&amp;gt;
&amp;lt;SwapData&amp;gt;
&amp;lt;LegData&amp;gt;
&amp;lt;LegType&amp;gt;Fixed&amp;lt;/LegType&amp;gt;
&amp;lt;Payer&amp;gt;false&amp;lt;/Payer&amp;gt;
&amp;lt;Currency&amp;gt;USD&amp;lt;/Currency&amp;gt;
&amp;lt;Notionals&amp;gt;&amp;lt;Notional&amp;gt;10000000&amp;lt;/Notional&amp;gt;&amp;lt;/Notionals&amp;gt;
&amp;lt;DayCounter&amp;gt;A360&amp;lt;/DayCounter&amp;gt;
&amp;lt;PaymentConvention&amp;gt;ModifiedFollowing&amp;lt;/PaymentConvention&amp;gt;
&amp;lt;PaymentLag&amp;gt;2&amp;lt;/PaymentLag&amp;gt;
&amp;lt;FixedLegData&amp;gt;&amp;lt;Rates&amp;gt;&amp;lt;Rate&amp;gt;0.034610&amp;lt;/Rate&amp;gt;&amp;lt;/Rates&amp;gt;&amp;lt;/FixedLegData&amp;gt;
&amp;lt;ScheduleData&amp;gt;
&amp;lt;Rules&amp;gt;
&amp;lt;StartDate&amp;gt;2023-01-31&amp;lt;/StartDate&amp;gt;
&amp;lt;EndDate&amp;gt;2028-01-31&amp;lt;/EndDate&amp;gt;
&amp;lt;Tenor&amp;gt;1Y&amp;lt;/Tenor&amp;gt;
&amp;lt;Calendar&amp;gt;US&amp;lt;/Calendar&amp;gt;
&amp;lt;Convention&amp;gt;ModifiedFollowing&amp;lt;/Convention&amp;gt;
&amp;lt;TermConvention&amp;gt;ModifiedFollowing&amp;lt;/TermConvention&amp;gt;
&amp;lt;Rule&amp;gt;Backward&amp;lt;/Rule&amp;gt;
&amp;lt;/Rules&amp;gt;
&amp;lt;/ScheduleData&amp;gt;
&amp;lt;/LegData&amp;gt;
&amp;lt;LegData&amp;gt;
&amp;lt;LegType&amp;gt;Floating&amp;lt;/LegType&amp;gt;
&amp;lt;Payer&amp;gt;true&amp;lt;/Payer&amp;gt;
&amp;lt;Currency&amp;gt;USD&amp;lt;/Currency&amp;gt;
&amp;lt;Notionals&amp;gt;&amp;lt;Notional&amp;gt;10000000&amp;lt;/Notional&amp;gt;&amp;lt;/Notionals&amp;gt;
&amp;lt;DayCounter&amp;gt;A360&amp;lt;/DayCounter&amp;gt;
&amp;lt;PaymentLag&amp;gt;2&amp;lt;/PaymentLag&amp;gt;
&amp;lt;PaymentConvention&amp;gt;ModifiedFollowing&amp;lt;/PaymentConvention&amp;gt;
&amp;lt;FloatingLegData&amp;gt;
&amp;lt;Index&amp;gt;USD-SOFR&amp;lt;/Index&amp;gt;
&amp;lt;/FloatingLegData&amp;gt;
&amp;lt;ScheduleData&amp;gt;
&amp;lt;Rules&amp;gt;
&amp;lt;StartDate&amp;gt;2023-01-31&amp;lt;/StartDate&amp;gt;
&amp;lt;EndDate&amp;gt;2028-01-31&amp;lt;/EndDate&amp;gt;
&amp;lt;Tenor&amp;gt;1Y&amp;lt;/Tenor&amp;gt;
&amp;lt;Calendar&amp;gt;US&amp;lt;/Calendar&amp;gt;
&amp;lt;Convention&amp;gt;ModifiedFollowing&amp;lt;/Convention&amp;gt;
&amp;lt;TermConvention&amp;gt;ModifiedFollowing&amp;lt;/TermConvention&amp;gt;
&amp;lt;Rule&amp;gt;Backward&amp;lt;/Rule&amp;gt;
&amp;lt;/Rules&amp;gt;
&amp;lt;/ScheduleData&amp;gt;
&amp;lt;/LegData&amp;gt;
&amp;lt;/SwapData&amp;gt;
&amp;lt;/Trade&amp;gt;
&amp;lt;/Portfolio&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>When ORE prices these trades using the bootstrapped curve, the output reports NPVs of exactly &lt;strong>0.000000&lt;/strong>:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Trade ID&lt;/th>
&lt;th style="text-align:left">Leg 1 Type&lt;/th>
&lt;th style="text-align:left">Leg 2 Type&lt;/th>
&lt;th style="text-align:left">Notional (USD)&lt;/th>
&lt;th style="text-align:left">NPV (USD)&lt;/th>
&lt;th style="text-align:left">Base NPV (USD)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>OIS_1M&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Fixed&lt;/td>
&lt;td style="text-align:left">Floating&lt;/td>
&lt;td style="text-align:left">10,000,000.00&lt;/td>
&lt;td style="text-align:left">0.000000&lt;/td>
&lt;td style="text-align:left">0.000000&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>OIS_1Y&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Fixed&lt;/td>
&lt;td style="text-align:left">Floating&lt;/td>
&lt;td style="text-align:left">10,000,000.00&lt;/td>
&lt;td style="text-align:left">0.000000&lt;/td>
&lt;td style="text-align:left">0.000000&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>OIS_5Y&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Fixed&lt;/td>
&lt;td style="text-align:left">Floating&lt;/td>
&lt;td style="text-align:left">10,000,000.00&lt;/td>
&lt;td style="text-align:left">0.000000&lt;/td>
&lt;td style="text-align:left">0.000000&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>This confirms that our bootstrapping configuration is consistent and perfectly reproduces the input market quotes.&lt;/p>
&lt;hr>
&lt;h2 id="9-sanity-check--breaking-the-linkage">9. Sanity Check — Breaking the Linkage&lt;/h2>
&lt;p>To demonstrate that our zero-PV result is a meaningful validation of the bootstrap rather than a configuration triviality, we can introduce a deliberate mismatch. If we perturb one of the swap fixed rates in our portfolio to &lt;code>3.561%&lt;/code> (+10 bps) &lt;em>without&lt;/em> rebuilding the curve, and re-price:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Trade ID&lt;/th>
&lt;th style="text-align:left">NPV (USD)&lt;/th>
&lt;th style="text-align:left">Base NPV (USD)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>OIS_5Y&lt;/strong>&lt;/td>
&lt;td style="text-align:left">45,379.995138&lt;/td>
&lt;td style="text-align:left">45,379.995138&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The NPV deviates significantly from zero. This demonstrates that the zero-PV check is highly sensitive to the exact alignment between the curve calibration quotes and the trade valuation models.&lt;/p>
&lt;hr>
&lt;h2 id="10-testing-ore-against-your-existing-system">10. Testing ORE Against Your Existing System&lt;/h2>
&lt;p>If you are looking to integrate ORE into your workflow, the best way to start is by testing it against your current library or legacy pricing system. This is typically an iterative process:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Align on Conventions &amp;amp; Market Data&lt;/strong>: Ensure your day-count conventions, calendar adjustment rules, holiday calendars, spot lags, and market rate inputs (in &lt;code>market.txt&lt;/code>) are exactly identical to your current system.&lt;/li>
&lt;li>&lt;strong>Replicate the Curve Configuration&lt;/strong>: Re-create the interpolation method (e.g., LogLinear discount factor interpolation) and segment definitions.&lt;/li>
&lt;li>&lt;strong>Compare Discount Factors&lt;/strong>: Calibrate the curves in both systems for the same as-of date and compare the resulting discount factors at various tenors.&lt;/li>
&lt;/ol>
&lt;p>Discrepancies during this comparison are common and usually trace back to subtle differences in schedule rules or accrual fraction calculations. This is where ORE&amp;rsquo;s new &lt;strong>&lt;code>todaysmarketcalibration_cashflows.csv&lt;/code>&lt;/strong> report becomes invaluable. By comparing ORE&amp;rsquo;s detailed cashflow schedule and discount factors side-by-side with vendor libraries, you can pinpoint the exact payment date or compounding difference causing the divergence, drastically reducing integration time.&lt;/p>
&lt;p>By following this disciplined comparison, you can gain high confidence in ORE&amp;rsquo;s open-source calculations. But establishing a solid, verified bootstrap is just the first step. Once you have matching curves, you unlock the ability to leverage ORE&amp;rsquo;s wider ecosystem for full portfolio valuation, XVA, historical simulation, and market risk analytics. Reconciling your curves is the ideal foundation for a much broader ORE integration journey.&lt;/p>
&lt;h3 id="source-code">Source Code&lt;/h3>
&lt;p>All configuration files and the Python script used in this post are available for download &lt;a href="https://obrienjoey.github.io/post/ore_sofr_bootstrap/ore_sofr_bootstrap_files.zip">here&lt;/a>.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Disclaimer: The minimal ORE inputs utilized in this post, along with the featured graphics, were generated and coordinated using Gemini 3.5 Flash and Nano Banana 2.&lt;/em>&lt;/p></description></item></channel></rss>