cdsmodel 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. cdsmodel-0.1.0/.clang-format +3 -0
  2. cdsmodel-0.1.0/.clangd +6 -0
  3. cdsmodel-0.1.0/.editorconfig +18 -0
  4. cdsmodel-0.1.0/.gitattributes +3 -0
  5. cdsmodel-0.1.0/.gitignore +58 -0
  6. cdsmodel-0.1.0/CLAUDE.md +328 -0
  7. cdsmodel-0.1.0/CMakeLists.txt +529 -0
  8. cdsmodel-0.1.0/CMakePresets.json +104 -0
  9. cdsmodel-0.1.0/LICENSE +32 -0
  10. cdsmodel-0.1.0/NOTICE.md +49 -0
  11. cdsmodel-0.1.0/PKG-INFO +256 -0
  12. cdsmodel-0.1.0/README.md +238 -0
  13. cdsmodel-0.1.0/cmake/cdsmodelConfig.cmake.in +12 -0
  14. cdsmodel-0.1.0/include/cdsmodel/bad_day.hpp +167 -0
  15. cdsmodel-0.1.0/include/cdsmodel/bad_day_map.hpp +191 -0
  16. cdsmodel-0.1.0/include/cdsmodel/bootstrap.hpp +239 -0
  17. cdsmodel-0.1.0/include/cdsmodel/bsearch.hpp +128 -0
  18. cdsmodel-0.1.0/include/cdsmodel/business_days.hpp +300 -0
  19. cdsmodel-0.1.0/include/cdsmodel/calendar.hpp +203 -0
  20. cdsmodel-0.1.0/include/cdsmodel/cash_flow_bootstrap.hpp +394 -0
  21. cdsmodel-0.1.0/include/cdsmodel/cash_flow_list.hpp +191 -0
  22. cdsmodel-0.1.0/include/cdsmodel/cash_flow_schedule.hpp +416 -0
  23. cdsmodel-0.1.0/include/cdsmodel/cds.hpp +340 -0
  24. cdsmodel-0.1.0/include/cdsmodel/cdsmodel.hpp +66 -0
  25. cdsmodel-0.1.0/include/cdsmodel/cdsone.hpp +160 -0
  26. cdsmodel-0.1.0/include/cdsmodel/contingent_leg.hpp +252 -0
  27. cdsmodel-0.1.0/include/cdsmodel/coupon_schedule.hpp +506 -0
  28. cdsmodel-0.1.0/include/cdsmodel/curve_discount.hpp +114 -0
  29. cdsmodel-0.1.0/include/cdsmodel/curve_instruments.hpp +378 -0
  30. cdsmodel-0.1.0/include/cdsmodel/curve_linear_interp.hpp +154 -0
  31. cdsmodel-0.1.0/include/cdsmodel/curve_rates.hpp +178 -0
  32. cdsmodel-0.1.0/include/cdsmodel/date.hpp +464 -0
  33. cdsmodel-0.1.0/include/cdsmodel/date_adjust.hpp +147 -0
  34. cdsmodel-0.1.0/include/cdsmodel/date_interval.hpp +284 -0
  35. cdsmodel-0.1.0/include/cdsmodel/date_list.hpp +232 -0
  36. cdsmodel-0.1.0/include/cdsmodel/date_schedule.hpp +327 -0
  37. cdsmodel-0.1.0/include/cdsmodel/date_sup.hpp +237 -0
  38. cdsmodel-0.1.0/include/cdsmodel/day_count.hpp +206 -0
  39. cdsmodel-0.1.0/include/cdsmodel/day_count_string.hpp +173 -0
  40. cdsmodel-0.1.0/include/cdsmodel/defaulted.hpp +150 -0
  41. cdsmodel-0.1.0/include/cdsmodel/expected.hpp +235 -0
  42. cdsmodel-0.1.0/include/cdsmodel/fee_leg.hpp +410 -0
  43. cdsmodel-0.1.0/include/cdsmodel/float_rate.hpp +159 -0
  44. cdsmodel-0.1.0/include/cdsmodel/holiday_file.hpp +55 -0
  45. cdsmodel-0.1.0/include/cdsmodel/interp_curve.hpp +285 -0
  46. cdsmodel-0.1.0/include/cdsmodel/interpolation.hpp +334 -0
  47. cdsmodel-0.1.0/include/cdsmodel/ir_zero_curve.hpp +188 -0
  48. cdsmodel-0.1.0/include/cdsmodel/match_range.hpp +231 -0
  49. cdsmodel-0.1.0/include/cdsmodel/rate_conversion.hpp +313 -0
  50. cdsmodel-0.1.0/include/cdsmodel/root_find.hpp +430 -0
  51. cdsmodel-0.1.0/include/cdsmodel/schedule.hpp +112 -0
  52. cdsmodel-0.1.0/include/cdsmodel/stream_cash_flows.hpp +458 -0
  53. cdsmodel-0.1.0/include/cdsmodel/stub.hpp +347 -0
  54. cdsmodel-0.1.0/include/cdsmodel/swap_bootstrap.hpp +508 -0
  55. cdsmodel-0.1.0/include/cdsmodel/swap_bootstrap_flows.hpp +187 -0
  56. cdsmodel-0.1.0/include/cdsmodel/swap_dates.hpp +297 -0
  57. cdsmodel-0.1.0/include/cdsmodel/timeline.hpp +102 -0
  58. cdsmodel-0.1.0/include/cdsmodel/version.hpp +17 -0
  59. cdsmodel-0.1.0/include/cdsmodel/zero_curve.hpp +404 -0
  60. cdsmodel-0.1.0/include/cdsmodel/zero_curve_builder.hpp +814 -0
  61. cdsmodel-0.1.0/pyproject.toml +104 -0
  62. cdsmodel-0.1.0/python/CMakeLists.txt +36 -0
  63. cdsmodel-0.1.0/python/cdsmodel/__init__.py +115 -0
  64. cdsmodel-0.1.0/python/cdsmodel/_core.pyi +560 -0
  65. cdsmodel-0.1.0/python/cdsmodel/py.typed +0 -0
  66. cdsmodel-0.1.0/python/src/blocks.hpp +111 -0
  67. cdsmodel-0.1.0/python/src/calendars.cpp +79 -0
  68. cdsmodel-0.1.0/python/src/credit_curve.cpp +117 -0
  69. cdsmodel-0.1.0/python/src/curves.cpp +105 -0
  70. cdsmodel-0.1.0/python/src/date_caster.hpp +39 -0
  71. cdsmodel-0.1.0/python/src/errors.cpp +41 -0
  72. cdsmodel-0.1.0/python/src/errors.hpp +65 -0
  73. cdsmodel-0.1.0/python/src/instruments.cpp +111 -0
  74. cdsmodel-0.1.0/python/src/module.cpp +45 -0
  75. cdsmodel-0.1.0/python/src/pricing.cpp +105 -0
  76. cdsmodel-0.1.0/python/src/types.cpp +190 -0
  77. cdsmodel-0.1.0/requirements-dev.txt +4 -0
  78. cdsmodel-0.1.0/src/holiday_file.cpp +157 -0
  79. cdsmodel-0.1.0/src/version.cpp +15 -0
  80. cdsmodel-0.1.0/verify.py +946 -0
@@ -0,0 +1,3 @@
1
+ BasedOnStyle: LLVM
2
+ IndentWidth: 2
3
+ ColumnLimit: 100
cdsmodel-0.1.0/.clangd ADDED
@@ -0,0 +1,6 @@
1
+ CompileFlags:
2
+ CompilationDatabase: .
3
+ Add: [-std=c++20]
4
+ Diagnostics:
5
+ UnusedIncludes: None
6
+ MissingIncludes: None
@@ -0,0 +1,18 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 2
10
+
11
+ [*.{c,h}]
12
+ indent_size = 4
13
+
14
+ [*.{py,md,yml,yaml,json}]
15
+ indent_size = 4
16
+
17
+ [*.md]
18
+ trim_trailing_whitespace = false
@@ -0,0 +1,3 @@
1
+ * text=auto
2
+ *.xll binary
3
+ *.xls binary
@@ -0,0 +1,58 @@
1
+ # Upstream ISDA CDS Standard Model -- NEVER COMMITTED.
2
+ # It is distributed only from cdsmodel.com after accepting the ISDA CDS
3
+ # Standard Model Public License and supplying an email address. Shipping it
4
+ # here would route around that gate. Each developer fetches their own copy.
5
+ # See README.md "Obtaining the reference implementation".
6
+ isda_cds_model_c_v*/
7
+ isda_cds_model_c_v*.zip
8
+ .git.pre-purge/
9
+
10
+ # build output
11
+ build/
12
+ cmake-build*/
13
+
14
+ # generated / machine-specific
15
+ compile_commands.json
16
+ CMakeUserPresets.json
17
+ .cache/
18
+
19
+ # loose compiled artifacts
20
+ *.o
21
+ *.a
22
+ *.so
23
+ *.dylib
24
+ *.dSYM/
25
+ *.profraw
26
+ *.profdata
27
+
28
+ # python
29
+ .venv/
30
+ __pycache__/
31
+ *.egg-info/
32
+ *.whl
33
+ dist/
34
+
35
+ # editors / agents
36
+ .claude/
37
+ .vscode/
38
+ .vs/
39
+ .idea/
40
+ .DS_Store
41
+
42
+ # personal context
43
+ CLAUDE.local.md
44
+
45
+ # GOTCHA: .gitignore has NO inline comments. `*.key # secrets` matches nothing --
46
+ # it becomes the literal pattern "*.key # secrets". Comments go on their OWN line.
47
+ *.key
48
+ *.pem
49
+ *.p12
50
+ .env
51
+ .env.*
52
+ credentials
53
+ *.secret
54
+
55
+ # Microsoft Excel XLL SDK -- obtained from Microsoft, never redistributed here.
56
+ # Same reasoning as the ISDA oracle: it is theirs, and committing it routes
57
+ # around their licence. Pointed at by CDSMODEL_XLSDK_DIR.
58
+ xlsdk/
@@ -0,0 +1,328 @@
1
+ # cdsmodel — the law for this repo
2
+
3
+ Guardrails, not suggestions. When a change conflicts with this file, this file
4
+ wins. Narrow by design: everything here is enforceable, and every line is
5
+ checked by a gate named beside it. Rationale lives in `specs/` and
6
+ `docs/port-notes.md`; how I work generally lives outside this repo.
7
+
8
+ ## The oracle — two inviolable rules
9
+
10
+ `isda_cds_model_c_v1.8.3/` is a local copy of the upstream ISDA CDS Standard
11
+ Model. It is the project's only independent check on 163 ported functions.
12
+
13
+ 1. **It is never edited.** Compiler problems are solved with CMake flags, never
14
+ by touching a source file. Editing it destroys the only independent check
15
+ the project has.
16
+ → enforced by `python verify.py upstream-unmodified` (132 files byte-compared
17
+ against a recorded manifest).
18
+
19
+ 2. **It is never committed.** Upstream is gated behind accepting the ISDA
20
+ licence and giving an email address on cdsmodel.com; redistributing it here
21
+ routes around that. It is gitignored and stays that way.
22
+ → enforced by `python verify.py upstream-absent`.
23
+
24
+ Computed output under `tests/golden/` **is** committable — licence section 4(b)
25
+ exempts derived data. Each generator says so in its header.
26
+
27
+ ## The verification contract
28
+
29
+ CI has no oracle, because of rule 2. A module tested only against upstream is
30
+ therefore verified **on one laptop and nowhere else.** So every module needs
31
+ both:
32
+
33
+ - a **tier-2** differential test that compiles upstream into the same binary and
34
+ sweeps the input domain against it (local only); and
35
+ - that sweep **recorded into tier-1 vectors** under `tests/golden/`, replayed
36
+ without the oracle.
37
+
38
+ → enforced by `python verify.py golden` (every vector set paired with its
39
+ generator) and `python verify.py tests` (a floor on the count collected with no
40
+ oracle present — raise it when a module lands, never lower it to go green).
41
+
42
+ The build must be green **both** ways before a commit:
43
+ `ctest --preset debug` and the same with `-DCDSMODEL_UPSTREAM_DIR=/nonexistent`.
44
+
45
+ ## Divergence from upstream
46
+
47
+ The port reproduces upstream's behaviour, including its defects. Correcting is
48
+ the exception and needs a reason: reproduce when the implementation is
49
+ self-consistent and only its documentation disagrees; correcting is available
50
+ only when the code contradicts *itself*, so there is no single behaviour to
51
+ preserve.
52
+
53
+ Any deliberate difference gets all three of: a comment at the site, a row in
54
+ the "Deliberate differences" table in `docs/port-notes.md`, and a test
55
+ asserting it from **both** sides — so an upstream release that changes the
56
+ behaviour fails a test instead of drifting silently.
57
+
58
+ A known divergence is never frozen into a recorded vector set. Golden files are
59
+ what the port is checked against; putting a divergence there converts a
60
+ documented difference into a silent one.
61
+
62
+ → enforced by `python verify.py reports` (every catalogued defect present on all
63
+ three surfaces) and `python verify.py claims` (no upstream function claimed by
64
+ two headers).
65
+
66
+ ## The error channel
67
+
68
+ A function reports failure by returning `cdsmodel::Expected<T>` carrying a
69
+ kind and a message that names the offending value. **No namespace-scope
70
+ function in `include/cdsmodel/` returns `std::optional`.**
71
+
72
+ `std::optional` remains correct where `nullopt` means *legitimately absent* --
73
+ an optional parameter, a struct field with no value yet, a lookup miss. The
74
+ test is semantic: **absent is `optional`, failed is `Expected`.** Exemptions
75
+ are named individually in the gate, never granted by pattern.
76
+
77
+ Propagation is not a kind. A caller forwarding a callee's failure passes the
78
+ original kind and message through unchanged; inventing a wrapper at each layer
79
+ buries the one reason the caller needs.
80
+
81
+ `Expected<T>` is a C++20 stand-in whose API is a **strict subset** of
82
+ `std::expected`'s, and it may not grow a member `std::expected` lacks -- that
83
+ subset is what lets it become a type alias and a deletion if this project ever
84
+ moves to C++23 for its own reasons.
85
+
86
+ → enforced by `python verify.py error-channel` (return types, named
87
+ exemptions, and a floor on DISTINCT error messages -- a non-empty check alone
88
+ would pass 341 copies of "invalid input").
89
+
90
+ Rationale and the measurements behind the four kinds: `specs/01_error_channel.md`.
91
+
92
+ ## The Excel add-in
93
+
94
+ `cdsmodel.xll` is built **only on Windows, only with the Excel XLL SDK
95
+ present.** A session on any other machine builds and tests everything except
96
+ the add-in itself, and that is by design, not a limitation to work around.
97
+
98
+ ### Four layers, and what may depend on what
99
+
100
+ cdsmodel the domain library all platforms
101
+ xl/core XlValue, dispatch, readers all platforms
102
+ xl/sdk XLOPER12 <-> XlValue Windows + SDK
103
+ xl/interface cdsmodel.xll Windows + SDK
104
+ python the nanobind extension all platforms
105
+
106
+ `python/` is a **peer of `xl/core`, not a layer above it**: both bind the same
107
+ `cdsmodel` functions, and neither may depend on the other. It mirrors
108
+ `xl/core`'s four argument blocks by hand rather than including them, because
109
+ those types carry `XlValue` and the handle registries.
110
+ → enforced by `python verify.py python-layer`.
111
+
112
+ Dependencies run **downward only**: `cdsmodel` knows nothing about Excel, and
113
+ `xl/core` knows nothing about `XLOPER12`. **Logic does not belong in `xl/sdk`
114
+ or `xl/interface`** -- those two are the only code CI cannot reach, so anything
115
+ decided there is verified on one machine by hand. If a marshalling rule is
116
+ worth a test, it goes in `xl/core`.
117
+
118
+ → enforced by `python verify.py coverage`, whose `xl/core` floor is high
119
+ precisely because that is where the testable logic must live.
120
+
121
+ ### Getting the SDK
122
+
123
+ The SDK is Microsoft's -- `xlcall.h` carries *"Copyright (c) 1997 - 2010
124
+ Microsoft Corporation"* -- and its licence (the Excel 2013 XLL SDK terms)
125
+ **forbids redistributing any of its files** (clause 2.b). So it is gitignored
126
+ and never committed; this repo is public. Each machine supplies its own copy,
127
+ and `python verify.py sdk-absent` enforces that nothing leaks in. Same rule, and
128
+ same reason, as the ISDA oracle.
129
+
130
+ Two further licence points shape how we use it:
131
+
132
+ - `xlcall.h` and `src/xlcall.cpp` **may not be modified** (clause 2.a.i) -- they
133
+ are staged **byte-for-byte**.
134
+ - The **sample** framework (`framewrk.*`, `MemoryManager.*`, `MemoryPool.*`)
135
+ **may** be modified (clause 2.a.ii), but its *executable code* is left exactly
136
+ as Microsoft ships it. The only touch to `framework.c` is its `#include`
137
+ lines: un-inline `xlcall.cpp` (the pristine sample `#include`s it, which would
138
+ double-define every callback) and repoint the framework / memory-manager
139
+ includes at the names we stage them under. The 8-bit `Excel4` helpers, which a
140
+ 64-bit link cannot resolve, are **not** compiled out -- they are left intact
141
+ and `xl/sdk/src/excel4_stub.cpp` (ours) defines the two symbols they reference,
142
+ so the workaround sits on our side of the seam, not in Microsoft's file.
143
+
144
+ **Eight files** are compiled, not four -- `framework.c` pulls in the memory
145
+ manager:
146
+
147
+ xlcall.h xlcall.cpp framework.h framework.c
148
+ MemoryManager.h MemoryManager.cpp MemoryPool.h MemoryPool.cpp
149
+
150
+ The easiest way to stage them from your own download:
151
+
152
+ python tools/setup_xlsdk.py /path/to/extracted/Excel2013XLLSDK
153
+
154
+ It copies `xlcall.*` and the memory manager pristine, repoints `framework.c`'s
155
+ `#include` lines (its code untouched), and writes all eight into `xlsdk/`
156
+ (gitignored). Then `cmake --preset release` configures and builds the add-in.
157
+
158
+ You can also populate `xlsdk/` (or `CDSMODEL_XLSDK_DIR`) by hand; CMake searches
159
+ recursively for `xlcall.h/.cpp` and `framework.h/.c` by name, and if it finds a
160
+ `framework.c` that still `#include`s `xlcall.cpp` inline it compiles `xlcall.cpp`
161
+ once rather than twice. Configure prints what it found:
162
+
163
+ -- cdsmodel: Excel XLL SDK found
164
+ -- cdsmodel: building cdsmodel.xll
165
+
166
+ ### What this repo builds, and where
167
+
168
+ Four targets, in dependency order. Nothing below depends on anything above it.
169
+
170
+ include/cdsmodel/ cdsmodel all platforms
171
+ src/ the ported library, 163 functions
172
+
173
+ xl/core/ cdsmodel_xl_core all platforms
174
+ include/cdsmodel/xl/ XlValue, the registration
175
+ src/ table, dispatch, readers,
176
+ tests/ the handle registries
177
+
178
+ xl/sdk/ cdsmodel_xl_sdk Windows + SDK
179
+ include/cdsmodel/xl/oper.hpp XLOPER12 <-> XlValue, and
180
+ src/oper.cpp the SDK's own files compiled
181
+ src/excel4_stub.cpp in; the stub (ours) defines
182
+ Excel4/Excel4v so the pristine
183
+ sample links unedited
184
+
185
+ xl/interface/ cdsmodel_xll Windows + SDK
186
+ src/exports.cpp the five entry points plus
187
+ one wrapper per function;
188
+ SUFFIX ".xll"
189
+
190
+ Supporting directories:
191
+
192
+ xlsdk/ the Excel SDK -- GITIGNORED, see above
193
+ tools/winshim/ a ten-typedef <windows.h> stand-in, for
194
+ tools/typecheck_xl.sh only. Not a compatibility
195
+ layer and nothing links it
196
+ tests/xll/smoke.xlsx the C8 workbook, self-contained
197
+ specs/reasoning/C8.md where the Excel result gets recorded
198
+
199
+ ### READ THIS BEFORE THE FIRST BUILD ON WINDOWS
200
+
201
+ `xl/sdk` and `xl/interface` are the only code CI cannot compile -- they sit
202
+ behind a platform guard, so on macOS and Linux they vanish. **Typecheck them
203
+ before trusting them:**
204
+
205
+ ./tools/typecheck_xl.sh
206
+
207
+ That compiles both against the REAL `xlcall.h` using a ten-typedef shim in
208
+ `tools/winshim` standing in for `<windows.h>`. It needs the SDK in `xlsdk/`
209
+ and nothing else. Run it after touching either file.
210
+
211
+ On Windows, `tools/typecheck_xl.ps1` is the native counterpart: it syntax-checks
212
+ the same two files with `clang++` against the **real** `<windows.h>`, so no shim
213
+ is involved and it catches strictly more. The full `cmake --preset release`
214
+ build is still authoritative; the script is the quick inner-loop gate.
215
+
216
+ It found four bugs the first time it ran, each of which would have failed a
217
+ Windows build: a missing `<windows.h>` include before `xlcall.h`;
218
+ `static_cast` where `GetTempMemory`'s `LPSTR` return needs `reinterpret_cast`;
219
+ a `CallContext` built with one registry when it needs two; and **thirteen of
220
+ sixteen registered functions with no exported wrapper at all.**
221
+
222
+ **What it still cannot catch**, and what the first real build is therefore for:
223
+
224
+ 1. The `XLOPER12` ABI's actual layout and the calling conventions. The shim
225
+ defines `pascal`, `_cdecl` and `CALLBACK` as nothing, so a convention
226
+ mismatch is invisible to it.
227
+ 2. Whether Excel accepts what `to_oper` builds -- especially the
228
+ `xltypeMulti` grid path used by `ParSpreads`, `DatesAndRates`,
229
+ `FeeLegFlows`, `DefaultAccrual` and `CDS.CalendarDates`.
230
+ 3. `xlAutoFree12` does nothing, because this add-in returns only temp memory.
231
+ If Excel crashes on a returned array, that assumption is where to look.
232
+
233
+ **Fix in `xl/sdk`, not in `xl/core`.** If a fix seems to need a change above
234
+ that line, say so rather than making it: the seam is what keeps the logic
235
+ testable, and CI cannot see anything on the Windows side of it.
236
+
237
+ ### Producing and recording the add-in's output
238
+
239
+ An XLL only truly runs inside Excel, interactively, which is not an oracle. So
240
+ the result is recorded rather than asserted, and the workbook reports its own
241
+ verdict:
242
+
243
+ cmake --preset release
244
+ cmake --build --preset release --target cdsmodel_xll
245
+ python tools/gen_xll_workbook.py # writes tests/xll/smoke.xlsx
246
+
247
+ Or drive it: `pwsh tools/run_c8.ps1` registers the add-in in 64-bit Excel over
248
+ COM, sweeps every function name for `#NAME?`, recalculates the workbook and
249
+ prints the Verdict and Forms columns, exiting non-zero if anything fails to
250
+ register or any row is not PASS. That is the same Excel calculation engine and
251
+ the same add-in; scripting it only makes the evidence reproducible.
252
+
253
+ By hand works too: load `cdsmodel.xll` in 64-bit Excel, open the workbook, let
254
+ it recalculate. Every row carries the value the C++ library computed and a
255
+ verdict column comparing it to what Excel got.
256
+
257
+ **Record the result in `specs/reasoning/C8.md`** with the date, the Excel
258
+ version, and the verdict column's contents. That file is the only evidence
259
+ tier 1 has for the add-in, so an empty or stale one means the add-in is
260
+ unverified -- say so plainly rather than implying otherwise.
261
+
262
+ ### Recording a run
263
+
264
+ `specs/reasoning/C8.md` is the only evidence tier 1 has for the add-in, so
265
+ **every run is appended, not overwritten.** Two are recorded: 2026-11-11 and
266
+ 2026-11-14. One run is evidence; a series is a habit, and the file is where
267
+ the difference shows.
268
+
269
+ A session starting on Windows has no memory of the last one, so anything it
270
+ discovers belongs in this file or in a spec rather than in a transcript. The
271
+ rule that matters most on a cold start: **do not mark a criterion passing
272
+ without the oracle result pasted into the spec's Progress table.** "It built"
273
+ is not a result.
274
+
275
+ ### What the add-in exposes
276
+
277
+ `CdsPrice` is registered **twice**: in its original sixteen-argument form, so
278
+ existing workbooks keep working, and as `CDS.Price`, taking five labelled
279
+ two-column ranges. Both read into the same four structs and then run one code
280
+ path, so they cannot disagree -- and a test compares them bitwise.
281
+
282
+ **Every wide upstream function now has a grouped form too.** The seven that were
283
+ once flat-only -- `UpfrontFlat` and `ParSpreadFlat` at seventeen arguments,
284
+ `CleanSpreadCurveBuild` at sixteen, `ParSpreads` at thirteen, `IRZeroCurveBuild`
285
+ at twelve, `DefaultAccrual` at eleven, `FeeLegFlows` at nine -- each gained a
286
+ `CDS.`-prefixed twin taking labelled ranges, reading through the same
287
+ `read_block` the four reader structs expose. The flat forms stay registered so
288
+ existing workbooks keep working.
289
+
290
+ **Twenty-four functions are registered**, covering all twelve upstream exposed:
291
+
292
+ pricing CdsPrice (16 args) CDS.Price (5 args, grouped)
293
+ ParSpreads CDS.ParSpreads
294
+ UpfrontFlat CDS.Upfront
295
+ ParSpreadFlat CDS.ParSpreadFlat
296
+ cash flows DefaultAccrual CDS.DefaultAccrual
297
+ FeeLegFlows CDS.FeeLegFlows
298
+ curves IRZeroCurveMake IRZeroCurveBuild CDS.IRZeroCurve
299
+ CleanSpreadCurveBuild CDS.SpreadCurve
300
+ DiscountFactor DatesAndRates
301
+ calendars LoadHolidays CDS.Calendar CDS.CalendarFromFile
302
+ CDS.CalendarDates
303
+ other CdsModelVersion
304
+
305
+ Eight of those return a **grid** rather than a number -- `ParSpreads`,
306
+ `DatesAndRates`, `FeeLegFlows`, `DefaultAccrual`, `CDS.CalendarDates` and the
307
+ grouped twins `CDS.ParSpreads`, `CDS.FeeLegFlows`, `CDS.DefaultAccrual` -- the
308
+ newest and least-tested part of the Windows side.
309
+
310
+ **A failed call returns the library's own message as text in the cell.** Not
311
+ `#VALUE!`, and not a log entry a user has to go and read -- upstream needed six
312
+ of its eighteen functions to manage that log, and all six are gone.
313
+
314
+ Adding a function means adding a row to the table in `xl/core/src/functions.cpp`
315
+ and a three-line wrapper in `xl/interface/src/exports.cpp`. Registration walks
316
+ the table, so the name, type codes, parameter names, help and category cannot
317
+ drift apart.
318
+
319
+ → enforced by `python verify.py coverage` and the `Registration` tests, which
320
+ assert the arity the type codes declare equals the documented parameter count.
321
+
322
+ ## Formatting
323
+
324
+ `clang-format` covers our own C++ only: `include/`, `src/`, `tests/`, `tools/`
325
+ and `python/src/`. Upstream C is never reformatted — it is not ours, and a
326
+ reformatted oracle is a modified oracle. The Excel SDK is excluded for the same
327
+ reason, and `xl/` is excluded because it was not in scope when the gate was
328
+ written.