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']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 alturaabs(close - open); un cuerpo de 0 es un doji. - Dibuja todas las mechas con una sola llamada
ax.vlinesy todos los cuerpos con una sola llamadaax.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