σμ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 2 · NumPy e pandas para dados de mercado›Tópico 2.20·~35 minIntermediário

Histogramas e distribuições

Posição no roteiroMódulo 2 de 11 · Tópico 20 de 20
2.20 Histogramas e distribuições
—Nota do lab— / 100XP total—Sequência—

Contar por faixa

A média e o desvio padrão comprimem mil retornos em dois números. Um histograma guarda a forma: divide a faixa de valores em intervalos e conta quantas observações caem em cada um. Barras altas no meio e baixas nas pontas dão o sino conhecido; uma forma desequilibrada ou de pontas pesadas é um aviso. np.histogram(values, bins=edges) devolve as contagens e trabalha em um array inteiro. O intervalo i pega os valores de edges[i] incluído até edges[i + 1] excluído; só o último intervalo inclui também a borda direita.

import numpy as np

returns = np.array([-0.021, -0.012, -0.008, -0.004, -0.002, 0.000, 0.001, 0.003, 0.004, 0.006, 0.009, 0.015, 0.032])
edges = np.array([-0.03, -0.01, 0.0, 0.01, 0.03])      # four bins: -3%..-1%, -1%..0%, 0%..1%, 1%..3%

counts, _ = np.histogram(returns, bins=edges)
print(counts.tolist(), counts.sum(), len(returns))      # [2, 3, 6, 1] 12 13   the 3.2% return is outside every bin

# bins=4 asks numpy for 4 equal-width bins between the minimum and the maximum
counts, edges4 = np.histogram(returns, bins=4)
print(counts.tolist(), edges4.round(4).tolist())        # [3, 6, 3, 1] [-0.021, -0.0078, 0.0055, 0.0188, 0.032]

Frequência ou densidade

As contagens dependem do número de observações e da largura das faixas, então dois histogramas com tamanhos de amostra diferentes não se comparam. Uma densidade resolve isso: divida cada contagem pelo total contado e pela largura da faixa, de modo que a área das barras some 1. Aí uma densidade pode ser comparada com uma curva teórica, como o sino normal, ou com outra amostra. np.histogram(values, bins=edges, density=True) faz isso, assim como counts / (counts.sum() * np.diff(edges)).

counts, _ = np.histogram(returns, bins=edges)
density = counts / (counts.sum() * np.diff(edges))
print(density.round(2).tolist())              # [8.33, 25.0, 50.0, 4.17]
print((density * np.diff(edges)).sum())        # 1.0   the areas add up to 1

Desenhá-lo e ler as caudas

ax.hist(values, bins=10) conta e desenha em uma chamada: uma barra por faixa (ax.patches), cujas alturas são as contagens. Sempre dê nome aos eixos, pois um histograma de retornos não significa nada sem "Retorno diário" embaixo. O que importa é a forma, e o que machuca são as caudas: contar a parcela de observações a mais de k desvios padrão da média, np.mean(np.abs(x - mean) > k * std), diz com que frequência os extremos acontecem. Numa normal, cerca de 4,6% dos valores ficam além de 2 desvios e 0,27% além de 3. Os mercados são piores, como os próximos tópicos mostram.

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.hist(returns, bins=5)
ax.set_xlabel("Daily return")
ax.set_ylabel("Frequency")
print(len(ax.patches), [round(p.get_height()) for p in ax.patches])   # 5 [2, 4, 5, 1, 1]   one bar per bin; the heights are the counts

# How often are the returns more than 1 standard deviation from the mean?
mean, std = returns.mean(), returns.std(ddof=1)
print(round(float(np.mean(np.abs(returns - mean) > 1 * std)), 3))     # 0.308   about 4 of 13 days
# The number of bins changes the picture: compare a few
for bins in (2, 4, 8):
    print(bins, np.histogram(returns, bins=bins)[0].tolist())
# 2 [9, 4]
# 4 [3, 6, 3, 1]
# 8 [1, 2, 2, 4, 2, 1, 0, 1]
As faixas mudam a imagemPoucas faixas escondem a forma e faixas demais fazem ruído. Não há um número certo único; teste alguns e compare histogramas com os mesmos limites. Lembre também que um histograma é uma amostra: a próxima parecerá um pouco diferente, então julgue a forma geral, não barras isoladas.
  • np.histogram(values, bins=edges) conta os valores de cada faixa; a última faixa inclui a borda direita.
  • Uma densidade divide pelo total contado e pela largura da faixa: as áreas somam 1 e as amostras ficam comparáveis.
  • ax.hist(values, bins=n) o desenha; np.mean(np.abs(x - mean) > k * std) mede as caudas. Dê nome aos eixos e compare com os mesmos limites.

A seguir: média e variância dos retornos, os dois números que resumem uma distribuição, calculados a partir de suas definições.

Lab: o que é avaliado

  • Contar os retornos de cada faixa com bin_counts25 pts
  • Transformar as contagens em densidade com density25 pts
  • Medir as caudas com fraction_beyond25 pts
  • Desenhar o histograma com plot_histogram25 pts
Explorador · lab-53-1
▾ lab-53-1
…
bash · no navegador
learner@quantcraft:~/lab-53-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

Tudo em lab-53-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