Skip to main content

Precificador de derivativos em Python (MC/LSMC, PDE CN, FFT Heston, IR Black-76) com DSL declarativa.

Project description

derivx

CI

Precificador geral de derivativos por blocos de construção

  • Modelo sob Q (GBM multiativo com correlação; r(t), q_i(t), σ_i(t))
  • Numerário piecewise-flat (desconto determinístico exato por trechos)
  • Payoffs PF (funcionais de trajetória): terminal, média, máx/mín, basket, barreira…
  • Exercício Européias, Bermudas, Americanas (LSMC robusto)
  • PDE 1D (Crank–Nicolson) para vanillas (inclui Americano via projeção)
  • FFT (Heston) para europeias (Carr–Madan)
  • Analítico (Haug/Margrabe): Digitais, Gap, Exchange
  • Renda Fixa (IR / Black‑76): ZCB, FRA, Swap (PV/par rate), Cap/Floor, Swaptions payer/receiver
  • DSL declarativa (dict/JSON) para montar produto e precificar
  • Visualização de payoff + inputs + equações + preço (via plot_report)
  • Testes e CI prontos (pytest + GitHub Actions)

Índice


Instalação

Requisitos: Python 3.11+ (testado). A instalação em modo dev já traz dependências de testes.

Windows (PowerShell):

python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
# opcional para relatórios/plots:
pip install matplotlib
# executar testes (desabilita plugins externos do pytest)
$env:PYTEST_DISABLE_PLUGIN_AUTOLOAD = "1"
python -m pytest -q

macOS / Linux (bash/zsh):

python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
# opcional para relatórios/plots:
pip install matplotlib
# executar testes (desabilita plugins externos do pytest)
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest -q

Hello, World (Quick Start)

from derivx import price_from_spec, bs_call_price

spec = {
  "engine": "mc",
  "model": {"name":"gbm","r":0.05,"q":0.0,"sigma":0.2},
  "grid": {"T": 1.0, "steps": 128},
  "S0": [100.0],
  "product": {"style":"european","type":"european_call","asset":0,"K":100.0},
  "n_paths": 80_000, "seed": 42,
}
p, se = price_from_spec(spec)
print("MC:", p, "±", 1.96*se)
print("BS:", bs_call_price(100, 100, r=0.05, q=0.0, sigma=0.2, T=1.0))

Visão de arquitetura

  • Curva (numerário): PiecewiseFlatCurve implementa ( r(t) ) piecewise-flat, com desconto exato por trechos ( DF(t_0,t_1)=\exp{-\int_{t_0}^{t_1} r(u),du} ).
  • Modelos sob ( \mathbb{Q} ):
    • RiskNeutralGBM (multiativo; q_i(t), σ_i(t), correlação via Cholesky)
    • Heston (europeias) — MC e FFT (Carr–Madan)
  • Payoffs PF (funcionais de trajetória): utilitários vetorizados para terminal, médias, running max/min, barreiras, cestas…
  • Motores numéricos:
    • MC: simulação GBM/Heston, antitético e (opcional) control variate
    • PDE CN 1D: vanillas (europeias/americanas)
    • FFT (Heston): preços para vários strikes
    • Analítico: fórmulas fechadas (digitais, gap, exchange; IR Black‑76)
  • Exercício (LSMC): regressão do valor de continuação em features (padrão: log S com base polinomial até grau 2 + cruzados)
  • DSL: price_from_spec(spec) mapeia um dicionário JSON para engine, grade temporal e produto.

Usando a DSL (price_from_spec)

Chaves principais

  • engine: "mc" | "pde" | "fft" | "analytic" | "auto"
    auto tenta analítico/PDE/FFT quando aplicável; senão cai para MC.
  • model:
    • GBM: {"name":"gbm", "r":..., "q":..., "sigma":..., "corr":...}
    • Heston: {"name":"heston","r":...,"q":...,"kappa":...,"theta":...,"xi":...,"rho":...,"v0":...}
    • IR flat: {"r": 0.05} (ou use r_curve para curva por trechos)
  • grid:
    • MC: {"T":..., "steps":...} (uniforme)
    • PDE/FFT/Analítico: usa {"T":...} quando aplicável
  • S0: lista de preços iniciais (uma entrada por ativo; em IR puro pode ser vazio [])
  • product:
    • style: "european" | "bermudan" | "american"
    • type: ver Produtos suportados
    • Parametrização conforme o tipo (asset, K, barrier, weights, …)
    • Exercício (bermudan): exercise_idx, exercise_times ou exercise_every
  • Parâmetros do motor:
    • MC: n_paths, seed
    • PDE: NS, NT, Smax_mult
    • FFT: alpha, N, eta

Exemplos práticos

1) Europeu (MC) vs Black–Scholes

from derivx import price_from_spec, bs_call_price

S0=K=100.0; r=0.05; q=0.0; sigma=0.2; T=1.0
spec = {
  "engine":"mc",
  "model":{"name":"gbm","r":r,"q":q,"sigma":sigma},
  "grid":{"T":T,"steps":128},
  "S0":[S0],
  "product":{"style":"european","type":"european_call","asset":0,"K":K},
  "n_paths":80_000,"seed":42,
}
pmc,se = price_from_spec(spec)
pbs = bs_call_price(S0,K,r,q,sigma,T)
print(f"MC={pmc:.4f} ± {1.96*se:.4f} | BS={pbs:.4f}")

2) PDE (put europeu vs americano)

from derivx import price_from_spec

euro = {"engine":"pde","model":{"name":"gbm","r":0.05,"q":0.0,"sigma":0.2},
        "grid":{"T":1.0},"S0":[100.0],
        "product":{"style":"european","type":"european_put","asset":0,"K":100.0},
        "NS":800,"NT":800,"Smax_mult":5.0}

amer = {**euro, "product":{"style":"american","type":"european_put","asset":0,"K":100.0}}

pe,_ = price_from_spec(euro)
pa,_ = price_from_spec(amer)
print(f"PDE euro={pe:.4f}  PDE amer={pa:.4f}  (amer >= euro)")

3) Barreira up-and-out (monotonia)

base = {"engine":"mc","model":{"name":"gbm","r":0.05,"q":0.0,"sigma":0.2},
        "grid":{"T":1.0,"steps":128},"S0":[100.0],
        "n_paths":100_000,"seed":7}

van,_   = price_from_spec({**base,"product":{"style":"european","type":"european_call","asset":0,"K":100.0}})
uo130,_ = price_from_spec({**base,"product":{"style":"european","type":"up_and_out_call","asset":0,"K":100.0,"barrier":130.0}})
uo140,_ = price_from_spec({**base,"product":{"style":"european","type":"up_and_out_call","asset":0,"K":100.0,"barrier":140.0}})
print(f"UO130={uo130:.4f} <= UO140={uo140:.4f} <= Vanilla={van:.4f}")

4) Asiática aritmética (≤ vanilla)

asian,_ = price_from_spec({**base,"product":{"style":"european","type":"asian_arith_call","asset":0,"K":100.0}})
print(f"Asian={asian:.4f} <= Vanilla={van:.4f}")

5) Bermudana (LSMC): efeito da frequência de exercício

def berm(ex_every):
  spec={"engine":"mc","model":{"name":"gbm","r":0.05,"q":0.0,"sigma":0.2},
        "grid":{"T":1.0,"steps":256},"S0":[100.0],
        "product":{"style":"bermudan","type":"european_put","asset":0,"K":100.0,"exercise_every":ex_every},
        "n_paths":120_000,"seed":7}
  return price_from_spec(spec)

for ex in (8,16,32):
  p,se = berm(ex)
  print(f"ex_every={ex:>2}: {p:.4f} ± {1.96*se:.4f}")

6) Heston: FFT vs MC

common={"name":"heston","r":0.05,"q":0.0,"kappa":1.5,"theta":0.04,"xi":0.5,"rho":-0.7,"v0":0.04}

fft={"engine":"fft","model":common,"grid":{"T":1.0},"S0":[100.0],
     "product":{"style":"european","type":"european_call","asset":0,"K":100.0},
     "alpha":1.5,"N":4096,"eta":0.25}

mc={"engine":"mc","model":common,"grid":{"T":1.0,"steps":512},"S0":[100.0],
    "product":{"style":"european","type":"european_call","asset":0,"K":100.0},
    "n_paths":200_000,"seed":7}

p_fft,_ = price_from_spec(fft)
p_mc,se = price_from_spec(mc)
print(f"FFT={p_fft:.4f} | MC={p_mc:.4f} ± {1.96*se:.4f}")

7) Basket 2D (GBM correlacionado)

spec={"engine":"mc",
      "model":{"name":"gbm","r":0.05,"q":[0.01,0.03],"sigma":[0.20,0.30],
               "corr":[[1.0,0.5],[0.5,1.0]]},
      "grid":{"T":2.0,"steps":80},"S0":[100.0,120.0],
      "product":{"style":"european","type":"basket_call","weights":[0.5,0.5],"K":110.0},
      "n_paths":100_000,"seed":3}
p,se = price_from_spec(spec)
print(p, "±", 1.96*se)

8) Analítico (Haug/Margrabe) — Digitais, Gap, Exchange

{
  "engine":"analytic",
  "model":{"r":0.05,"q":[0.0],"sigma":[0.2],"corr":[[1.0]]},
  "grid":{"T":1.0},
  "S0":[100.0],
  "product":{"style":"european","type":"asset_or_nothing_call","asset":0,"K":100.0}
}

9) Renda Fixa (IR, Black‑76): FRA, Swap (PV/par), Cap/Floor, Swaptions

FRA (PV)

spec = {
  "engine": "analytic",
  "model": {"r": 0.05},   # ou r_curve: {"times":[...], "rates":[...]}
  "grid": {"T": 1.0},
  "S0": [],
  "product": {"style":"european","type":"fra","T1":1.0,"T2":1.5,"tau":0.5,"K":0.045,"notional":1.0}
}
pv,_ = price_from_spec(spec)

Swap (PV)

spec = {
  "engine":"analytic","model":{"r":0.05},"grid":{"T":2.0},"S0":[],
  "product":{"style":"european","type":"swap","T0":0.0,
             "payment_times":[0.5,1.0,1.5,2.0],
             "tau":0.5, "fixed_rate":0.05, "notional":1.0}
}
pv,_ = price_from_spec(spec)

Cap (soma de caplets via Black‑76)

spec = {
  "engine":"analytic","model":{"r":0.05},"grid":{"T":2.0},"S0":[],
  "product":{"style":"european","type":"cap",
             "payment_times":[0.5,1.0,1.5,2.0],
             "tau":0.5,"K":0.04,"sigma":0.20,"notional":1.0}
}
pv,_ = price_from_spec(spec)

Swaption payer (Black‑76 no swap subjacente)

spec = {
  "engine":"analytic","model":{"r":0.05},"grid":{"T":2.0},"S0":[],
  "product":{"style":"european","type":"payer_swaption","expiry":1.0,
             "payment_times":[1.5,2.0,2.5],"tau":0.5,"K":0.05,"sigma":0.25,"notional":1.0}
}
pv,_ = price_from_spec(spec)

Produtos suportados

✔️ = implementado / OK

Vanillas (GBM)

  • ✔️ european_call, european_put (MC e PDE)
  • ✔️ Americano (put/call) via PDE 1D (Crank–Nicolson)
  • ✔️ Bermudano (LSMC) com exercise_every, exercise_idx ou exercise_times

Path-dependentes (GBM)

  • ✔️ asian_arith_call
  • ✔️ Barreira: up_and_out_call (outros tipos na fila)

Multi-ativo (GBM)

  • ✔️ basket_call (pesos arbitrários)
  • ✔️ exchange_call (Margrabe, 2 ativos)

Analíticos (Haug/Margrabe)

  • ✔️ Digitais: cash_or_nothing_call|put, asset_or_nothing_call|put
  • ✔️ Gap: gap_call, gap_put
  • ✔️ Exchange (Margrabe): exchange_call

Heston

  • ✔️ Europeias (FFT Carr–Madan; MC)

Renda Fixa (IR / Black‑76)

  • ✔️ zcb, fra, swap (PV/par rate), cap, floor, payer_swaption, receiver_swaption

Roadmap curto

  • Digitais/barreiras adicionais (up/down, in/out, rebates)
  • Asians put, lookbacks, cliquets
  • Greeks pathwise/LRM
  • Calibração Heston/GBM (smiles/term-structure)

Visualização (plot_report)

O módulo derivx.report.plot gera uma figura PNG com:

  1. Curva de payoff (quando aplicável – ex.: vanilla, digital, asiática estimada)
  2. Inputs do spec (parâmetros usados no preço)
  3. Equações (payoff + fórmula de precificação, quando disponível)
  4. Preço (e SE se for MC)

Instale a dependência opcional:

pip install matplotlib

Exemplo (vanilla call, analítico):

from derivx.report import plot_report

spec = {
  "engine": "analytic",
  "model": {"r": 0.05, "q": [0.0], "sigma": [0.2], "corr": [[1.0]]},
  "grid": {"T": 1.0},
  "S0": [100.0],
  "product": {"style": "european", "type": "european_call", "asset": 0, "K": 100.0},
}

rep = plot_report(spec, filename="report_call.png", dpi=150)
print("Preço:", rep.price, "SE:", rep.se, "PNG:", rep.png_path)

Gerar relatórios de exemplo via pytest (salvos em uma pasta temporária):

PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest tests/report -q
# Os PNGs são criados em diretórios temporários de teste (impressos no log se um teste falhar).

Validação & testes

  • Consistência BS: MC (GBM) ≈ Black–Scholes (dentro de k·SE)
  • PDE vs BS: put europeu CN ≈ BS; americano PDE ≥ europeu
  • Monotonicidades: up&out ≤ vanilla; Bermudano densificando → Americano
  • Heston: MC ≈ FFT (tolerância baseada em SE)
  • Analíticos (Haug/Margrabe/Black‑76): testes de referência com fórmulas fechadas

Rode todos os testes (desabilitando plugins externos do PyTest):

# Windows
$env:PYTEST_DISABLE_PLUGIN_AUTOLOAD="1"
python -m pytest -q

One-click (Windows):

# roda testes, faz commit (se houver mudanças), puxa e dá push
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\oneclick.ps1

Dicas de precisão & performance

Backend Parâmetro Efeito
MC n_paths SE ∝ 1/√N (custo linear)
MC steps Reduz viés temporal (path-dep./LSMC); custo ∝ paths×steps
PDE NS, NT Convergência O(Δt + ΔS²); aumente até estabilizar
PDE Smax_mult Domínio [0, S_max]; comece com 5–7×K
FFT alpha Damping (1–2 típico); extremos podem instabilizar
FFT N, eta Resolução em frequência/strike

LSMC – boas práticas

  • Regressão apenas em ITM
  • Desconto correto entre janelas (Δt múltiplos)
  • Cross-fit A/B para reduzir overfit
  • Checar monotonia (Bermudano ↑ conforme mais janelas)

Estrutura do repositório

src/derivx/
  __init__.py
  curves.py               # PiecewiseFlatCurve
  models/gbm.py           # RiskNeutralGBM
  engine/montecarlo.py
  engine/pde.py           # Crank–Nicolson 1D (vanillas)
  engine/fft.py           # Heston (Carr–Madan)
  exercise/lsmc.py        # LSMC (com fix de desconto entre janelas)
  payoffs/core.py         # PF utilitários (terminal, média, etc.)
  payoffs/extra.py        # Digitais, Gap, Exchange, etc. (PF)
  analytic/bs.py          # Φ, d1d2, BS
  analytic/haug.py        # Digitais, Gap, Margrabe (closed-form)
  ir/black76.py           # ZCB, FRA, swap PV/par, cap/floor, swaptions (Black-76)
  dsl/spec.py             # Mapeia dict -> engine/produto
  report/plot.py          # plot_report: payoff + inputs + equações + preço
tests/
  reference/              # testes de referência (BS/Haug/Margrabe/Black-76…)
  report/                 # smoke tests de plot_report
scripts/
  oneclick.ps1            # roda testes + commit + sync + push
README.md

Contribuindo

  1. Crie um branch: git checkout -b feat/minha-feature
  2. Adicione testes em tests/
  3. Garanta python -m pytest -q verde
  4. Abra um Pull Request (descrevendo escopo, resultados esperados e validação)

Padrões

  • Estilo PEP 8 / tipagem leve
  • Funções puras e vetorização onde possível
  • Documentar decisões numéricas (condições de contorno PDE, escolhas FFT…)

Referências

  • Black, F.; Scholes, M. (1973) The Pricing of Options and Corporate Liabilities
  • Longstaff, F.; Schwartz, E. (2001) Valuing American Options by Simulation
  • Carr, P.; Madan, D. (1999) Option Valuation Using the FFT
  • Heston, S. (1993) A Closed-Form Solution for Options with Stochastic Volatility
  • Margrabe, W. (1978) The Value of an Option to Exchange One Asset for Another
  • Haug, E. G. (2006) The Complete Guide to Option Pricing Formulas
  • Black, F. (1976) The Pricing of Commodity Contracts (Black‑76)

Licença

MIT. Uso acadêmico/educacional; valide premissas, calibração e risco de modelo antes de produção.

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

derivx_precificador-0.1.1.tar.gz (33.5 kB view details)

Uploaded Source

Built Distribution

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

derivx_precificador-0.1.1-py3-none-any.whl (29.1 kB view details)

Uploaded Python 3

File details

Details for the file derivx_precificador-0.1.1.tar.gz.

File metadata

  • Download URL: derivx_precificador-0.1.1.tar.gz
  • Upload date:
  • Size: 33.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.0

File hashes

Hashes for derivx_precificador-0.1.1.tar.gz
Algorithm Hash digest
SHA256 3777327e1b26f0f0e86bc8d97354c70f6b71b7634a24c45741c3ee30250ba099
MD5 c095cead9d6634fbdb361377128a05b0
BLAKE2b-256 c3e658c341b3a608b9bbbd6b2bb197216cd0ecf0aea88d1972bc0ed1ff0fe273

See more details on using hashes here.

File details

Details for the file derivx_precificador-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for derivx_precificador-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0ce521b31629e38e410fd2df2857045dd46cec46424ddc34273498854f986537
MD5 979bc595e3de43c8b56cb422d637ca49
BLAKE2b-256 9372e1af9d72e85d777e645df995d4675b638ca9276689de7f03c5eda014f3e8

See more details on using hashes here.

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