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.
- cdsmodel-0.1.0/.clang-format +3 -0
- cdsmodel-0.1.0/.clangd +6 -0
- cdsmodel-0.1.0/.editorconfig +18 -0
- cdsmodel-0.1.0/.gitattributes +3 -0
- cdsmodel-0.1.0/.gitignore +58 -0
- cdsmodel-0.1.0/CLAUDE.md +328 -0
- cdsmodel-0.1.0/CMakeLists.txt +529 -0
- cdsmodel-0.1.0/CMakePresets.json +104 -0
- cdsmodel-0.1.0/LICENSE +32 -0
- cdsmodel-0.1.0/NOTICE.md +49 -0
- cdsmodel-0.1.0/PKG-INFO +256 -0
- cdsmodel-0.1.0/README.md +238 -0
- cdsmodel-0.1.0/cmake/cdsmodelConfig.cmake.in +12 -0
- cdsmodel-0.1.0/include/cdsmodel/bad_day.hpp +167 -0
- cdsmodel-0.1.0/include/cdsmodel/bad_day_map.hpp +191 -0
- cdsmodel-0.1.0/include/cdsmodel/bootstrap.hpp +239 -0
- cdsmodel-0.1.0/include/cdsmodel/bsearch.hpp +128 -0
- cdsmodel-0.1.0/include/cdsmodel/business_days.hpp +300 -0
- cdsmodel-0.1.0/include/cdsmodel/calendar.hpp +203 -0
- cdsmodel-0.1.0/include/cdsmodel/cash_flow_bootstrap.hpp +394 -0
- cdsmodel-0.1.0/include/cdsmodel/cash_flow_list.hpp +191 -0
- cdsmodel-0.1.0/include/cdsmodel/cash_flow_schedule.hpp +416 -0
- cdsmodel-0.1.0/include/cdsmodel/cds.hpp +340 -0
- cdsmodel-0.1.0/include/cdsmodel/cdsmodel.hpp +66 -0
- cdsmodel-0.1.0/include/cdsmodel/cdsone.hpp +160 -0
- cdsmodel-0.1.0/include/cdsmodel/contingent_leg.hpp +252 -0
- cdsmodel-0.1.0/include/cdsmodel/coupon_schedule.hpp +506 -0
- cdsmodel-0.1.0/include/cdsmodel/curve_discount.hpp +114 -0
- cdsmodel-0.1.0/include/cdsmodel/curve_instruments.hpp +378 -0
- cdsmodel-0.1.0/include/cdsmodel/curve_linear_interp.hpp +154 -0
- cdsmodel-0.1.0/include/cdsmodel/curve_rates.hpp +178 -0
- cdsmodel-0.1.0/include/cdsmodel/date.hpp +464 -0
- cdsmodel-0.1.0/include/cdsmodel/date_adjust.hpp +147 -0
- cdsmodel-0.1.0/include/cdsmodel/date_interval.hpp +284 -0
- cdsmodel-0.1.0/include/cdsmodel/date_list.hpp +232 -0
- cdsmodel-0.1.0/include/cdsmodel/date_schedule.hpp +327 -0
- cdsmodel-0.1.0/include/cdsmodel/date_sup.hpp +237 -0
- cdsmodel-0.1.0/include/cdsmodel/day_count.hpp +206 -0
- cdsmodel-0.1.0/include/cdsmodel/day_count_string.hpp +173 -0
- cdsmodel-0.1.0/include/cdsmodel/defaulted.hpp +150 -0
- cdsmodel-0.1.0/include/cdsmodel/expected.hpp +235 -0
- cdsmodel-0.1.0/include/cdsmodel/fee_leg.hpp +410 -0
- cdsmodel-0.1.0/include/cdsmodel/float_rate.hpp +159 -0
- cdsmodel-0.1.0/include/cdsmodel/holiday_file.hpp +55 -0
- cdsmodel-0.1.0/include/cdsmodel/interp_curve.hpp +285 -0
- cdsmodel-0.1.0/include/cdsmodel/interpolation.hpp +334 -0
- cdsmodel-0.1.0/include/cdsmodel/ir_zero_curve.hpp +188 -0
- cdsmodel-0.1.0/include/cdsmodel/match_range.hpp +231 -0
- cdsmodel-0.1.0/include/cdsmodel/rate_conversion.hpp +313 -0
- cdsmodel-0.1.0/include/cdsmodel/root_find.hpp +430 -0
- cdsmodel-0.1.0/include/cdsmodel/schedule.hpp +112 -0
- cdsmodel-0.1.0/include/cdsmodel/stream_cash_flows.hpp +458 -0
- cdsmodel-0.1.0/include/cdsmodel/stub.hpp +347 -0
- cdsmodel-0.1.0/include/cdsmodel/swap_bootstrap.hpp +508 -0
- cdsmodel-0.1.0/include/cdsmodel/swap_bootstrap_flows.hpp +187 -0
- cdsmodel-0.1.0/include/cdsmodel/swap_dates.hpp +297 -0
- cdsmodel-0.1.0/include/cdsmodel/timeline.hpp +102 -0
- cdsmodel-0.1.0/include/cdsmodel/version.hpp +17 -0
- cdsmodel-0.1.0/include/cdsmodel/zero_curve.hpp +404 -0
- cdsmodel-0.1.0/include/cdsmodel/zero_curve_builder.hpp +814 -0
- cdsmodel-0.1.0/pyproject.toml +104 -0
- cdsmodel-0.1.0/python/CMakeLists.txt +36 -0
- cdsmodel-0.1.0/python/cdsmodel/__init__.py +115 -0
- cdsmodel-0.1.0/python/cdsmodel/_core.pyi +560 -0
- cdsmodel-0.1.0/python/cdsmodel/py.typed +0 -0
- cdsmodel-0.1.0/python/src/blocks.hpp +111 -0
- cdsmodel-0.1.0/python/src/calendars.cpp +79 -0
- cdsmodel-0.1.0/python/src/credit_curve.cpp +117 -0
- cdsmodel-0.1.0/python/src/curves.cpp +105 -0
- cdsmodel-0.1.0/python/src/date_caster.hpp +39 -0
- cdsmodel-0.1.0/python/src/errors.cpp +41 -0
- cdsmodel-0.1.0/python/src/errors.hpp +65 -0
- cdsmodel-0.1.0/python/src/instruments.cpp +111 -0
- cdsmodel-0.1.0/python/src/module.cpp +45 -0
- cdsmodel-0.1.0/python/src/pricing.cpp +105 -0
- cdsmodel-0.1.0/python/src/types.cpp +190 -0
- cdsmodel-0.1.0/requirements-dev.txt +4 -0
- cdsmodel-0.1.0/src/holiday_file.cpp +157 -0
- cdsmodel-0.1.0/src/version.cpp +15 -0
- cdsmodel-0.1.0/verify.py +946 -0
cdsmodel-0.1.0/.clangd
ADDED
|
@@ -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,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/
|
cdsmodel-0.1.0/CLAUDE.md
ADDED
|
@@ -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.
|