Skip to main content

Stress-test mathematical and financial logic in Python code — find the exact line where models break.

Project description

blackswan

PyPI version Python License: MIT

A stress-testing engine for financial and mathematical Python code.

BlackSwan finds the exact source line where your model breaks under extreme conditions — before production does. It is a debugger for numerical fragility, not a linter, not a simulator.


Installation

pip install blackswan

Requires Python 3.11+ and NumPy 1.26+.


Quickstart

# Stress-test a function with the liquidity crash scenario
python -m blackswan test models/risk.py --scenario liquidity_crash
{
  "status": "failures_detected",
  "runtime_ms": 2840,
  "iterations_completed": 5000,
  "summary": {
    "total_failures": 847,
    "failure_rate": 0.1694,
    "unique_failure_types": 1
  },
  "shatter_points": [
    {
      "line": 36,
      "severity": "critical",
      "failure_type": "non_psd_matrix",
      "message": "Covariance matrix loses positive semi-definiteness when pairwise correlation exceeds 0.91. Smallest eigenvalue: -0.0034.",
      "frequency": "847 / 5000 iterations (16.9%)",
      "causal_chain": [
        { "line": 8,  "variable": "correlation", "role": "root_input" },
        { "line": 31, "variable": "corr_matrix",  "role": "intermediate" },
        { "line": 36, "variable": "cov_matrix",   "role": "failure_site" }
      ],
      "fix_hint": "Apply nearest-PSD correction (Higham 2002) after correlation perturbation, or clamp eigenvalues to epsilon."
    }
  ]
}

CLI Reference

python -m blackswan test <file> [options]

Options:
  --scenario     Preset scenario name (required)
  --function     Target function name (auto-detected if omitted)
  --iterations   Number of Monte Carlo iterations (default: 5000)
  --seed         Random seed for reproducibility (default: 42)
  --adversarial  Use genetic algorithm to search for worst-case inputs
  --population   GA population size (default: 100, requires --adversarial)

Exit codes: 0 = no failures, 1 = failures detected, 2 = engine error.

Available Scenarios

Name Description
liquidity_crash Spread widening, vol expansion, correlation stress, turnover collapse
vol_spike 2–4× volatility multiplier, mild correlation increase
correlation_breakdown Pairwise correlation shift +0.20–+0.50
rate_shock +100–+300 bps interest rate shock with spread widening
missing_data Random NaN injection and partial time series truncation

Python API

from blackswan.engine.runner import StressRunner
from blackswan.scenarios.registry import load_scenario

scenario = load_scenario("liquidity_crash")
runner = StressRunner(scenario)

result = runner.run(
    calculate_portfolio_var,
    base_inputs={"weights": weights, "vol": vols, "correlation": 0.0},
)

print(f"Failures: {len(result.findings)}")
for finding in result.findings:
    print(f"  Line {finding.line} [{finding.severity}]: {finding.message}")

Adversarial API

from blackswan.engine.adversarial import EvolutionaryStressRunner

runner = EvolutionaryStressRunner(
    scenario,
    n_generations=20,
    population_size=100,
    elite_fraction=0.2,
)
result = runner.run(fn, base_inputs)

Custom Detectors

from blackswan.detectors.numerical import LogicalInvariantDetector

# Weights must always sum to 1 (+/-1e-6)
invariant = LogicalInvariantDetector(
    assertion=lambda inputs, output: abs(output.sum() - 1.0) < 1e-6,
    name="weights_sum_to_one",
)
runner = StressRunner(scenario, extra_detectors=[invariant])

Failure Detectors

Detector Catches Always active?
NaNInfDetector NaN or Inf in any output Yes
DivisionStabilityDetector Denominator approaching zero Yes
MatrixPSDDetector Covariance/correlation matrix non-PSD Auto (on matrix code)
ConditionNumberDetector Ill-conditioned matrices (cond > 1e12) Auto (on linalg.inv)
BoundsDetector Outputs outside configurable plausible ranges Auto
ExplodingGradientDetector Output growth > 100x input perturbation Auto
RegimeShiftDetector Structural breaks in output distribution Auto
LogicalInvariantDetector User-defined assertions On demand

Detectors are auto-tagged to relevant source lines via AST analysis.


Custom Scenarios

Create a YAML file and pass its path as --scenario:

name: my_scenario
description: "Custom stress test for credit portfolio"
perturbations:
  - target: spread
    type: multiplicative
    distribution: lognormal
    mu: 2.0
    sigma: 0.4
    constraints:
      min: 1.0
      max: 5.0
  - target: correlation
    type: additive
    distribution: uniform
    low: 0.15
    high: 0.40
global_constraints:
  - target: correlation
    min_value: -1.0
    max_value: 0.95
defaults:
  iterations: 5000
  seed: 42
python -m blackswan test models/credit.py --scenario path/to/my_scenario.yaml

What BlackSwan Supports

Works well on:

  • Pure functions with NumPy / Pandas inputs and outputs
  • Explicit variable assignments
  • NumPy array operations, linalg, random
  • Pandas DataFrame column operations
  • Single-file scripts and focused modules

Out of scope for V1:

  • Deeply nested class hierarchies with side effects
  • Config-driven logic loading parameters from databases
  • Multi-threaded or async computation pipelines
  • C extensions or Cython modules

Links


License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

blackswan-0.1.2.tar.gz (70.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

blackswan-0.1.2-py3-none-any.whl (84.5 kB view details)

Uploaded Python 3

File details

Details for the file blackswan-0.1.2.tar.gz.

File metadata

  • Download URL: blackswan-0.1.2.tar.gz
  • Upload date:
  • Size: 70.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for blackswan-0.1.2.tar.gz
Algorithm Hash digest
SHA256 bef2d52fcfabf12d8150c1f6556e24ea887833e071d2e7b10715a02f65c7aefa
MD5 be3348bf6ccd9034cd855a2898545e87
BLAKE2b-256 8b2613c55788c0e7654f2422cc110ed895bdad69fc005227de88812324aab862

See more details on using hashes here.

Provenance

The following attestation bundles were made for blackswan-0.1.2.tar.gz:

Publisher: workflow.yml on Lushenwar/BlackSwan

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file blackswan-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: blackswan-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 84.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for blackswan-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a7ec2a2485c6cab1dbb676f8b8c5e26623d561a98a0460c7c0fa4631987bfc88
MD5 b85f559845d08ab0021de2e941255b8f
BLAKE2b-256 47d77e54d9358977154d545ba882f99a8df4e2f880af23ef8ce4c10b3f5aaef1

See more details on using hashes here.

Provenance

The following attestation bundles were made for blackswan-0.1.2-py3-none-any.whl:

Publisher: workflow.yml on Lushenwar/BlackSwan

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page