Development Guide
This guide explains how to build, test, document, and extend DuckDB Finance as a standard out-of-tree DuckDB extension.
Repository Shape
| Path | Purpose |
|---|---|
src/scalar.cpp and src/scalar/*.inc |
Native scalar functions for math, rates, options, cash flows, portfolios, validation, calendars, and compatibility structs. |
src/aggregate.cpp and src/aggregate/*.inc |
Native aggregate state for metrics such as Sortino, EWMA volatility, drawdowns, outliers, IV rank, and IV percentile. |
src/macros.cpp and src/macros/*.inc |
SQL macro registrations and compatibility aliases. |
src/table_functions.cpp and src/table_functions/*.inc |
Table functions and bind-replace SQL generators. |
include/finance/finance_extension.hpp |
Extension registration declarations. |
test/sql/gold_dataset.sql |
Small deterministic fixture tables. |
test/sql/gold_tests.sql |
Assertion-based behavior and edge-case tests. |
test/sql/smoke_queries.sql |
Broad callable-surface smoke coverage. |
docs/function_reference.md |
Public usage reference for registered fin_* functions. |
Build Requirements
- DuckDB source checkout.
- CMake and a C++ toolchain supported by DuckDB.
- Python 3 for documentation coverage checks.
make.
Build:
make debug DUCKDB_ROOT=/path/to/duckdb
Test Commands
make smoke
make gold
make test
make check
make check runs:
scripts/check_function_docs.pyto confirm registered functions are covered indocs/function_reference.md.scripts/check_docs_site.pyto confirm the GitHub Pages navigation and publishing workflow are wired.scripts/check_function_tests.pyto confirm registered functions are covered by the gold behavior tests.scripts/check_function_perf_tests.pyto confirm the profiled gold corpus covers registered functions.make smoketo load the extension and run broad smoke queries.make goldto run deterministic fixtures and assertions.
The test targets start DuckDB with unsigned local extensions enabled:
make test DUCKDB_ROOT=/path/to/duckdb
CI Scope
CI always runs the static coverage gates:
make ci-static
Pull requests that touch source, tests, examples, build files, workflow files, or other runtime-sensitive paths also run the DuckDB-backed gate:
make ci-duckdb DUCKDB_ROOT=/path/to/duckdb
Protected-branch, merge-queue, and manual CI runs execute the full path. This keeps documentation-only checks fast without weakening behavior checks for extension changes.
Adding A Function
- Choose the smallest native or SQL-macro implementation that fits the behavior.
- Register the function under
fin_*. - Add behavior tests in
test/sql/gold_tests.sql. - Add or update deterministic fixture rows in
test/sql/gold_dataset.sqlonly when a reusable fixture makes the test clearer. - Document the function in
docs/function_reference.md. - Run
make check.
Prefer native C++ for numerically sensitive models, custom list/struct output, table-function binding, and hot row-wise execution. Prefer SQL macros when DuckDB already exposes the right aggregate or window primitive.
Numerical And Finance Conventions
- Rates and returns are decimal values.
- Volatility is annualized decimal volatility unless stated otherwise.
- Option
ttmis a year fraction. - Currency fields are labels unless a function explicitly performs FX pricing.
- Portfolio aggregation assumes caller-normalized units.
- Invalid dimensions should return
NULLor throw consistently with nearby functions; do not silently fabricate successful results.
Documentation Expectations
The public docs should make model assumptions explicit. Every new function should describe:
- Purpose.
- SQL usage.
- Return type or shape.
- Units and important assumptions.
- NULL, invalid input, or approximation behavior when relevant.
The function reference is intentionally concise; longer workflows belong in
docs/playbooks.md or examples/playbooks.sql.