Deterministic verification for financial AI (v3.0.1).
QWED Finance is a verification library for financial AI. A language model proposes a figure, a decision, a payment message or a query; QWED Finance recomputes or checks it with deterministic code before your system acts on it. It does not make the model more accurate. It decides whether a given output may be used.
It combines formal and high-precision tools: SymPy for cash-flow maths, Z3 for the AML rule, mpmath and Decimal for pricing and risk, XML parsing with required-element rules for ISO 20022, field checks on the framed text of SWIFT MT messages, and the SQLGlot parser for SQL safety.
New in v3.0.1: security fixes.
- ISO 20022 business rules read amounts and currencies from the parsed XML tree, not from raw text (GHSA-mrrj-6m2q-jch9)
- Sanctions screening folds diacritics and look-alike letters and compares separator-free names, so
E.V.I.L. CORP or ÉVIL CORP no longer clears an EVIL CORP entry (GHSA-mv2c-jwm9-pfrq)
QueryGuard rejects MySQL /*! ... */ and MariaDB /*M! ... */ executable comments (GHSA-q8r4-6gpp-5fx2)
v3.0.0 highlights: keyed HMAC receipt signatures (get_signature(key)), ISO amount and currency limits in receipts and UCP, a fail-closed batch for AML, sanctions, amounts and message validation, and a breaking change to the npm bridge (stdin JSON with runtime validation). See the changelog for details.
Why QWED Finance?
Language models get arithmetic and strict rules wrong, and in finance close enough is not good enough.
- Problem: a model says “IRR is 12%” when it is 11.8%.
- What QWED Finance does: it recomputes the IRR from the cash flows and rejects the claim when it differs by more than the tolerance. It reports the value it computed; it does not rewrite the model’s answer.
verify_irr solves NPV = 0 with SymPy and uses the first real root above -100%. Cash flows that change sign more than once can have several IRRs, and the first root is not always the one you mean: check those with verify_npv at each candidate rate. When SymPy finds no real root, the method falls back to a numeric solver and reports verification_mode="HEURISTIC" instead of "SYMBOLIC". A claim that is not a number, such as "not a rate", raises ValueError: treat that as a rejection.
Key features
- 11 guards: Compliance, Calendar, Derivatives, Message, ISO, Query, Cross, Bond, FX, Risk and Trading.
- GitHub Action: checks financial calculations in CI, with optional SARIF output for security dashboards.
- Receipts: verification receipts for cross-guard and integration flows. Receipts are unsigned by default: call
get_signature(key) and store the HMAC-SHA256 signature separately to get a tamper-evident record.
- Deterministic results: each check is computed by code, so the same input gives the same result.
The four parts of banking verification
Quick example
Architecture
Where QWED Finance sits
Your code chooses the guard for each output. QWED Finance returns a result; your system decides what to do with it.
Guards and their engines
Payment check with UCP
UCPIntegration.verify_payment_token() runs four checks: amount limits, currency, AML threshold and KYC status. When an AML flag is needed the status is PENDING_REVIEW, even if another check also failed; BLOCKED means a check failed with no AML flag. Sanctions screening is part of verify_iso20022_payment(), which takes a sanctions list.
Why not just trust the model?
Language models are probabilistic. They can:
- state a figure that is wrong
- miss a compliance threshold, such as the 10,000 currency transaction report limit
- produce a payment message that is missing required elements
- write SQL that changes or deletes data
QWED Finance checks each of these with deterministic code:
Rules and standards the checks are built around
The checks implement parts of these rules and standards. Using QWED Finance does not make a system compliant with them: that is for your own compliance review.
- BSA/FinCEN:
verify_aml_flag requires a flag at or above the 10,000 currency transaction report threshold, and for a high-risk country whatever the amount (amounts are compared as given; see the Compliance guard)
- OFAC and other sanctions lists: name screening against a list you supply
- ISO 20022 and SWIFT MT: message structure and business-rule checks
- RBI FREE-AI (India): receipts and audit logs as records of how an AI output was checked
FinanceVerifier rejects ambiguous or unknown inputs instead of silently falling back to a default. In finance, a wrong answer with no error signal is worse than a loud failure.
verify_compound_interest: accepted compounding frequencies
Since v2.1.0: verify_compound_interest() raises ValueError for unknown compounding frequencies. Earlier releases silently used annual compounding for unknown values (for example "weekly" or "continuous"), producing wrong results with no sign of failure.
Accepted values for the compounding argument:
If you need a frequency outside this list, compute the equivalent rate yourself and pass one of the supported values.
Next steps