Los gráficos de velas representan la evolución del precio de un activo: cada vela muestra el precio de apertura, el máximo, el mínimo y el de cierre de un periodo. La librería mplfinance, basada en matplotlib, los crea a partir de un data frame de pandas con un índice de fechas y las columnas Open, High, Low, Close y, opcionalmente, Volume.
mpf.plot
Pasa el data frame a mpf.plot y establece type = "candle".
import numpy as np
import pandas as pd
import mplfinance as mpf
rng = np.random.default_rng(21)
close = 50 + rng.normal(0, 1, 60).cumsum()
df = pd.DataFrame({"Open": close + rng.normal(0, 0.5, 60),
"Close": close,
"Volume": rng.integers(1000, 5000, 60)},
index = pd.bdate_range("2025-03-03", periods = 60))
df["High"] = df[["Open", "Close"]].max(axis = 1) + rng.uniform(0, 1, 60)
df["Low"] = df[["Open", "Close"]].min(axis = 1) - rng.uniform(0, 1, 60)
mpf.plot(df, type = "candle", figsize = (4, 4))

Barras OHLC y línea
Otros valores de type son "ohlc" (barras con marcas para los precios de apertura y cierre), "line" y "renko".
import numpy as np
import pandas as pd
import mplfinance as mpf
rng = np.random.default_rng(21)
close = 50 + rng.normal(0, 1, 60).cumsum()
df = pd.DataFrame({"Open": close + rng.normal(0, 0.5, 60),
"Close": close,
"Volume": rng.integers(1000, 5000, 60)},
index = pd.bdate_range("2025-03-03", periods = 60))
df["High"] = df[["Open", "Close"]].max(axis = 1) + rng.uniform(0, 1, 60)
df["Low"] = df[["Open", "Close"]].min(axis = 1) - rng.uniform(0, 1, 60)
mpf.plot(df, type = "ohlc", figsize = (4, 4))

Establece volume = True para agregar un panel con el volumen negociado debajo de las velas.
import numpy as np
import pandas as pd
import mplfinance as mpf
rng = np.random.default_rng(21)
close = 50 + rng.normal(0, 1, 60).cumsum()
df = pd.DataFrame({"Open": close + rng.normal(0, 0.5, 60),
"Close": close,
"Volume": rng.integers(1000, 5000, 60)},
index = pd.bdate_range("2025-03-03", periods = 60))
df["High"] = df[["Open", "Close"]].max(axis = 1) + rng.uniform(0, 1, 60)
df["Low"] = df[["Open", "Close"]].min(axis = 1) - rng.uniform(0, 1, 60)
mpf.plot(df, type = "candle", volume = True, figsize = (4, 4))

El argumento mav agrega medias móviles simples del número de periodos que indiques. Pasa una tupla para agregar varias.
import numpy as np
import pandas as pd
import mplfinance as mpf
rng = np.random.default_rng(21)
close = 50 + rng.normal(0, 1, 60).cumsum()
df = pd.DataFrame({"Open": close + rng.normal(0, 0.5, 60),
"Close": close,
"Volume": rng.integers(1000, 5000, 60)},
index = pd.bdate_range("2025-03-03", periods = 60))
df["High"] = df[["Open", "Close"]].max(axis = 1) + rng.uniform(0, 1, 60)
df["Low"] = df[["Open", "Close"]].min(axis = 1) - rng.uniform(0, 1, 60)
mpf.plot(df, type = "candle", mav = (5, 20), volume = True,
style = "yahoo", figsize = (4, 4))

mplfinance incluye varios estilos, como "yahoo", "charles", "nightclouds" o "binance" (puedes verlos todos con mpf.available_styles()). Para elegir los colores de las velas crea un estilo con make_marketcolors y make_mpf_style.
import numpy as np
import pandas as pd
import mplfinance as mpf
rng = np.random.default_rng(21)
close = 50 + rng.normal(0, 1, 60).cumsum()
df = pd.DataFrame({"Open": close + rng.normal(0, 0.5, 60),
"Close": close,
"Volume": rng.integers(1000, 5000, 60)},
index = pd.bdate_range("2025-03-03", periods = 60))
df["High"] = df[["Open", "Close"]].max(axis = 1) + rng.uniform(0, 1, 60)
df["Low"] = df[["Open", "Close"]].min(axis = 1) - rng.uniform(0, 1, 60)
colors = mpf.make_marketcolors(up = "#2A9D8F", down = "#E76F51", inherit = True)
style = mpf.make_mpf_style(marketcolors = colors, gridstyle = ":")
mpf.plot(df, type = "candle", style = style, figsize = (4, 4))

Título y etiquetas
import numpy as np
import pandas as pd
import mplfinance as mpf
rng = np.random.default_rng(21)
close = 50 + rng.normal(0, 1, 60).cumsum()
df = pd.DataFrame({"Open": close + rng.normal(0, 0.5, 60),
"Close": close,
"Volume": rng.integers(1000, 5000, 60)},
index = pd.bdate_range("2025-03-03", periods = 60))
df["High"] = df[["Open", "Close"]].max(axis = 1) + rng.uniform(0, 1, 60)
df["Low"] = df[["Open", "Close"]].min(axis = 1) - rng.uniform(0, 1, 60)
mpf.plot(df, type = "candle", style = "nightclouds", figsize = (4, 4),
title = "Precio de la acción", ylabel = "Precio ($)")

Para crear un gráfico de velas interactivo consulta el tutorial sobre el gráfico de velas en plotly.
También te puede interesar