σμ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 AcademyRutas
Ctrl K
AO
+1,2 k estudiantes
Iniciar sesiónUnirse ↗
Rutas
AO
+1,2 k estudiantes
Iniciar sesión
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Ruta de Python›Módulo 2 · NumPy y pandas para datos de mercado›Tema 2.19·~40 minIntermedio

Gráficos de velas

Posición en la rutaMódulo 2 de 11 · Tema 19 de 20
2.19 Gráficos de velas
—Puntuación del lab— / 100XP total—Racha—

Cuatro precios en una imagen

Un gráfico de líneas de cierres desperdicia la mayor parte de un día. Una vela japonesa conserva cuatro precios a la vez: apertura, máximo, mínimo y cierre. El cuerpo grueso va de la apertura al cierre y se colorea según la dirección (verde cuando el cierre es igual o mayor que la apertura, rojo en caso contrario). La mecha fina va del mínimo al máximo. De un vistazo ves adónde fue el día, qué rango recorrió y si ganaron compradores o vendedores.

import numpy as np
import pandas as pd

df = pd.DataFrame(
    {
        "open":  [100.0, 103.0, 102.0, 104.0],
        "high":  [104.0, 105.0, 106.0, 104.5],
        "low":   [ 99.0, 101.0, 101.5, 101.0],
        "close": [103.0, 102.0, 105.5, 104.0],
    },
    index=pd.bdate_range("2026-03-02", periods=4),
)

# Green when the day closed at or above its open, red otherwise: one np.where on whole columns
colors = np.where(df["close"] >= df["open"], "green", "red")
print(colors.tolist())   # ['green', 'red', 'green', 'green']

Calcular el cuerpo

Un cuerpo es un rectángulo. Empieza en el menor de la apertura y el cierre (df[["open", "close"]].min(axis=1) toma el mínimo fila por fila) y su altura es la diferencia absoluta abs(close - open). Un día que abre y cierra al mismo precio tiene un cuerpo de altura 0: un doji, una vela de indecisión. Comparar el cuerpo con el rango total high - low dice lo decidido que fue el día, y hacerlo con columnas enteras encuentra todos los dojis de un año en una línea.

body = pd.DataFrame({
    "bottom": df[["open", "close"]].min(axis=1),    # the lower of open and close, row by row
    "height": (df["close"] - df["open"]).abs(),
})
print(body)
#             bottom  height
# 2026-03-02   100.0     3.0
# 2026-03-03   102.0     1.0
# 2026-03-04   102.0     3.5
# 2026-03-05   104.0     0.0

# Body as a share of the day's range: the last day is a doji
share = body["height"] / (df["high"] - df["low"])
print(share.round(2).tolist())          # [0.6, 0.25, 0.78, 0.0]
print((share <= 0.1).tolist())          # [False, False, False, True]

Dibujar: mechas y barras

matplotlib no tiene una llamada para velas, pero bastan dos sencillas. ax.vlines(x, ymin, ymax) dibuja de una vez una línea vertical por cada x: son las mechas, de mínimo a máximo. ax.bar(x, height, bottom=..., width=0.6, color=...) dibuja una barra por cada x a partir de bottom: son los cuerpos, y color acepta una lista con un color por barra. Coloca las velas en las posiciones 0, 1, 2, ... (np.arange(len(df))) y no en fechas, para que los fines de semana no dejen huecos. Pasar columnas enteras evita cualquier bucle sobre los días.

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

fig, ax = plt.subplots()
x = np.arange(len(df))
ax.vlines(x, df["low"], df["high"], color="black", linewidth=1)                       # the wicks
ax.bar(x, body["height"], bottom=body["bottom"], width=0.6, color=colors)               # the bodies

print(len(ax.collections), len(ax.patches))            # 1 4   one set of wicks, four bodies
print([p.get_y() for p in ax.patches])                  # [100.0, 102.0, 102.0, 104.0]   body bottoms
print(ax.collections[0].get_segments()[0].tolist())     # [[0.0, 99.0], [0.0, 104.0]]    the first wick, low to high
# Candles whose body is at most 10% of the day's range are dojis
doji = share <= 0.1
print(df.index[doji].strftime("%d %b").tolist())   # ['05 Mar']
Las imágenes se pueden leer de vueltaUn gráfico también son datos: ax.patches contiene las barras y ax.collections las mechas, con posiciones, tamaños y colores que se pueden comprobar. Probar el Axes y no los píxeles es como se verifica automáticamente una función de dibujo, y también como se depura un gráfico que parece incorrecto.
  • Una vela muestra apertura, máximo, mínimo y cierre: un cuerpo de la apertura al cierre, una mecha del mínimo al máximo.
  • La base del cuerpo es min(open, close) fila a fila (min(axis=1)), su altura abs(close - open); un cuerpo de 0 es un doji.
  • Dibuja todas las mechas con una sola llamada ax.vlines y todos los cuerpos con una sola llamada ax.bar (lista de colores); sin bucle sobre los días.

A continuación: los histogramas y las distribuciones, para contar con qué frecuencia caen los rendimientos en cada rango.

Lab: qué se califica

  • Colorear cada vela según su dirección con candle_colors25 pts
  • Medir el cuerpo de cada vela con candle_body25 pts
  • Encontrar los días de indecisión con doji_days25 pts
  • Dibujar las velas en un Axes con draw_candles25 pts
Explorador · lab-52-1
▾ lab-52-1
…
bash · en el navegador
learner@quantcraft:~/lab-52-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

Todo lo que hay en lab-52-1 vuelve a los archivos iniciales y se limpia el terminal. Tu solución actual se perderá: no se puede deshacer.

Se restablecerá
  • main.py → código inicial
  • Historial del terminal y salida de pruebas
  • Cambios sin enviar
Se conservará
  • Mejor puntuación del lab
  • Tu XP y tu racha
  • Progreso de la lección y notas

Inicia sesión para ejecutar tu código.

Todas las clases se pueden leer gratis. Crea una cuenta o inicia sesión para ejecutar código, lanzar las pruebas y enviar este lab.

  • IDE en el navegador con terminal bash — sin instalar nada
  • Corrección instantánea, XP y tu lugar en la ruta
Crear una cuentaIniciar sesión
O
Continuar con GitHub