σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyRoteiros
Ctrl K
AO
+1,2 mil alunos
EntrarParticipar ↗
Roteiros
AO
+1,2 mil alunos
Entrar
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Roteiro de Python›Módulo 4 · Precificação de renda fixa e opções›Tópico 4.4·~50 minIntermediário

Duração e convexidade

Posição no roteiroMódulo 4 de 11 · Tópico 4 de 16
4.4 Duração e convexidade
—Nota do lab— / 100XP total—Sequência—

Qual é o comprimento real de um título?

O vencimento diz quando chega o último pagamento, mas um título que paga cupons grandes devolve grande parte do seu dinheiro antes. A duração de Macaulay é o tempo médio para receber os fluxos, ponderando cada data de pagamento pela sua parcela do preço: sum(t * PV(t)) / preço. Um título de cupom zero tem duração igual ao vencimento; os cupons a reduzem. Nosso título de 10 anos a 5% com rendimento de 6% tem duração de 7,9 anos. A duração é o comprimento real do título no tempo.

import numpy as np

def bond_cashflows(face, coupon_rate, years, freq):
    n = int(round(years * freq))
    times = np.arange(1, n + 1) / freq
    flows = np.full(n, face * coupon_rate / freq)
    flows[-1] += face
    return times, flows

times, flows = bond_cashflows(1000, 0.05, 10, 2)
pv = flows / (1 + 0.06 / 2) ** (2 * times)           # present value of each payment
price = pv.sum()
macaulay = (times * pv).sum() / price                # the average time, weighted by present value
print(round(price, 4), round(macaulay, 4))           # 925.6126 7.895   shorter than the 10-year maturity

Da duração ao risco de preço

Dividir por 1 + ytm / freq dá a duração modificada, que tem um significado direto: é a queda percentual do preço para uma alta de uma unidade (100 pontos) no rendimento; uma duração modificada de 7,67 significa cerca de -7,67% para +1 ponto percentual, em primeira aproximação: dP / P ≈ -D_mod * dy. É o número que as mesas de risco citam como a sensibilidade do título à taxa de juros. Ele também explica por que o título longo do tópico anterior caiu muito mais que o curto: sua duração é maior.

modified = macaulay / (1 + 0.06 / 2)
print(round(modified, 4))                       # 7.6654   about -7.67% of price for +1 percentage point of yield

dy = 0.01
print(round(price * (1 - modified * dy), 2))    # 854.66   the first-order estimate after a rise to 7%
# the exact price at 7% is 857.88: duration alone underestimates it

Convexidade: a curvatura

A relação preço-rendimento é uma curva, não uma reta, e a duração é apenas sua tangente. A tangente subestima o preço para movimentos nos dois sentidos, porque a curva se dobra para cima: um título ganha mais quando os rendimentos caem do que perde quando sobem o mesmo valor. A convexidade mede essa curvatura, a partir da segunda derivada: sum(fluxo * t * (t + 1/freq) / (1 + y/freq) ** (freq * t + 2)) / preço. Somar o termo 0.5 * convexidade * dy² à estimativa pela duração dá uma previsão de preço muito melhor, e importa mais quanto maior o movimento.

convexity = (flows * times * (times + 1 / 2) / (1 + 0.06 / 2) ** (2 * times + 2)).sum() / price
print(round(convexity, 3))                                   # 71.785

for dy in (0.01, -0.01, 0.03):
    exact = bond_price(1000, 0.05, 0.06 + dy, 10)
    duration_only = price * (1 - modified * dy)
    with_convexity = price * (1 - modified * dy + 0.5 * convexity * dy ** 2)
    print(dy, round(exact, 2), round(duration_only, 2), round(with_convexity, 2))
# 0.01 857.88 854.66 857.99
# -0.01 1000.0 996.56 999.88
# 0.03 739.84 712.77 742.67      for a big move convexity matters most
# Duration by maturity for a 5% bond at a 6% yield: it grows with maturity, but slower than one for one
for years in (1, 5, 10, 30):
    t_, f_ = bond_cashflows(1000, 0.05, years, 2)
    p_ = f_ / (1 + 0.06 / 2) ** (2 * t_)
    print(years, round((t_ * p_).sum() / p_.sum(), 3))
# 1 0.988
# 5 4.472
# 10 7.895
# 30 14.77
A duração é para movimentos pequenosA duração supõe um movimento paralelo de um único rendimento; curvas reais se torcem e grandes movimentos precisam também da convexidade. Use a duração para comparar o risco de juros dos títulos e proteger pequenas variações. Para cenários de alguns pontos, reprecifique o título por completo, que é exatamente o que bond_price faz.
  • Duração de Macaulay = sum(t * PV) / preço, o tempo médio até o dinheiro; a de um cupom zero é seu vencimento.
  • Duração modificada = Macaulay / (1 + ytm / freq): a queda relativa do preço para +1 de rendimento, dP / P ≈ -D_mod * dy.
  • Estimativa do preço = preço * (1 - D_mod * dy + 0.5 * convexidade * dy²); o termo de convexidade corrige a tangente, sobretudo em grandes movimentos.

A seguir: as curvas de juros e a interpolação, porque prazos diferentes têm taxas diferentes.

Lab: o que é avaliado

  • Achar o tempo médio até receber seu dinheiro com macaulay_duration25 pts
  • Transformá-la em sensibilidade do preço com modified_duration25 pts
  • Capturar a curvatura com convexity25 pts
  • Prever o novo preço sem reprecificar com price_estimate25 pts
Explorador · lab-69-1
▾ lab-69-1
…
bash · no navegador
learner@quantcraft:~/lab-69-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

Tudo em lab-69-1 volta aos arquivos iniciais e o terminal é limpo. Sua solução atual será perdida — isso não pode ser desfeito.

Será redefinido
  • main.py → código inicial
  • Histórico do terminal e saída dos testes
  • Alterações não enviadas
Será mantido
  • Melhor nota do lab
  • Seu XP e sua sequência
  • Progresso da aula e anotações

Entre para executar o seu código.

Todas as aulas são gratuitas para ler. Crie uma conta ou entre para executar código, rodar os testes e enviar este lab.

  • IDE no navegador com terminal bash — nada para instalar
  • Correção instantânea, XP e o seu lugar no roteiro
Criar uma contaEntrar
OU
Continuar com o GitHub