Michal Kaszubski

Bugs I found in libraries that quants use, and the fixes their authors merged.

Each entry names the library, what was wrong, how I found it and what the fix does, and links to the pull request so the claim can be checked. Most were found by testing a library against itself: Greeks against finite differences, put-call and in-out parities, closed forms against Monte Carlo, one engine against another. Only merged pull requests are described as merged.

As of 28 September 2026. Commits are under my own name; the GitHub profile is github.com/Cashubski (opens in a new tab).

FinancePy (opens in a new tab) a derivatives-pricing library

six pull requests merged, September 2026

  1. Fixed the Bjerksund and Stensland American option pricer, which divided by zero at a zero dividend yield and fell below the European price near it; the fix returns the European value when early exercise is never optimal and floors the approximation at the European bound.

    When the cost of carry equals the riskless rate, the Bjerksund and Stensland exercise boundary is undefined: beta is exactly one and the trigger price divides by zero. The library raised. Just below that point the approximation also fell under the European price, which an American option cannot do. The fix returns the European value where early exercise is never optimal and floors the approximation at the European bound, since both are lower bounds on the American price. Found by checking every American pricer against a 2,000-step binomial tree and against the no-dividend identity.

  2. Made date-schedule generation repeatable: a second call stepped back from the adjusted maturity date and shifted every coupon date whenever the maturity fell on a weekend or holiday, which reached bonds, cross-currency swaps and cliquet options.

    The schedule generator produced the right coupon dates on its first call and different ones on every call after, because the first call replaced the maturity date with its weekend-adjusted version and later calls stepped backwards from that. Most products call the generator twice, so bonds with floating coupons, cross-currency swaps and cliquet options received shifted dates and a spurious one-day stub whenever the maturity fell on a weekend or holiday. One existing test had silently encoded the bug: its stored value included a one-day option that should not exist.

  3. Rewrote the forward-start option, which could not be constructed, and verified it against the Rubinstein closed form and the library’s cliquet option.

    The forward-start option class referenced calendar settings it never set, so it could not be constructed, and its valuation loop priced an extra option before the start date. Rewritten as the sequence of at-the-money forward-start options between reset dates, and tested against the Rubinstein 1991 closed form for one period and against the library’s own cliquet option for several.

  4. Corrected two FX option error paths that raised a Python type error instead of the library’s own error.

    Two error messages concatenated an enum to a string, so an invalid option type raised a Python TypeError from the message itself instead of the library’s FinError.

  5. Fixed four of the six Monte Carlo pricing methods, which returned NaN for every input because they passed the option type where the model expects the interest rate.

    Four of the six Monte Carlo pricing methods returned NaN for every input: they passed the option type in the position the model reserves for the interest rate. A test now prices the same call with all six variants and pins each to the closed form.

  6. Fixed the variance-swap fair strike, which was too high by twice the dividend yield and crashed on large strike grids, and verified it against the Demeterfi, Derman, Kamal and Zhou replication.

    Under a flat volatility the fair variance strike of a variance swap must equal the squared volatility, whatever the rate and dividend yield. It came out too high by twice the dividend yield, because the log-contract drift used the rate alone and the option portfolio was compounded at the wrong rate, and it crashed on large strike grids. Fixed against the Demeterfi, Derman, Kamal and Zhou replication and verified to within 0.2 percent across rate and yield combinations.

vectorbt (opens in a new tab) a backtesting library

two pull requests merged, September 2026

  1. Fixed the deflated Sharpe ratio, which used excess kurtosis where the Bailey and López de Prado formula requires raw kurtosis, and which counted missing returns as zero-return periods.

    The deflated Sharpe ratio of Bailey and López de Prado uses the raw kurtosis, which is 3 for Gaussian returns and recovers the classic Lo standard error. The implementation passed excess kurtosis, so the variance term was off by three quarters of the squared Sharpe ratio and could turn negative. It also zero-filled missing returns before computing skewness. Both fixed, with tests against the paper’s formula.

  2. Made the Numba and Rust engines agree on expanding windows shorter than the minimum period, matching pandas.

    Found with a harness that runs every function through both the Numba and Rust engines on clean, gappy, constant and short inputs. The one discrepancy: expanding windows shorter than the minimum period raised an error in Numba and returned NaN in Rust and pandas.

skfolio (opens in a new tab) a scikit-learn-compatible portfolio-optimisation library

three estimators under review, September 2026

  1. A parametric portfolio policy estimator after Brandt, Santa-Clara and Valkanov (2009): weights as a linear function of characteristics, fitted by maximising realised CRRA utility, with long-only and transaction-cost variants.

    Weights are the benchmark plus a linear tilt in cross-sectionally demeaned characteristics, and the few coefficients maximise the realised CRRA utility of the return path, with no expected-return or covariance estimate. The smooth case is concave and solved with a trust-region method using the analytic gradient and Hessian; long-only and transaction-cost variants use a quasi-Newton method. Reviewed in discussion, including a look-ahead bias the reviewer caught and I fixed.

  2. Online learning for the Schur complementary allocation, so it can be updated in a stream.

    Adds streaming updates to the Schur complementary allocation and to the covariance-based distance estimator, so both can be fed new observations without refitting on history. Chunked updates reproduce the batch fit exactly.

  3. A rolling-window multi-factor exposure estimator with gap-tolerant lags.

    Turns one panel field into a library of trailing statistics and lags as a single multi-factor exposure, with a policy for listing gaps: either invalidate the lookback or measure it in active observations.

The same work appears in brief on the CV.