← Research index
INDEPENDENT NUMERICAL AUDIT13 September 2026

FinancePy misprices three FX digital payout-currency paths

An FX digital can pay in either member of a currency pair. In FinancePy 1.0.1, three valuation paths do not consistently switch the probability and discount terms with the payout currency.

Xamit Kadirbekov
Xamit KadirbekovIndependent verification · GERO Research
Quantitative financeFinancePy 1.0.1FX options
STATUS · REPORTED UPSTREAM — CORRECTION SUBMITTEDReproduced from the published PyPI wheel. FinancePy PR #260 is open, clean and mergeable; both official workflows pass. It remains unmerged.

A one-minute explanation

Synthetic English narration using macOS Samantha. Original motion cards, no music or third-party imagery. Download the script, source ledger, renderer and QA record.

Three affected formula paths

  1. FXDigitalOption uses N(d2) for a foreign-currency payout. In domestic units the payoff is S_T × 1(condition), so this is asset-or-nothing and uses N(d1).
  2. FXDoubleDigitalOption discounts a domestic-currency interval payout with the foreign discount factor instead of the domestic factor.
  3. The same interval class uses d2 rather than d1 for a foreign-currency payout.

The two domestic single-digital controls agree with their independent cash-or-nothing formulas. The finding is therefore bounded to the named paths.

The payoff determines the formula

Let S_T be domestic currency per unit of foreign currency. Under the domestic pricing measure:

PV[1 domestic × 1(S_T > K)] = df_domestic × N(d2)
PV[1 foreign  × 1(S_T > K)] = S_0 × df_foreign × N(d1)

The second identity follows by converting the foreign unit at expiry. Its domestic payoff is S_T × 1(S_T > K). An interval digital is the difference of the matching lower- and upper-strike terms.

Synthetic released-wheel counterexample

The reproducible case uses EURUSD spot 1.20, one-year expiry, domestic rate 5%, foreign rate 1%, volatility 20%, a single strike of 1.25 and interval strikes 1.10–1.40.

path                    FinancePy 1.0.1    independent oracle
foreign single call          0.5449552491          0.6397169446
foreign single put           0.6430720022          0.5483103068
domestic interval            0.4474588468          0.4298665323
foreign interval             0.5369506162          0.5338519318

The oracle evaluates the payoff-derived Black–Scholes expressions with Python’s standard-library math.erf. It does not reuse FinancePy’s vector normal-CDF approximation.

Submitted correction and falsification

FinancePy pull request #260 calculates both strike-specific d1 and d2, then chooses the probability and discount factor that correspond to the payout currency.

  • 6 focused oracle tests pass after the correction.
  • The complete local unit suite reports 964 passes, with four pre-existing LSMC RankWarning messages.
  • Against the former source, all four affected tests fail while both unaffected domestic single-digital controls pass.
  • Both existing FX digital regression scripts complete.
  • Both official upstream workflows pass on commit 1a78f85d4576f20d1671338bad49640a9dbb7b87.

At publication time the pull request remains open and unmerged. Green checks validate the submitted change; they do not imply maintainer acceptance.

Evidence and limits

The public wheel has SHA-256 110e784122f485ae207239f44af473334f418d81bcbb958f5eda4e76956feca5. Its single- and double-digital source files hash to 415ec9bd1f3ffb65afd450f9589685b63401d800569d86b670edf2692ff7878c and 9a85bc68f56b0c55e7a5394efbb051e3ff1c00412667b485d1c952568db169db.

A bounded FinancePy GitHub search using four direct formulations found no matching issue or pull request. This is not a worldwide novelty or priority guarantee.

All market inputs are synthetic. The report establishes library-level formula discrepancies. It does not establish use by a financial institution, a customer position, a production deployment, security impact or financial loss.

The public reproducer and report are supplied under GPL-3.0-or-later. Source excerpts retain their upstream licensing.