Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,3 @@ applyTo: '/**'

* Strategy runtime markdown descriptions (read by `load_description()` at runtime) live inside the package at `quantflow/options/strategies/docs/` — they must be inside the package to be accessible when the library is installed
* mkdocs documentation pages live in `docs/api/options/` — do not mix these two locations

## Releasing

The release procedure is fully driven by `make release` and the `release.yml` workflow:

1. Bump `version` in `pyproject.toml` to the new release version.
2. Add a `## vX.Y.Z` section to `docs/release-notes.md` with the notes for the release. The header text is matched verbatim by the workflow's `awk` extractor, so it must be `## vX.Y.Z` exactly (no trailing dash, no title after the version).
3. Commit and merge to `main`.
4. From `main`, run `make release` — it reads the version from `pyproject.toml`, prompts for confirmation, then creates an annotated `vX.Y.Z` tag and pushes it.
5. The tag push triggers `.github/workflows/release.yml`, which runs lint and tests, publishes the package to PyPI (`make publish`), and posts the extracted `## vX.Y.Z` section as the GitHub Release body.

Do not publish to PyPI manually or via the old `head_commit.message == 'release'` flow — the tag-triggered workflow is the only supported path.

### Release-notes conventions

The `## vX.Y.Z` section in `docs/release-notes.md` must follow these conventions, since the same content is rendered both on the docs site and as the GitHub Release body:

* Open with a one-paragraph summary describing the theme of the release. If the release contains breaking changes, point readers to the **Breaking changes** section in that paragraph.
* Group entries under H3 subsections in this order: `### Breaking changes`, `### New features`, `### Improvements and fixes`, `### Documentation and assets`. Omit any subsection that has no entries.
* Every PR reference must be a markdown link of the form `[#NN](https://github.com/quantmind/quantflow/pull/NN)`. Never write a bare `(#NN)` — both readers (docs and GitHub) benefit from the explicit URL, and GitHub's auto-linking only works in some contexts. When a single entry references multiple PRs, list them comma-separated inside one set of parentheses, each as its own markdown link.
* Build the PR list by running `git log vPREV..HEAD --oneline` against the previous release tag and following each squashed-merge commit back to its PR. Cross-check with `gh pr list --state merged --base main` for any PRs merged since the previous tag.
* End the section with a `[Full changelog](https://github.com/quantmind/quantflow/compare/vPREV...vX.Y.Z)` link comparing the new tag against the previous one.
48 changes: 48 additions & 0 deletions .github/instructions/release.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Release Instructions

Releases are driven by `v*` git tags. Pushing a tag triggers
`.github/workflows/release.yml`, which runs lint and the test suite, publishes
the package to PyPI (`make publish`), then extracts the matching `## vX.Y.Z`
section from `docs/release-notes.md` and publishes it as the GitHub Release
body.

## Cutting a release

1. Bump `version` in `pyproject.toml` to the new release version.
2. Add a `## vX.Y.Z` section at the top of `docs/release-notes.md` with the
notes for the release. The header text is matched verbatim by the
workflow's `awk` extractor, so it must be `## vX.Y.Z` exactly (no trailing
dash, no title after the version). The release workflow fails if this
section is missing.
3. Commit and merge to `main`; let the `build` workflow pass.
4. From `main`, run `make release` — it reads the version from
`pyproject.toml`, asks for confirmation, then creates an annotated `vX.Y.Z`
tag and pushes it. The `release` workflow takes it from there.

Do not publish to PyPI manually, and do not revive the old
`head_commit.message == 'release'` flow — the tag-triggered workflow is the
only supported path.

## Release-notes conventions

The `## vX.Y.Z` section in `docs/release-notes.md` is rendered both on the
docs site and as the GitHub Release body, so it must follow these conventions:

- Open with a one-paragraph summary describing the theme of the release. If
the release contains breaking changes, point readers to the **Breaking
changes** section in that paragraph.
- Group entries under H3 subsections in this order: `### Breaking changes`,
`### New features`, `### Improvements and fixes`,
`### Documentation and assets`. Omit any subsection that has no entries.
- Every PR reference must be a markdown link of the form
`[#NN](https://github.com/quantmind/quantflow/pull/NN)` — never a bare
`(#NN)`. GitHub's auto-linking only works in some contexts, and the explicit
URL works everywhere. When one entry references multiple PRs, list them
comma-separated inside one set of parentheses, each as its own link.
- Build the PR list by running `git log vPREV..HEAD --oneline` against the
previous release tag and following each squashed-merge commit back to its
PR. Cross-check with `gh pr list --state merged --base main` for any PRs
merged since the previous tag.
- End the section with a
`[Full changelog](https://github.com/quantmind/quantflow/compare/vPREV...vX.Y.Z)`
link comparing the new tag against the previous one.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@readme.md
@.github/copilot-instructions.md
@.github/instructions/makefile.instructions.md
@.github/instructions/release.instructions.md
@.github/instructions/tutorial.instructions.md
88 changes: 88 additions & 0 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,94 @@ below maps to a tagged release on
pushed, the matching section is extracted by
`.github/workflows/release.yml` and published as the GitHub Release body.

## v0.9.0

Pricing-engine and calibration overhaul. `MaturityPricer` now evaluates call
prices and Greeks lazily at arbitrary log-strikes instead of carrying a
precomputed grid, Fourier pricers take a moneyness-based truncation parameter,
and the volatility-surface calibration can fit Black implied vols directly.
This release contains several API changes: see **Breaking changes** below.

### Breaking changes

**`MaturityPricer` reworked.** ([#59](https://github.com/quantmind/quantflow/pull/59))

- The precomputed `std`, `log_strike` and `call` arrays are gone. A
`MaturityPricer` now holds a single `pricing` field (an
`OptionPricingResult`) that evaluates call prices and Greeks on demand at
any log-strike.
- `moneyness` is now a method, `moneyness(log_strikes)`, not a cached array
property. The `time_value` and `intrinsic_value` array properties and the
`interp(...)` helper were removed; use `prices(log_strikes)` to get a
DataFrame of prices and implied vols on a chosen log-strike grid.

**Fourier pricing truncation: `max_log_strike` → moneyness parameters.**
([#59](https://github.com/quantmind/quantflow/pull/59))

- `Marginal1D.call_option`, `call_option_carr_madan` and `call_option_lewis`
take `max_moneyness` (a multiple of the marginal standard deviation)
instead of `max_log_strike`. The COS path takes
`cos_moneyness_std_precision` instead.
- `OptionPricingResult.call_at(...)` is renamed `call_price(...)`, the
`method` field is removed, and a new abstract `call_greeks(log_strike)`
returns a `Greeks` namedtuple `(price, delta, gamma)`.

**`OptionPricerBase.call_price` → `call_prices`.**
([#59](https://github.com/quantmind/quantflow/pull/59)) The method is now
vectorised: it takes arrays of times-to-maturity and log-strikes and prices
them in a single maturity-grouped call.

**`DIVFMPricer` no longer builds a fixed moneyness grid.**
([#59](https://github.com/quantmind/quantflow/pull/59)) The
`max_moneyness_ttm` and `n` fields are removed; the fitted IV surface is
evaluated on demand through `OptionPricingResultDIVFM`.

### New features

- **Implied-vol calibration residuals.** New `ResidualKind` enum and a
`residual_kind` field on `VolModelCalibration`: set it to `ResidualKind.IV`
to fit the model to Black implied vols (recovered by inverting the model
price) rather than to forward-space prices. The IV residual is naturally
well-scaled across moneyness, so `moneyness_weight` is not applied in that
mode. ([#59](https://github.com/quantmind/quantflow/pull/59))
- **Greeks from the pricing result.** `OptionPricingCosResult.call_greeks`
returns closed-form price, delta and gamma from the COS expansion; the
transform-based result derives delta and gamma by differentiating the call
grid; DIVFM uses finite differences on the fitted surface.
([#59](https://github.com/quantmind/quantflow/pull/59))
- **COS truncation control on `OptionPricer`.** New
`cos_moneyness_std_precision` field (default 12) sets the width of the COS
integration interval in standard deviations.
([#59](https://github.com/quantmind/quantflow/pull/59))

### Improvements and fixes

- Calibration residuals are now computed in a single vectorised pricing call.
Deep-wing strikes where the model price falls outside the no-arbitrage band
(so Newton fails to invert it) are masked out instead of poisoning the fit,
and a parameter set that fails to invert on more than half the options is
rejected with a large penalty.
([#59](https://github.com/quantmind/quantflow/pull/59))
- Calibration plots now evaluate the model on a fresh moneyness grid;
`plot(max_moneyness=...)` no longer accepts `None`.
([#59](https://github.com/quantmind/quantflow/pull/59))
- `OptionEntry.mid_price()` no longer caches through a private attribute.
([#59](https://github.com/quantmind/quantflow/pull/59))
- Stale Jupytext notebook mirrors under `notebooks/` removed.
([#59](https://github.com/quantmind/quantflow/pull/59))

### Documentation and assets

- New GitHub social-preview banner under `docs/assets/logos/png/`.
([#59](https://github.com/quantmind/quantflow/pull/59))
- `docs/api/options/black.md` and the volatility-surface calibration examples
updated for the new pricer API.
([#59](https://github.com/quantmind/quantflow/pull/59))
- The release procedure moved out of `.github/copilot-instructions.md` into
its own `.github/instructions/release.instructions.md`.

[Full changelog](https://github.com/quantmind/quantflow/compare/v0.8.0...v0.9.0)

## v0.8.0

Volatility-surface calibration overhaul. This release adds a two-factor BNS
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "quantflow"
version = "0.8.0"
version = "0.9.0"
description = "quantitative analysis"
authors = [ { name = "Luca Sbardella", email = "luca@quantmind.com" } ]
license = "BSD-3-Clause"
Expand Down
36 changes: 18 additions & 18 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading