Skip to main content
Each guard checks one kind of financial output with deterministic code: a model’s claim goes in, and the guard recomputes or checks it before your system uses it. Your code chooses which guard to call.

1. Compliance guard

Purpose: Check AML, KYC, transaction-limit and sanctions decisions against fixed rules. The AML check uses the Z3 solver; the other three are rule checks.

Methods

verify_aml_flag takes no currency: it compares amount with the threshold for jurisdiction ("USA", "EU" or "UK", each 10,000 in that jurisdiction’s currency). Pass the amount in that currency, converting it first if needed.Since v3.0.0, verify_aml_flag fails closed: country codes must be canonical ISO alpha-2 codes, and malformed, non-finite, or missing amounts are rejected instead of passing.

How Z3 works


2. Calendar guard (day counts)

Purpose: Deterministic day count conventions for interest calculations, computed with exact Decimal arithmetic.

Supported conventions

Other methods: verify_day_count_fraction(), verify_accrued_interest(), verify_business_day(), and get_next_business_day().

3. Derivatives guard (Black-Scholes)

Purpose: Check option prices, Greeks and margin figures, computed with mpmath.

Methods

Arbitrary-precision arithmetic

Since v2.1.0: DerivativesGuard uses mpmath (30 decimal places) for all transcendental functions (log, exp, sqrt and erf) instead of IEEE-754 math.* calls. The standard normal CDF and PDF (_norm_cdf, _norm_pdf) are computed to 30 decimal places, and verify_margin_call and verify_put_call_parity compare values in Decimal space.
Breaking change in v2.1.0: Greeks are str, not float. Each Greek is Decimal.quantize()’d and returned as a string to preserve precision across serialisation boundaries. Cast explicitly if you need a numeric type:
mpmath is now a runtime dependency. It was already pulled in transitively by sympy, so no extra install step is required.

4. Message guard (ISO 20022 and SWIFT)

Purpose: Check that a message carries what its type requires before it is sent: ISO 20022 XML is parsed and checked for required elements; SWIFT MT text is checked field by field (it is not XML). These are structural checks with fixed rules, not full XSD schema validation.

Supported formats

MessageGuard also provides verify_iban() and verify_bic().

SWIFT MT validation


5. ISOGuard (JSON schema)

Purpose: Check JSON payment messages shaped after ISO 20022 against a JSON Schema.

Why JSON vs. XML?

MessageGuard checks ISO 20022 XML, including transaction elements such as CdtTrfTxInf, and SWIFT MT text. ISOGuard is a lighter check for JSON messages: it validates the four required top-level fields (MsgId, CreDtTm, NbOfTxs, TtlIntrBkSttlmAmt) against a JSON Schema. A JSON message that passes ISOGuard has not been checked for everything MessageGuard requires.

6. Query guard (SQLGlot)

Purpose: Check model-written SQL before it runs: writes, tables and columns outside an allow-list, and injection patterns.

Methods

Why AST, not regex?

Queries that SQLGlot cannot parse fail closed with an SQL parse error violation.
Since v3.0.1 (GHSA-q8r4-6gpp-5fx2): queries that contain MySQL /*! ... */ or MariaDB /*M! ... */ executable comments are rejected. MySQL runs the content of these comments, but the parser drops it, so tables and columns inside them could bypass the allow-list and PII checks. This applies to verify_readonly_safety, verify_table_access, verify_column_access, sanitize_query, and CrossGuard.verify_query_with_pii_protection. Ordinary comments and optimizer hints (/*+ ... */) are unaffected.

7. Cross-guard (multi-layer)

Purpose: Run several guards on one message or query and return their results together, with receipts.

Methods

CrossGuard is the only guard that issues VerificationReceipt objects directly (in result.receipts). See Compliance and auditing.
Since v3.0.1 (GHSA-mrrj-6m2q-jch9): business rules read IntrBkSttlmAmt values and Ccy attributes from the parsed XML tree (local names, any namespace), not from regex over raw text. Amounts with child nodes, exponents, or grouping separators fail closed as unparseable.Since v3.0.1 (GHSA-mv2c-jwm9-pfrq): sanctions screening folds diacritics and look-alike letters and compares separator-free names, so EV-IL CORP, E.V.I.L. CORP, or ÉVIL CORP no longer clear an EVIL CORP entry. An empty or missing sanctions list fails closed as unscreened.

8. Bond guard (yield analytics)

Purpose: Check fixed-income figures such as yield to maturity (YTM) and duration, solved with Newton-Raphson.
verify_ytm() and verify_duration() default to semi-annual coupons (frequency=2): coupon_rate is annual, paid in two halves, and YTM is the bond-equivalent annual yield. Pass frequency=1 for annual coupons, or 4 for quarterly. For the bond above, annual coupons give 5.6687%, so pass the frequency your bond actually pays.

Rate format rules

Since v2.1.0: _parse_rate() no longer silently guesses whether an input is a percentage or decimal. The old heuristic (val < 1 → decimal, else percentage) has been removed.
The same explicit-% rule applies to BondGuard._parse_rate() and FinanceVerifier.verify_irr(), so a rate string means the same thing in both.

Exact arithmetic with Decimal

Since v2.1.0: BondGuard runs Newton-Raphson YTM solving and all duration, convexity, and accrued-interest math in Decimal with 50-digit precision (getcontext().prec = 50). Inputs are converted to Decimal at the boundary, eliminating IEEE-754 cancellation in long-dated bond cashflow sums.tolerance_pct is now stored as Decimal. Pass a float or int; the guard converts it with Decimal(str(value)) to avoid float contamination:
verify_ytm, verify_duration, and verify_convexity return computed_value and their details fields as quantized strings (e.g. "5.6617%") instead of raw floats.Other methods: verify_accrued_interest() and verify_dirty_price().

9. FX guard (currency conversion)

Purpose: Check currency conversions, cross and forward rates, and arbitrage decisions.
Pass llm_converted as a plain number ("920.00"). A leading currency symbol ($, €, £, ¥) is stripped, but currency codes such as "EUR 920.00" raise decimal.InvalidOperation.

Methods


10. Risk guard (portfolio metrics)

Purpose: Recompute risk metrics such as the Sharpe ratio and value at risk (VaR) and compare them with the model’s figures.

Exact arithmetic with Decimal

Since v2.1.0: every RiskGuard method computes in Decimal. verify_var and verify_sortino_ratio use Decimal.sqrt() instead of math.sqrt(), and verify_beta accumulates covariance and variance in Decimal to prevent catastrophic cancellation on large return histories.The Z_SCORES lookup table is Decimal-typed:

11. Trading guard (order parameters)

Purpose: Verify order payloads for prediction markets (tick size, price bounds, volume, contract type, side) before they reach an execution API.
Unknown markets fail closed (risk = "UNKNOWN_MARKET"). Prices are exact Decimal values; float prices, non-finite values, and boolean volumes are rejected. Use verify_order_batch() to check a list of orders.
All 11 guards are available via pip install qwed-finance.