Cómo entrené una IA simple en Python para analizar velas (II)
En el artículo pasado (parte I) vimos cómo “desenredé” las estructuras básicas de supergana.com que es una de las IAs más famosas de trading para binarias. Hoy escribiré sobre como se construyen indicadores básicas a partir de las velas usando Python.
Vamos a generar un análisis cuantitativo de velas OHLC con Python.
Las velas japonesas contienen cuatro datos fundamentales del mercado:
- Open (apertura).
- High (máximo).
- Low (mínimo).
- Close (cierre).
Aunque parecen simples, estos cuatro valores permiten construir una gran cantidad de variables cuantitativas útiles para análisis estadístico, trading algorítmico y modelos de machine learning.
En este artículo construiremos un pipeline completo de análisis de velas usando Python.
Vamos con la preparación del entorno
Instalamos librerías necesarias.
pip install pandas numpy matplotlib scikit-learn
Librerías utilizadas:
Pandas nuevamente para la manipulación de datos.
NumPy para el cálculo numérico.
Matplotlib para visualización.
scikit-learn la usaremos para modelos de machine learning.
Ahora necesitamos cargar datos OHLC
Supongamos un archivo CSV con estructura:
time,open,high,low,close
Código:
df = pd.read_csv(“candles.csv”) print(df.head())import pandas as pd
print(df.describe())
Verificar datos faltantes:
print(df.isnull().sum())
Eliminar valores faltantes si existen:
df = df.dropna()
Ahora pasamos a un cálculo del rango de la vela
El rango total mide la volatilidad de cada vela.
Fórmula propuesta: range=high−low
Código:
df[“range”] = df[“high”] – df[“low”]
Ahora vamos con el cálculo del cuerpo de la vela
El cuerpo mide la presión compradora o vendedora.
Fórmula propuesta: body=close−open
Código:
df[“body”] = df[“close”] – df[“open”]
Magnitud absoluta:
df[“body_size”] = abs(df[“body”])
Vamos con la generación de sombras superior e inferior
Las sombras representan rechazo del precio.
Para las sombras superiores se propone esta fórmula: upper_shadow=high−max(open,close)
Para las sombras inferiores propongo esta fórmula: lower_shadow=min(open,close)−low
Código:
df[“lower_shadow”] = df[[“open”,”close”]].min(axis=1) – df[“low”]df[“upper_shadow”] = df[“high”] – df[[“open”,”close”]].max(axis=1)
Relación cuerpo/rango
Una métrica útil es qué porcentaje de la vela representa el cuerpo.
df[“body_ratio”] = df[“body_size”] / df[“range”]
Valores cercanos a 1 se considera una vela fuerte y 0 es simplemente indecisión.
Pasamos a la dirección de la vela
df[“direction”] = df[“body”].apply(
lambda x: 1 if x > 0 else -1
)
Opcionalmente:
df[“bullish”] = df[“close”] > df[“open”]
Configurando un cambio porcentual
Movimiento relativo de cada vela.
df[“pct_change”] = (df[“close”] – df[“open”]) / df[“open”]
Pasemos a cómo ver la volatilidad móvil
Usamos desviación estándar.
df[“volatility”] = df[“range”].rolling(window=20).std()
Promedio móvil del rango:
df[“range_mean”] = df[“range”].rolling(20).mean()
Detección de velas tipo Doji
Un Doji ocurre cuando el cuerpo es muy pequeño.
body = abs(row[“close”] – row[“open”]) total_range = row[“high”] – row[“low”] if total_range == 0: return body < total_range * 0.1def is_doji(row):
return False
Aplicación:
df[“doji”] = df.apply(is_doji, axis=1)
Opción para la detección de velas martillo
body = abs(row[“close”] – row[“open”]) lower_shadow = min(row[“open”],row[“close”]) – row[“low”] upper_shadow = row[“high”] – max(row[“open”],row[“close”]) if lower_shadow > body * 2 and upper_shadow < body: return Falsedef is_hammer(row):
return True
Aplicación:
df[“hammer”] = df.apply(is_hammer, axis=1)
Escudriñando la secuencias de velas
Muchas estrategias usan contexto de varias velas.
Creamos features retrasadas.
df[“prev_body”] = df[“body”].shift(1) df[“prev_range”] = df[“range”].shift(1)df[“prev_close”] = df[“close”].shift(1)
Tres velas anteriores:
df[f”close_lag_{i}”] = df[“close”].shift(i)for i in range(1,4):
Creando dataset para Machine Learning
Definimos variables predictoras.
“body”, ]features = [
“body_size”,
“upper_shadow”,
“lower_shadow”,
“range”,
“body_ratio”,
“pct_change”
Dataset:
Target: df[“target”] = (df[“close”].shift(-1) > df[“close”]).astype(int) y = df[“target”]X = df[features]
División de datos
X_train, X_test, y_train, y_test = train_test_split( X, )from sklearn.model_selection import train_test_split
y,
test_size=0.2,
shuffle=False
Entrenar modelo simple
model = RandomForestClassifier( n_estimators=200, ) model.fit(X_train,y_train)from sklearn.ensemble import RandomForestClassifier
max_depth=6,
random_state=42
Evaluar el modelo
pred = model.predict(X_test) accuracy = accuracy_score(y_test,pred) print(“Accuracy:”,accuracy)from sklearn.metrics import accuracy_score
Importancia de variables
Podemos ver qué características son más relevantes.
importance = model.feature_importances_ for i,v in enumerate(importance): print(features[i],v)import numpy as np
Visualización de resultados
plt.figure(figsize=(10,5)) plt.plot(df[“close”]) plt.title(“Serie de precios”) plt.show() Visualizar volatilidad: [wpbch language='html']plt.figure(figsize=(10,5)) plt.plot(df[“volatility”]) plt.title(“Volatilidad”) plt.show()import matplotlib.pyplot as plt
Pipeline completo
Podemos encapsular todo el proceso.
df[“range”] = df[“high”] – df[“low”] df[“body”] = df[“close”] – df[“open”] df[“body_size”] = abs(df[“body”]) df[“upper_shadow”] = df[“high”] – df[[“open”,”close”]].max(axis=1) df[“lower_shadow”] = df[[“open”,”close”]].min(axis=1) – df[“low”] df[“body_ratio”] = df[“body_size”] / df[“range”] df[“pct_change”] = (df[“close”] – df[“open”]) / df[“open”] return dfdef prepare_features(df):
Uso:
df = prepare_features(df)
Y si, todo artículo debería tener una conclusión
A partir de los cuatro valores básicos de una vela: apertura, cierre, máximo y mínimo, es posible construir docenas de variables cuantitativas que capturan información sobre volatilidad, momentum, presión compradora/vendedora y patrones de velas.
Estas variables pueden utilizarse para análisis estadístico, trading algorítmico y modelos de machine learning.
Agradecimientos para todo el equipo de supergana.com