Machine Translated by Google
centile_67 = [Link](df[ f "target_var_ {n}
" ].iloc[:split].dropna().values, 67 )
# Variable ficticia
df[ "target_dummy" ] =
0 [Link][df[ f "target_var_ {n} " ]>centile_67, "target_dummy" ]
=1
[Link][df[ f "target_var_ {n} " ]<centile_33, "target_dummy" ]
= -1
Resumen
Los datos de la OHLCV son como un coche desmontado, por lo que es
necesario transformarlos.
La ingeniería de características ayuda al algoritmo a comprender mejor la
relación entre los datos (es como ensamblar el automóvil)
El etiquetado de destino es la variable que queremos predecir (es a dónde
queremos ir)
Machine Translated by Google
Machine Translated by Google
Capítulo 11: Máquina de vectores de soporte
(MVS)
Este capítulo analiza uno de los algoritmos más utilizados en finanzas, la
máquina de vectores de soporte. Es ventajoso en finanzas porque no necesita
muchos datos para entrenar. Antes de aprender SVM, haremos un punto
sobre el preprocesamiento de datos. Luego, aprenderemos a usar un regresor
de máquina de vectores de soporte (SVR) y un clasificador de máquina de
vectores de soporte (SVC).
11.1. Preparación de datos
En esta sección, prepararemos los datos para nuestra SVM [13] y
recapitularemos lo que ya sabemos sobre la preparación de datos. Luego
profundizaremos en el concepto explicando la estandarización de datos.
11.1.1. Ingeniería de características
En esta sección, recapitularemos rápidamente la preparación de datos. De
hecho, haremos lo mismo que en los capítulos anteriores. Entonces,
necesitamos definir conjuntos de entrenamiento y conjuntos de pruebas. Además,
mejoraremos las prestaciones de nuestro modelo. Para hacerlo, agregaremos
algunos indicadores técnicos. No explicamos los indicadores técnicos que no
usaremos en el libro. Si desea encontrar alguna documentación al respecto,
podemos encontrarla en Internet y en libros. Hacemos un recordatorio de
ingeniería de características aquí para comprender realmente cómo incorporarlo
en nuestro proyecto.
Machine Translated by Google
La ingeniería de características ayuda al algoritmo a encontrar el mejor patrón
en los datos. Por ejemplo, el precio de las acciones si tiene un activo con un
precio entre 50$ y 5000$, los parámetros del modelo no se pueden ajustar
correctamente. En lugar de esto, utilice la variación porcentual que convierte
todos los activos en el mismo rango. Es muy útil para el algoritmo.
Para crear indicadores técnicos, hay dos formas. Primero, podemos crear por nosotros mismos.
También podemos utilizar la biblioteca de análisis técnico de Python (ta). En esta parte,
crearemos los indicadores necesarios por nosotros mismos.
Para este ejemplo, hemos creado una media de rendimientos y volatilidad de rendimientos. Estos
indicadores no se pueden encontrar en la biblioteca ta, por lo que debemos calcularlos nosotros
mismos. Además, hemos puesto dos plazos en cada indicador.
Código 11.1: Ingeniería de características #
Ingeniería de características
df[ "devuelve t-1" ] = df[[ "devuelve" ]].shift( 1 ) 1
# Media de retornos
df[ "media devuelve 15" ] = df[[ "devuelve" ]].rolling( 15 ).mean().shift( 1 )
df[ "media devuelve 60" ] = df[[ "devuelve" ]].rolling ( 60 ).media().desplazamiento( 1 )
# Volatilidad de los
rendimientos df[ "volatilidad devuelve 15" ] =
df[[ "devoluciones" ]].rolling( 15 ).std() .shift( 1 ) df[ "volatilidad devuelve
60" ] = df[[ "devoluciones" ]].rodando( 60 ).std() .shift( 1 )
1 Se espera como este paso porque lo hemos visto muchas veces,
pero el cambio a la característica
Machine Translated by Google
columnas nos permite poner la X y la y del
mismo día en la misma fila.
No olvide agregar un cambio a estos indicadores para no
interferir en los datos. Veamos por qué en la figura 11.1
Figura 11.1: Cómo evitar interferencias en los datos
Esta figura muestra que si no cambiamos los datos, tendremos
interferencias porque predecimos el día 15 cuando ya tenemos el día
15 en las funciones. No puede ser exacto y podemos perder mucho
dinero si cometemos este error.
11.1.2. Estandarización
Esta subsección explicará el concepto de estandarización. Vemos
esto en el capítulo SVM porque es un algoritmo geométrico y es
necesario estandarizar los datos para estos algoritmos. Aún así,
podemos aplicar este método a otro algoritmo.
Machine Translated by Google
La estandarización permite hacer el cálculo más rápido. Por lo
tanto, es interesante para el algoritmo que demanda muchos recursos.
A veces, como con este conjunto de datos, los datos no están a la misma escala.
Por ejemplo, podemos tener una volatilidad del 60% con una rentabilidad del 1,75%.
Entonces, el algoritmo tiene muchas dificultades para trabajar con eso. Necesitamos
estandarizar los datos para ponerlos en la misma escala. Veamos gráficamente por
qué necesitamos estandarizar los datos de la figura 11.2.
Figura 11.2: ¿Cómo funciona la estandarización?
Esta figura muestra que es difícil para nosotros entender el patrón entre las dos
líneas antes de la estandarización. También es para el algoritmo. Por lo tanto,
necesitamos estandarizar los datos para ayudarnos a comprenderlos mejor.
Ahora, veamos la fórmula para estandarizar los datos y estandarizar los datos
usando Python.
Machine Translated by Google
¿Dónde está el valor estandarizado, es el valor de la observación,
es la media del vector y la volatilidad del vector .
Código 11.2: Estandarizar los datos #
Importar la clase de [Link]
import StandardScaler
# Inicializar la clase
sc = StandardScaler()
# Estandarizar los
datos X_train_scaled = sc.fit_transform(X_train)
X_test_scaled = [Link](X_test)
En cuanto a los otros algoritmos, necesitamos encajar en el
conjunto de trenes solo porque no podemos conocer la media y la
desviación estándar del conjunto de prueba en la vida real.
11.2. Clasificador de máquina de vectores de soporte (SVC)
Esta sección explicará cómo funciona un SVC, luego cómo crear un
SVC usando Python y cómo hacer predicciones con el SVC para crear una
estrategia comercial.
11.2.1. Intuición sobre cómo funciona un SVC
Machine Translated by Google
En esta parte, veremos la intuición detrás del clasificador de máquinas de
vectores de soporte.
Para hacerlo, estamos comenzando con un pequeño gráfico para entender lo que
quiere hacer el SVC.
Figura 11.3: Funcionamiento de un SVC
En esta figura, podemos ver la pregunta a la que responde el SVC: " ¿Cómo se
pueden separar de forma óptima los grupos de puntos?".
Usamos márgenes para encontrar la línea óptima entre los dos grupos.
Estos márgenes quieren maximizar la distancia entre los dos grupos. Luego,
tomaremos el medio de los dos márgenes para encontrar la delimitación de los
dos grupos. Además, veremos que los puntos en los márgenes se llaman
soportes, y estos puntos son los únicos puntos importantes en el algoritmo. Si
eliminamos todos los demás puntos, el rendimiento del algoritmo será el mismo.
Figura 11.4: Optimizar la distancia
Machine Translated by Google
En esta figura podemos ver el funcionamiento de un SVC y los soportes.
El problema es que si un cuadrado está en el grupo circular, el algoritmo no
puede ejecutarse. Es porque el algoritmo tiene márgenes rígidos.
Afortunadamente, es posible crear un SVC con márgenes flexibles para evitar
este problema.
Con scikit-learn, es posible gestionar la invasión de márgenes.
Supongamos que ponemos una C con un valor alto; no permitiremos que
el modelo tenga mucha invasión de márgenes. Sin embargo, cuanto más
bajo es el valor, más significativa es la invasión del margen.
Ahora hablemos del núcleo del modelo. El núcleo es la forma en que se
entrena nuestro algoritmo. Hay muchas formas de optimizar un SVC, pero la
más utilizada es el kernel gaussiano o el kernel lineal en finanzas.
Hay otros kernels disponibles en scikit-learn como un kernel sigmoide. Sin
embargo, solo veremos el lineal y el gaussiano. Una línea como la de la
figura 11.4 esquematiza lo lineal, pero la gaussiana puede mantener un
patrón no lineal como el de la figura 11.5.
Machine Translated by Google
Figura 11.5: Esquematización del núcleo gaussiano
En esta figura podemos ver el funcionamiento de un SVC usando un kernel
gaussiano.
11.2.2. Cómo crear un SVC usando Python
Calcularemos un clasificador de máquinas de vectores de soporte (SVC) en
esta parte usando Python. Es fácil porque sigue la misma sintaxis que la
regresión logística. Necesitamos cambiar la función para usar la función SVC
de scikit-learn.
Código 11.2: implementación de SVC #
Importar la clase desde [Link] import
SVC
# Inicializar la clase
svc = SVC()
Machine Translated by Google
# Ajustar el
modelo [Link](X_train_scaled, y_train_cla)
Usaremos un SVC con un kernel RBF, el kernel gaussiano
en scikit-learn.
11.2.3. Predicciones y backtest
Como podemos ver en la figura 11.6, los rendimientos de la estrategia son
terribles porque tenemos un drawdown del 67% (conferir el código) y una
pérdida del 60%. Entonces, si estamos buscando un algoritmo para poner en
producción, no necesitamos profundizar más. Sería útil si exploráramos otra
combinación entre datos, modelo y estrategia.
Figura 11.6: Backtest de una estrategia usando las predicciones SVC
Beta: 0,248 Alfa: -21,69 % Sharpe: -0,602 Sortino: -0,684
-------------------------------------------------- ---------------------------
VaR: 87,9 % cVaR: 98,54 % VaR/cVaR: 1. Disminución de 121: 67,1 %
Machine Translated by Google
El crecimiento constante del drawdown es lo peor que le puede pasar a
una estrategia. Por lo tanto, es una muy mala estrategia.
11.3. Regresor de máquina de vectores de soporte (SVR)
En esta sección, explicaremos la intuición de Support Vector Machine
Regressor (SVR), luego crearemos el modelo y haremos una estrategia
comercial utilizando la predicción de nuestro SVR.
11.3.1. Intuición sobre cómo funciona un SVR
Será fácil de entender porque el SVR sigue casi el mismo proceso que el
SVC. Tenemos que tomar el problema de otra manera. En lugar de maximizar
la distancia entre dos grupos, el SVR intenta maximizar el número de
observaciones entre los márgenes o minimizar el número de observaciones
fuera de los márgenes.
Veamos un ejemplo en la figura 11.7.
Machine Translated by Google
Figura 11.7: Intuición sobre la RVS
En esta figura podemos ver la intuición de funcionamiento del SVR. El
parámetro más útil es el épsilon porque gestiona la ruta del SVR.
El parámetro epsilon es la tolerancia del modelo. Se puede cambiar
usando el hiperparámetro de la función scikit-learn. Muchas funciones
nos permiten encontrar la mejor combinación entre los hiperparámetros
de los modelos (veremos una técnica en el siguiente capítulo) pero no
olvides que cuanto más optimices el algoritmo para que se ajuste a
nuestros datos, más aumenta el riesgo de sobreajuste.
11.3.2. Cómo crear un SVR usando Python
En esta parte, queremos crear un modelo SVR usando scikit-learn. Para
hacerlo, usaremos la clase SVR de scikit-learn.
Código 11.3: implementación de SVR #
Importar la clase desde [Link] import
SVR
# Inicializar la clase
Machine Translated by Google
svr = RVS()
# Ajustar el
modelo [Link](X_train_scaled, y_train_reg)
11.3.3. Predicciones y backtest
Podemos mencionar que las características son las mismas para ambos. En
comparación, el rendimiento de los modelos es muy diferente. Veamos la figura
11.8. Es por el etiquetado del objetivo (esta vez, el regresor es mejor).
Como podemos ver, el modelo regresor gana un 35% al mismo tiempo que
el modelo clasificador pierde el 60% del capital inicial. Sin embargo, ¿por qué
casi el mismo algoritmo tiene algunas diferencias significativas? La verdad es
que no podemos decir por qué. Mientras que, para evitar tener algunos algoritmos
con un rendimiento pésimo como el modelo SVC, podemos hacer una prueba
retrospectiva profunda para encontrar los mejores algoritmos que se pueden usar
para minimizar el riesgo de perder dinero. También podemos hacer un portafolio
de estrategias para reducir el riesgo y tener retornos más estables.
Figura 11.8: Retorno acumulado de la estrategia usando las
predicciones SVR
Beta: 0,787 Alfa: 2,15 % Sharpe: 0,455 Sortino: 0,584
-------------------------------------------------- ---------------------------
VaR: 56,1 % cVaR: 66,0 % VaR/cVaR: 1,176 reducción: 30,32 %
Machine Translated by Google
La estrategia tiene un ratio de Sharpe muy bueno porque empieza a estar
razonablemente cerca de 0,5 (sharp=0,45). No está significativamente correlacionado
con el mercado (beta=0.787). Sin embargo, muchas fluctuaciones en los
rendimientos acumulados implican un riesgo considerable de pérdidas (cVaR =
66%). Es una excelente estrategia para una cartera de estrategias para disminuir el
riesgo porque ahora esta estrategia es demasiado arriesgada, teniendo en cuenta
el rendimiento superior del mercado.
Machine Translated by Google
Resumen
La estandarización es obligatoria para los SVM porque se basan en un
proceso geométrico.
El clasificador de máquinas de vectores de soporte busca optimizar la
distancia entre los dos grupos.
Podemos cambiar el valor de la invasión del margen usando los
parámetros C cuando trabajamos con scikit-learn.
El regresor de la máquina de vectores de soporte intenta crear una ruta
con el máximo de observaciones.
Podemos cambiar el ancho de la ruta usando el parámetro epsilon en
scikit learn.
El kernel más utilizado en finanzas tanto para SVC como para SVR es el
kernel lineal y el gaussiano.
Aplicación Live Trading and Screener
Este código se basa en la clase creada en el anexo: MetaTrader
Código 11.4: Comercio de aplicaciones / Screener para SVR
de importación MT5 *
importar numpy como np
importar pandas como
pd importar advertencias
[Link]( "ignorar" ) de
sklearn.linear_model importar LogisticRegression
tiempo de
importación
importar pickle desde joblib import dump, load
Machine Translated by Google
importar sistema operativo
= ""
sendero # Ex:
C:/Desktop/Python_for_finance_and_algorithmic_trading/
CapítuloN/
def create_model_weights ( símbolo ):
""" Pesos para la regresión lineal sobre el cambio porcentual"""
# Importar los datos
datos = MT5.get_data(símbolo, 3500 )[[ "cerrar" ]].pct_change( 1 )
# Crear nueva variable
datos[ "cerrar t-1" ] = datos[[ "cerrar" ]].shift( 1 )
# Dividir los datos
data = [Link]()
split = int( 0.80 * len (datos))
# Creación de conjuntos de trenes
Tren_X = datos[[ "cerrar t-1" ]].iloc[:dividir]
tren_y = np. ronda (datos[[ "cerrar" ]].iloc[:dividir]+ 0.5 )
# Crear el modelo alg
= LogisticRegression()
# Ajustar el
modelo [Link](X_train, y_train)
# Guardar el modelo
alg_var = [Link](alg)
alg_pickel = [Link](alg_var)
dump(alg_pickel ,[Link](ruta,f "Modelos/ {símbolo} .joblib" ))
def log_reg_sig ( símbolo ):
Función """ para predecir el valor de mañana usando
modelo ARIMA"""
Machine Translated by Google
# Crea los pesos si no hay en la carpeta
prueba :
alg = load([Link](path, f "Modelos/ {símbolo} .joblib" ))
excepto :
create_model_weights(símbolo)
alg = load([Link](ruta, f "Modelos/ {símbolo} .joblib" ))
# Tomar el último porcentaje de datos de
cambio = MT5.get_data(símbolo, 3500 )
[[ "cerrar" ]].pct_change( 1 ) datos[ "cerrar t-1" ] = datos[[ "cerrar" ]].shift( 1 )
X = datos[ "cerrar t-1" ].iloc[ -1 ].reshape( -1 , 1)
# Encuentra la
señal predicción = [Link](X)
predicción = [Link](prediction== 0 , -1 , 1)
comprar = predicción[ 0 ][ 0 ] > 0 vender =
no comprar
volver comprar, vender
# Verdadero = Comercio en vivo y Falso = Screener en
vivo = Verdadero
if live:
current_account_info = mt5.account_info() print
( "-------------------------------------- ----------------------" ) print ( "Fecha: " ,
[Link]().strftime(
"Saldo: "%Y-%m-%d
{info_cuenta_actual.saldo}
%H :%M:%S" )) USD,
print ( f
\t"
f "Patrimonio: {info_cuenta_actual.equity} USD, \t" f
"Beneficio: {info_cuenta_actual.beneficio} USD" ) print
( "--------------------- --------------------------------------------" )
info_pedido = {
Machine Translated by Google
"Euro vs dólar estadounidense" : [ "EURUSD" , 0.01 ]
} inicio = [Link]().strftime( "%H:%M:%S" ) #"23:59:59"
mientras que es cierto :
# Verificación para el lanzamiento
si [Link]().weekday() no está en ( 5 , 6 ):
es_hora = [Link]().strftime( "%H:%M:%S" ) ==
comienzo
más :
es_tiempo = Falso
# Inicie el algoritmo si
es_tiempo:
# Abra las operaciones
de activos en info_order.keys():
# Inicializar el símbolo de
entrada = info_pedido[activo][ 0 ] lote =
info_pedido[activo][ 1 ]
# Crear las señales
comprar, vender = log_reg_sig(símbolo)
# Ejecutar el algoritmo
si vivo:
[Link](símbolo, comprar, vender, lote)
más :
print ( f "Símbolo: {símbolo} \t" f "Comprar:
{comprar} \t" f "Vender: {vender} " )
[Link]( 1 )
El parámetro en vivo establece el modo de comercio en vivo
(en vivo = Verdadero) o el modo de filtro (en vivo = Falso).
Machine Translated by Google
Capítulo 12: Métodos de conjunto y
árbol de decisión
En este capítulo, veremos muchos algoritmos de aprendizaje automático.
Primero, veremos el árbol de decisiones, luego el bosque aleatorio y algunos otros
métodos de conjunto que son fundamentales en las finanzas. Todos los algoritmos de
este capítulo se aplicarán al precio de las acciones de Google.
12.1. Árbol de decisión
En esta sección, estudiaremos el algoritmo del árbol de decisión. Este algoritmo de
aprendizaje automático estadístico es más útil en finanzas porque comprende la
relación no lineal entre los datos.
12.1.1. Clasificador de árboles de decisión
Comenzamos con el clasificador del árbol de decisión [14] en esta subsección. Antes
de codificar algo, explicaremos cómo funciona un clasificador de árboles de decisión.
Matemáticamente, cuando tenemos un espacio con grupos de puntos, el árbol de
decisión cortará el espacio con hiperplanos para separar los grupos. Un hiperplano es
una línea en un espacio 2d, así que si no sabemos lo que esto significa, recuerda que en
nuestro ejemplo es una línea.
Además, cada hiperplano es ortogonal a los demás. ¿Qué significa? En nuestro
caso, cada hiperplano es perpendicular a los demás. Es esencial saber eso para
entender el comportamiento del algoritmo. En la siguiente figura veremos cómo
funciona un árbol de decisión de una forma más sencilla.
Machine Translated by Google
Figura 12.1: Cómo funciona gráficamente un árbol de decisión
En esta figura podemos ver los diferentes hiperplanos del árbol de decisión.
En este ejemplo, hay tres hiperplanos, lo que significa que la profundidad de este árbol
de decisión es 3.
Esquematizaremos el funcionamiento de un árbol de decisión para asegurarnos de
haber entendido lo que hace un clasificador de árbol de decisión. El árbol de decisión
trabaja con condiciones, veamos en la figura 10.2.
Figura 12.2: Clasificador de árboles de decisión
Machine Translated by Google
Además de eso, es un modelo muy interpretable, lo cual es interesante en finanzas.
Los árboles de decisión no necesitan normalización para tener buenos resultados.
Además, es un algoritmo perfecto cuando tiene muchas variables ficticias en las
características.
Ahora, veremos cómo implementar un clasificador de árboles
de decisión con Python. Para hacerlo, importamos la clase
DecisionTreeClassifier de scikit-learn, y usaremos la misma
sintaxis que para los algoritmos anteriores.
Código 12.1: Clasificador de árboles de decisión
# Importar la clase de [Link] import
DecisionTreeClassifier
# Inicializar la clase
trc = Clasificación del árbol de decisión (profundidad máxima = 6 )
# Ajustar el
modelo [Link](X_train, y_train_cla)
El hiperparámetro max_ depth se establece en 6. Sin embargo,
es una elección aleatoria. Es simplemente no dejar que el árbol se
hunda demasiado porque no es bueno; veremos más adelante por
qué. Veremos cómo encontrar la mejor profundidad en la siguiente parte.
Luego, tenemos el modelo, podemos hacer predicciones y probar la estrategia.
Como se muestra en la figura 12.3, tenemos un rendimiento excelente
utilizando la profundidad de 6 porque tenemos casi el 30 % de los rendimientos anuales.
Mientras que, cuando no precisamos la profundidad, el algoritmo puede
profundizar tanto como quiera, y no es bueno; podemos ver que los rendimientos
del mismo modelo pero sin precisar la profundidad es -80% en el período.
Machine Translated by Google
Figura 12.3: Backtest en función de la profundidad máxima
Profundidad_máx
= 6 Beta: 1,056 Alfa: 12,44 % Sharpe: 0,931 Sortino: 1,227
-------------------------------------------------- ---------------------------
VaR: 41,76 % cVaR: 52,03 % VaR/cVaR: 1,246 reducción: 30,79 %
Machine Translated by Google
Depth_max = Ninguno
Beta: -0,034 Alfa: -20,95 % Sharpe: -0,715. Sortino: -0.906
-------------------------------------------------- ---------------------------
VaR: 91,56 % cVaR: 101,59 % VaR/cVaR: 1,11 reducción: 57,31 %
En esta figura, podemos ver que la profundidad del árbol de decisión juega
un papel crucial. De hecho, la diferencia de retorno entre las dos estrategias es
de casi 160% en el período. Esto resalta el problema de sobreajuste cuando
dejamos que el algoritmo no tenga restricciones de profundidad.
Machine Translated by Google
Los hiperparámetros más críticos en el árbol de decisión son la
profundidad del árbol que viene dada por el hiperparámetro max_
depth en scikit-learn.
12.1.2. Regresor del árbol de decisión
Esta parte explicará cómo funciona un regresor de árbol de decisión y cómo
implementar un regresor de árbol de decisión usando Python y probar la estrategia.
El regresor del árbol de decisión sigue casi el mismo proceso que el clasificador del
árbol de decisión. Entonces, veamos esto en un árbol simple en la figura 12.4.
Figura 12.4: Árbol de decisión regresor
Para implementar un regresor de árbol de decisión, usaremos la misma sintaxis que el
clasificador de árbol de decisión.
Código 12.2: Árbol de decisión regresor
Machine Translated by Google
# Importar la clase
desde [Link] import DecisionTreeClassifier
# Inicializar la clase
trc = Clasificación del árbol de decisión (profundidad máxima = 6 )
# Ajustar el
modelo [Link](X_train, y_train_cla)
Podemos ver los resultados de la estrategia en la figura 12.5, y como podemos ver con
la restricción sobre la profundidad del algoritmo, también da buenos resultados.
Figura 12.5: predicción de acciones de Google basada en la estrategia de backtest
Beta: 0,243 Alfa: 18,27 % Sharpe: 0,728 Sortino: 0,96
-------------------------------------------------- ---------------------------
VaR: 47,95 % cVaR: 57,81 % VaR/cVaR: 1,206 reducción: 25,35 %
Machine Translated by Google
Es un backtest muy bueno. Tenemos un índice de Sharpe de 0,72 y un alfa de
18,27 %, lo que significa que superamos al mercado. Sin embargo, tenemos una
reducción considerable. La mejor manera de reducir el riesgo de una estrategia es
combinarla con las demás, pero lo veremos más adelante.
12.1.3. Optimizar los hiperparámetros
En la última parte, hemos dicho que dejar la profundidad máxima sin restricciones
no es una excelente opción, pero no tenemos que decir cómo encontrar la
óptima.
Para encontrar el mejor valor para el parámetro max_ depth, usaremos el
algoritmo GridShearchCV de scikit-learn. Es un algoritmo sencillo. Simplemente
prueba todas las posibilidades y toma lo mejor.
Código 12.3: Grid Search CV #
Importar la clase de
sklearn.model_selection import GridSearchCV
# Crear el modelo
dtr = DecisionTreeRegressor()
Machine Translated by Google
# Elija una lista de parámetros
parámetro = { "profundidad_máxima" : [ 3 , 6 , 15 ] } 1
# Crear la búsqueda en cuadrícula
modelo = GridSearchCV(dtr, param_grid=param, cv= 3 ,)
# Entrena el modelo
[Link](X_train.values, y_train_reg.values)
# Imprime el mejor
modelo model.best_estimator_
Salir (mejor modelo):
DecisionTreeRegressor(ccp_alpha=0.0, criterio='mse', max_ depth=3,
max_features=Ninguno, max_leaf_nodes=Ninguno, min_impurity_decrease=0.0,
min_impurity_split=Ninguno, min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, presort='obsoleto',random_state=Ninguno, splitter='mejor')
1 Crear un diccionario que contenga todas las variables
que queremos probar con los diferentes valores.
Aquí, solo queremos probar el modelo de prueba
dependiendo de la profundidad máxima del árbol (3, 6 o 15).
Como podemos ver, el mejor modelo es una longitud de 3. ¿Es el mejor
modelo en qué criterio? Como no tenemos que especificar, un criterio es el
criterio de entrenamiento del algoritmo que utilizará el MSE. Lo maravilloso
es que podemos personalizar la función para encontrar el mejor algoritmo
usando nuestro criterio. Crearemos algunos criterios para explicar esto.
Aquí se propone la suma de los rendimientos y el ratio de Sharpe, pero
podemos crear el ratio que queramos.
Código 12.4: Crear nuevas métricas # Importar la
función desde [Link] import make_scorer
# DEVOLUCIONES
# Crear criterio de devolución
def devuelve ( y , y_pred ) : 1
volver np. suma ([Link](y_pred) * y)
Machine Translated by Google
# Transformar el criterio en una métrica
devuelve_metric = make_scorer(devuelve, mayor_es_mejor= Verdadero ) 2
# SHARPE
# Crear criterio sharpe def
sharpe ( y , y_pred ): r =
[Link](y_pred) * y return
[Link](r) / [Link](r ) 3
# Transformar el criterio en una métrica
sharpe_metric = make_scorer(sharp, mayor_es_mejor= Verdadero )
1 La optimización función por de criterio toma solo
de hiperparámetros
dos parámetros de entrada: el objetivo real y el objetivo
predicho.
2 El parámetro mayor_es_mejor resalta el algoritmo si
queremos maximizar o minimizar la métrica.
3 No es necesario anualizar el índice de Sharpe aquí
porque la relación de tamaño no importa.
Así, añadimos menos cosas posibles para optimizar el
tiempo de cómputo.
La función make_score nos permite transformar una función
simple en una métrica compatible con los algoritmos de
aprendizaje de scikit.
La función make_score nos permite transformar una función simple en una
métrica compatible con los algoritmos de scikit-learn.
Con return_metric y sharpe_metric, tenemos una profundidad óptima de 3.
Significa que con las 3 formas, tenemos una profundidad óptima de tres.
Entonces, podemos decir que en el conjunto de entrenamiento, la mejor profundidad
para el algoritmo es 3.
Machine Translated by Google
12.2. Bosque aleatorio
Esta sección trata sobre el bosque aleatorio. Primero, veremos cómo calcular un
clasificador de bosque aleatorio, luego un regresor de bosque aleatorio y cómo
optimizar los hiperparámetros de un bosque aleatorio.
12.2.1. Clasificador de bosque aleatorio
En esta parte, aprenderemos cómo implementar un clasificador de bosque aleatorio.
El bosque aleatorio es el primer método de conjunto que aprenderemos. Un método
de conjunto es un método que reagrupa algoritmos para tener una mejor predicción.
Naturalmente, como su nombre lo dice, el bosque aleatorio es un conjunto de árboles
de decisión. De hecho, el bosque aleatorio es solo un algoritmo que combina las
predicciones de muchos árboles de decisión para tener mejores predicciones.
No vamos a profundizar en la explicación del bosque aleatorio porque la intuición
es fácil de entender. Sin embargo, si queremos profundizar, necesitamos muchas
matemáticas, lo cual es irrelevante para este libro. Veamos el código de un
clasificador de bosque aleatorio.
Código 12.5: Clasificador de bosque aleatorio #
Importar la clase de [Link] import
RandomForestClassifier
# Inicializar la clase
lr = RandomForestClassifier()
# Ajustar el
modelo [Link](X_train, y_train_cla)
Machine Translated by Google
Tenga en cuenta que no hay ningún hiperparámetro
personalizado aquí para mostrarle la diferencia en la figura 10.6.
Resaltaremos el problema con el bosque aleatorio (igual que un árbol de decisión)
cuando no se precisa la profundidad y la cantidad de estimadores (solo para el bosque
aleatorio). Hay un gran sobreajuste, como podemos ver en la figura 12.6.
Figura 12.6: Resalte el sobreajuste
Prueba retrospectiva del conjunto de trenes
Beta: -0.001 Alfa: 315.67 % Sharpe: 14.104 Sortino: nan
-------------------------------------------------- ---------------------------
VaR: -263,64 % cVaR: -256,21 % VaR/cVaR: 0,972disminución: -0%
Machine Translated by Google
Prueba retrospectiva del conjunto
Beta: -0,018 Alfa: -6,45 Sharpe: -0,224 Sortino: -0,28
-------------------------------------------------- --------------------------
VaR: 76,65 % cVaR: 86,33 % VaR/cVaR: 1,126 reducción: 61,75 %
Machine Translated by Google
Como podemos ver en la pantalla, hay sobreajuste porque, en el conjunto de trenes
(los datos que ya conoce el algoritmo), ganamos un 350% anual con una reducción del
0%, en lugar de que el conjunto de prueba pierda dinero.
12.2.2. Regresor de bosque aleatorio
En esta parte, hablaremos sobre los regresores de bosques aleatorios. Naturalmente,
un regresor de bosque aleatorio es un conjunto de regresores de árboles de decisión.
No explicamos las mismas cosas para evitar ser aburrido para este algoritmo. Podemos
copiar exactamente lo que decimos para el clasificador de bosque aleatorio en el regresor
de bosque aleatorio. Entonces, veamos cómo implementarlo y resaltemos el problema de
sobreajuste de estos algoritmos nuevamente.
Código 12.6: Regresor de bosque aleatorio #
Importar la clase de [Link] import
RandomForestRegressor
# Inicializar la clase
lr = RandomForestRegressor()
# Ajustar el
modelo [Link](X_train, y_train_reg)
Machine Translated by Google
Figura 12.7: Destacar el sobreajuste en el bosque aleatorio
Beta: 0,511 Alfa: 9,76 % Sharpe: 0,574 Sortino: 0,777
-------------------------------------------------- ---------------------------
VaR: 52,51 % cVaR: 62,26 % VaR/cVaR: 1,186 reducción: 43,26 %
Es un buen desempeño, pero hay una reducción significativa durante un
período muy largo. Significa que la estrategia es peligrosa.
Machine Translated by Google
12.2.3. Optimizar los hiperparámetros
En esta parte, optimizaremos los hiperparámetros para el árbol de decisión.
Para eso, usaremos la métrica de Sharpe utilizada en la parte 12.1.3.
Código 12.7: Optimizar los hiperparámetros # Importar la clase
de sklearn.model_selection import GridSearchCV
# Crear el modelo dtr
= RandomForestRegressor()
# Elija una lista de parámetros
param = { "max_depth" : [ 3 , 6 , 15 ], "n_estimadores" : [ 50 , 100
, 150 ]}
# Importa la función
desde [Link] import make_scorer
# SHARPE
# Crear criterio sharpe def
sharpe ( y , y_pred ): r =
[Link](y_pred) * y return
[Link](r) / [Link](r)
# Transformar el criterio en una métrica
sharpe_metric = make_scorer(sharp, mayor_es_mejor= Verdadero )
modelo = GridSearchCV(dtr, param_grid=param,
score=sharpe_metric, cv= 3 )
[Link](X_tren.valores, y_tren_reg.valores)
modelo.mejor_estimador_
Los parámetros que influyen en un bosque aleatorio son el
número de árboles y la profundidad de los árboles.
Machine Translated by Google
En la siguiente figura, podemos ver que el ajuste de los hiperparámetros impacta
considerablemente en el rendimiento. De hecho, esto nos permite tener una curva
más suave y un mejor indicador de backtest.
Figura 12.8: Retornos con y sin afinación
Sin modelo de afinación
Beta: -0.056 Alpha: 24.09 % Sharpe: 0.776 Sortino: 1.143
-------------------------------------------------- ---------------------------
VaR: 46,72 % cVaR: 56,63 % VaR/cVaR: 1.212 reducción: 33,43 %
Machine Translated by Google
Con modelo de sintonización
Beta: 0,553 Alfa: 18,25 % Sharpe: 0,879 Sortino: 1,194
-------------------------------------------------- ---------------------------
VaR: 44,05 % cVaR: 54,37 % VaR/cVaR: 1.234disminución: 29,33 %
Desafortunadamente, para el ejemplo, el modelo sin ajuste no se sobreajusta porque tiene
rendimientos razonables. Sin embargo, el modelo con
Machine Translated by Google
el ajuste es mejor porque tiene menos reducción, una relación de Sharpe más alta y
menos cVaR.
12.3. Métodos de conjunto
En esta sección, aprenderemos algunos métodos de conjunto [15] . Primero,
veremos el conjunto más simple, los métodos de votación, embolsado y apilamiento.
12.3.1. método de votación
El método de votación es el método más simple del método de conjunto.
Veamos cómo funciona en la figura 12.9.
Como podemos ver que los algoritmos son bien diferentes, la predicción es mejor
cuando agregamos su predicción. Sin embargo, necesitamos algunos supuestos matemáticos
como la independencia del estimador. Pero es casi imposible tenerlo en la vida real porque
los algoritmos se entrenan con los mismos datos.
Figura 12.9: Clasificador de votaciones
Machine Translated by Google
Como podemos ver en la figura, la agregación de los estimadores es mejor
que los estimadores solos.
Cuando trabajamos con estimadores de regresión, seguimos el mismo
proceso, excepto que la predicción es la media de todas las predicciones.
Veamos un código para VotingRegressor que usa LinearRegression, SVR
y RandomForestRegressor. Luego ponemos los resultados en la figura 10.10.
Código 12.8: implementación del regresor de votación desde
sklearn.linear_model import LogisticRegression from [Link]
import SVR from [Link] import RandomForestClassifier,
VotingRegressor
# Inicializar los estimadores
clf1 = LinearRegression()
clf2 = RandomForestRegressor(n_estimators= 150 , max_ depth= 3 )
clf3 = SVR(epsilon= 1.5 )
# Crear el método de conjunto
eclf1 = VotingRegressor(estimators=[
( 'lr' , clf1), ( 'rf' , clf2), ( "svc" , clf3)] ) 1
# Entrena el método
[Link](X_train, y_train_reg)
Machine Translated by Google
# Crear predicciones para todo el conjunto de
datos df[ "prediction" ] = [Link]([Link]((X_train,X_test),
axis= 0 ))
# Calcular la estrategia
df[ "estrategia" ] = [Link](df[ "predicción" ]) * df[ "devoluciones" ]
# Prueba retrospectiva
backtest_dynamic_portfolio(df[ "estrategia" ].iloc[split:])
1 Los modelos de votación se definen mediante una lista de
estimadores.
Figura 12.10: Rendimientos acumulados del regresor de votación
Beta: 1,056 Alfa: 7,16 % Sharpe: 0,754 Sortino: 0,968
-------------------------------------------------- ---------------------------
VaR: 47,4 % cVaR: 57,12 % VaR/cVaR: 1,205 reducción: 30,79 %
Machine Translated by Google
El método de votación tiene resultados similares a los del bosque aleatorio, pero el
rendimiento acumulativo es menos volátil.
12.3.2. Método de embolsado
En esta parte, hablaremos sobre el método de embolsado. Es una forma sencilla
de tener un método de conjunto en unas pocas líneas de código. De hecho, el
embolsado es un método que nos permite entrenar un método de conjunto con n
estimadores iguales. Por ejemplo, un bosque aleatorio está repleto de árboles de
decisión. Ahora, crearemos un regresor de embolsado que use 150 SVR.
Figura 12.11: Retorno acumulado de embolsado utilizando 150 SVR
Beta: 1,056 Alfa: 7,16 % Sharpe: 0,754 Sortino: 0,968
-------------------------------------------------- ---------------------------
VaR: 47,31 % cVaR: 57,77 % VaR/cVaR: 1.221disminución: 30,79 %
Machine Translated by Google
En esta figura podemos ver el retorno acumulado de un algoritmo de
ensacado creado con 150 SVR.
Código 12.10: Empaquetado con SVR
desde [Link] import SVR from
[Link] import BaggingRegressor
Machine Translated by Google
# Inicializar el embolsado
bag_reg = BaggingRegressor(SVR(epsilon= 1.5 ), n_estimators= 150 )
# Entrena el método
bag_reg.fit(X_train, y_train_reg)
# Crear predicciones para todo el conjunto de
datos df[ "prediction" ] =
bag_reg.predict([Link]((X_train,X_test), axis=
0 ))
# Calcular la estrategia
df[ "estrategia" ] = [Link](df[ "predicción" ]) * df[ "devoluciones" ]
# Prueba retrospectiva
backtest_dynamic_portfolio(df[ "estrategia" ].iloc[split:])
12.3.3. método de apilamiento
En esta parte, hablaremos sobre el método de apilamiento. Este método es un
poco diferente a los demás porque ahora, en lugar de hacer una media, por
ejemplo, le daremos la predicción de los estimadores a otro algoritmo que dará
la predicción.
Figura 12.12: Esquematización del método de apilamiento
Machine Translated by Google
Esta figura muestra la diferencia entre la votación y el embolsado (izquierda), que
hacen la media de la predicción del estimador en lugar del apilamiento (derecha),
que hace un algoritmo para agregar mejor la predicción.
Por lo general, colocamos un árbol de decisión o un bosque aleatorio
cuando hacemos un clasificador de apilamiento porque funcionan muy
bien con la variable ficticia.
Código 12.11: Implementación del regresor de apilamiento
de sklearn.linear_model importar LinearRegression
de [Link] importar SVR de [Link]
importar RandomForestRegressor, StackingRegressor
# Inicializar los estimadores
clf1 = LinearRegression()
clf2 = RandomForestRegressor(n_estimators= 150 , max_ depth= 3 )
clf3 = SVR(epsilon= 1.5 )
# Crear el método de conjunto
eclf1 = StackingRegressor(estimators=[ ( 'lr' ,
clf1), ( 'rf' , clf2), ( "svc" , clf3)])
# Entrena el método
[Link](X_train, y_train_reg)
Machine Translated by Google
# Crear predicciones para todo el conjunto de
datos df[ "prediction" ] = [Link]([Link]((X_train,X_test),
axis= 0 ))
# Calcular la estrategia
df[ "estrategia" ] = [Link](df[ "predicción" ]) * df[ "devoluciones" ]
# Prueba retrospectiva
backtest_dynamic_portfolio(df[ "estrategia" ].iloc[split:])
Figura 12.11: Retorno acumulativo de un método de apilamiento
Beta: 1,056 Alfa: 7,16 % Sharpe: 0,754 Sortino: 0,968
-------------------------------------------------- ---------------------------
VaR: 46,46 % cVaR: 56,64 % VaR/cVaR: 1,219 reducción: 30,79 %
Machine Translated by Google
En esta figura, podemos ver el retorno acumulativo de un regresor de apilamiento.
Como podemos ver, los resultados de los métodos de conjunto son los mismos.
Significa que no podemos hacer una mejor predicción usando estos datos con este
tipo de algoritmo. Para evitar este problema, veremos algo más poderoso usando el
aprendizaje profundo más adelante.
Resumen
Para encontrar la mejor separación entre grupos, el árbol de decisión
corta el espacio con n hiperplanos (donde n es la profundidad del árbol).
Un bosque aleatorio es un método de conjunto (empaquetado) que usa un
árbol de decisión muy diferente para tener mejores predicciones que un
árbol de decisión.
El árbol de decisión y el bosque aleatorio están muy expuestos al
sobreajuste. Para evitar eso, necesitamos restringir la profundidad del árbol
y la cantidad de árboles para el bosque aleatorio.
Machine Translated by Google
Los métodos de votación combinan algunos algoritmos. Da la media de las
predicciones de algoritmos individuales para la regresión y la clase más
votada para la clasificación.
El embolsado es un método de conjunto que combina el algoritmo exacto n
veces (por ejemplo, bosque aleatorio).
El apilamiento es un método de conjunto que utiliza un algoritmo con las
predicciones de algoritmos en características para encontrar las mejores
predicciones.
Aplicación Live Trading and Screener
Este código se basa en la clase creada en el anexo: MetaTrader
Código 12.12: Comercio de aplicaciones / Screener para el regresor del árbol de decisión de la importación de
MT5 *
importar numpy como np
importar pandas como pd
importar advertencias
[Link]( "ignorar" ) de
[Link] importar DecisionTreeRegressor tiempo de
importación importar pickle de joblib importar volcar, cargar
importar sistema operativo de [Link]
importar StandardScaler
""
sendero = # Ex:
C:/Desktop/Python_for_finance_and_algorithmic_trading/
CapítuloN/
def create_model_weights ( símbolo ):
""" Pesos para la regresión lineal sobre el cambio porcentual"""
# Importar los datos
Machine Translated by Google
datos = MT5.get_data(símbolo, 3500 )[[ "cerrar" ]].pct_change( 1 )
# Crear nueva variable
[Link] = [ "devoluciones" ]
# Características datos de
ingeniería[ "devuelve t-1" ] = datos[[ "devuelve" ]].shift( 1 )
# Media de retornos
data[ "la media devuelve 15" ] = data[[ "returns" ]].rolling( 15 ).mean() .shift( 1 )
data[ "mean devuelve 60" ] = data[[ "returns" ]].rolling
( 60 ).media() .desplazamiento( 1 )
# Volatilidad de los datos
de retorno[ "volatilidad devuelve 15" ] =
datos[[ "devoluciones" ]].rolling( 15 ).std() .shift( 1 ) datos[ "volatilidad
devuelve 60" ] = datos[[ "devoluciones" ]].rodando( 60 ).std() .shift( 1 )
# Dividir los datos
data = [Link]()
split = int( 0.80 * len (datos))
# Creación de conjuntos de trenes
Tren_X = datos[[ "devuelve t-1" , "media devuelve 15" , "significar
devuelve 60" ,
"la volatilidad devuelve ,
15" "la volatilidad devuelve 60" ]].iloc[:split]
y_tren = datos[[ "devoluciones" ]].iloc[:dividir]
sc = escalador estándar()
tren_X = sc.fit_transform(tren_X)
# Crea el modelo
alg = DecisionTreeRegressor(máx_profundidad= 6 )
Machine Translated by Google
# Ajustar el
modelo [Link](X_train, y_train)
# Guardar el modelo
alg_var = [Link](alg)
alg_pickel = [Link](alg_var)
dump(alg_pickel ,[Link](ruta,f "Modelos/ {símbolo}
_reg.joblib" ))
def tree_reg_sig ( símbolo ):
Función """ para predecir el valor de mañana usando
modelo ARIMA"""
# Crea los pesos si no hay en la carpeta
prueba :
alg = load([Link](ruta, f "Modelos/ {símbolo} _reg.joblib" ))
excepto :
create_model_weights(símbolo) alg
= load([Link](ruta, f "Modelos/ {símbolo} _reg.joblib" ))
# Tomar el último porcentaje de cambio de
datos = MT5.get_data(símbolo, 3500 )[[ "cerrar" ]].pct_change( 1 )
# Crear nueva variable
[Link] = [ "devoluciones" ]
# Características datos de
ingeniería[ "devuelve t-1" ] = datos[[ "devuelve" ]].shift( 1 )
# Media de retornos
data[ "la media devuelve 15" ] = data[[ "returns" ]].rolling( 15 ).mean() .shift( 1 )
data[ "mean devuelve 60" ] = data[[ "returns" ]].rolling
( 60 ).media( ).desplazamiento( 1 )
Machine Translated by Google
# Volatilidad de los datos
de retorno[ "volatilidad devuelve 15" ] =
datos[[ "devoluciones" ]].rolling( 15 ).std() .shift( 1 ) datos[ "volatilidad
devuelve 60" ] = datos[[ "devoluciones" ]].rodando( 60 ).std() .shift( 1 )
X = datos[[ "devuelve t-1" , "media devuelve 15" , "rendimientos medios
60" ,
"volatilidad devuelve 15" ,
"volatilidad devuelve 60" ]].iloc[ -1 :,:].values
# Encuentra la
señal predicción = [Link](X)
comprar = predicción[ 0 ] > 0
vender = no comprar
volver comprar, vender
# Verdadero = Comercio en vivo y Falso = Screener en
vivo = Verdadero
if live:
current_account_info = mt5.account_info() print
( "-------------------------------------- ----------------------" ) print ( "Fecha: " ,
[Link]().strftime(
"Saldo:"%Y-%m-%d
{info_cuenta_actual.saldo}
%H :%M:%S" ))USD,
print ( f
\t"
f "Patrimonio: {info_cuenta_actual.equity} USD, \t" f
"Beneficio: {info_cuenta_actual.beneficio} USD" ) print
( "--------------------- --------------------------------------------" )
info_order =
{ "Google" : [ "Alphabet_Inc_C_(GOOG.O).a" , 1.00 ]
} inicio = [Link]().strftime( "%H:%M:%S" ) #"23:59:59"
mientras que es cierto :
Machine Translated by Google
# Verificación para el lanzamiento
si [Link]().weekday() no está en ( 5 , 6 ):
es_hora = [Link]().strftime( "%H:%M:%S" ) ==
comienzo
más :
es_tiempo = Falso
# Inicie el algoritmo si
es_tiempo:
# Abra las
operaciones de activos en info_order.keys():
# Inicializar el símbolo de
entrada = info_pedido[activo][ 0 ] lote
= info_pedido[activo][ 1 ]
# Crear las señales
comprar, vender = tree_reg_sig(símbolo)
# Ejecutar el algoritmo
si está
activo: [Link] (símbolo, compra, venta, lote)
más :
print ( f "Símbolo: {símbolo} \t" f
"Comprar: {comprar} \t" f "Vender:
{vender} " )
[Link]( 1 )
El parámetro en vivo establece el comercio en vivo (en vivo =
Verdadero) o el modo de filtro (en vivo = Falso).
Machine Translated by Google
Capítulo 13: Redes neuronales profundas (DNN)
En este capítulo, vemos nuestro primer algoritmo para el aprendizaje
profundo. Hablaremos de la red neuronal profunda DNN, o red neuronal
artificial ANN. El aprendizaje profundo es un campo del aprendizaje automático
que utiliza los algoritmos más potentes. Sin embargo, requiere muchos
recursos para funcionar. Para explicar el DNN y crear una estrategia comercial
utilizando este algoritmo, explicaremos la intuición detrás del DNN y cómo
crear un clasificador DNN y un regresor DNN. Además, después de este
capítulo, seremos capaces de hacer que nuestra pérdida funcione.
Implementaremos los algoritmos en el precio de las acciones de Apple.
13.1. Intuición detrás de DNN
Machine Translated by Google
Esta parte discutirá la intuición detrás de la Red Neural Profunda o DNN. Para
ello, hablaremos de la propagación hacia adelante de una red neuronal, luego del
descenso de gradiente y finalmente de la propagación hacia atrás.
13.1.1. Propagación hacia adelante
En esta subsección, aprenderemos mucho sobre la propagación de reenvío, que
es el proceso utilizado por el algoritmo para crear una predicción. Lo esencial en
este proceso es la neurona. De hecho, es una parte esencial para comprender el
concepto de propagación de reenvío. Para empezar, explicamos cómo funciona
una neurona.
Una neurona es como una regresión lineal. Tiene una entrada llamada X y un
conjunto de parámetros para predecir una salida y. Los parámetros se nombran
pesos en el aprendizaje profundo, y la intersección (en la regresión lineal) se
llama sesgo. La única diferencia entre la neurona y una regresión lineal es que
ponemos una función de activación (hablaremos de las funciones de acción más
adelante). Veamos el proceso detrás de una neurona en la figura 13.1.
Figura 13.1: Proceso neuronal
En esta figura, podemos ver el proceso detrás de una neurona en una red neuronal
profunda.
Machine Translated by Google
Ahora, analicemos la función de activación. Por lo general, es solo una forma
de contener el valor de la salida. Sin embargo, explicaremos más adelante
que en la capa oculta, la elección de la función de activación no es "realmente"
esencial pero es crucial para la capa de salida. Veamos las diferentes funciones
de activación en la figura 13.2 para entender mejor la noción.
Figura 13.2: Algunas funciones de activación
Esta figura muestra algunas funciones de activación, siendo las más utilizadas la
función ReLu, la lineal y la sigmoidea.
Ahora, ya sabemos casi todo sobre la intuición detrás de la propagación de
reenvío. Lo único que necesitamos saber es cómo combinar neuronas para
crear una red neuronal.
La construcción de una red neuronal es sencilla. En la figura 13.1, hemos
creado una neurona con entradas y salidas. Debemos conectar algunas neuronas
para crear una red neuronal, como en la figura 13.3.
Así, la salida de la primera neurona se convierte en la entrada de las siguientes y así
sucesivamente hasta llegar a la neurona de salida.
Machine Translated by Google
Figura 13.3: Red neuronal profunda
En esta figura podemos ver el funcionamiento de una DNN. Vemos la capa de
entrada con los datos, la capa oculta y la capa de salida.
Como puede ver, la interpretabilidad del modelo es complicada
porque hay mucho cálculo y peso. Por lo tanto, a algunas
personas en finanzas no les gustan las DNN porque quieren saber
en qué criterios invertirán. Sin embargo, a la mayoría no le importa.
Por lo tanto, la propagación de reenvío consiste en colocar datos en la red neuronal
y dar un resultado, la predicción. Sin embargo, este proceso no entrena nuestro
algoritmo. Entonces, en las siguientes partes, veremos cómo entrenar el DNN.
13.1.2. Descenso de gradiente
En esta parte, aprenderemos qué es el descenso de gradiente. El descenso de
gradiente es el algoritmo más popular en el aprendizaje automático para optimizar el
peso de un algoritmo. Es una forma de resolver un problema de optimización.
Machine Translated by Google
El gradiente descendente es un algoritmo basado en el gradiente de la función que se
quiere optimizar. Este algoritmo es matemáticamente fácil de entender, pero necesitamos
usar algunas matemáticas muy complejas para crearlo.
Entonces, solo veremos la intuición aquí. No obstante, si queremos profundizar más en el tema,
podemos encontrar mucha documentación al respecto en internet.
Necesitamos tomar un ejemplo simple para entender cómo funciona el descenso de
gradiente. Estamos en una montaña y hay una gran niebla. Queremos bajar de la montaña
pero no podemos ver nada.
Para hacerlo, buscaremos sólo con los pies el camino de mayor pendiente hacia abajo, y en esa
dirección nos dirigimos después de algunos metros; Continuaremos este proceso hasta que
estemos abajo.
Es precisamente lo que hace el algoritmo. Después de que queremos verificar qué camino
tiene la mayor pendiente hacia abajo, el algoritmo usa el gradiente más negativo mientras
usamos nuestros pies para encontrar la pendiente más hacia abajo.
La elección del ritmo de aprendizaje es fundamental. Veamos en la figura 13.4 la
importancia de la tasa de aprendizaje.
Figura 13.4: Elección de la tasa de aprendizaje
En esta figura podemos ver la importancia del aprendizaje en el proceso de formación.
Machine Translated by Google
En deep learning, la letra representa todo el peso de todas
las neuronas de la red. Son los parámetros de
los modelos. Entonces, si cambiamos, cambiamos parte o
todo el peso y el sesgo de las neuronas.
El único problema con el descenso de gradiente es que puede caer en un
mínimo local. Para esquematizar el mínimo local y global, podemos pensar en un
buscador de oro en una cueva. Hay un paquete de 1 kg de oro (el mínimo local) y
solo un paquete de 100 kg (el mínimo global). Supongamos que no sabemos que
hay una manada en la cueva. Hay muchas posibilidades de encontrar un paquete
de 1 kg y salir de la cueva sin el paquete de 100 kg; este problema depende de la
función de costo. Por lo general, para una tarea de regresión, usamos el MSE, que
es convexo, por lo que no hay problema. Sin embargo, el algoritmo puede caer en
un mínimo local si creamos nuestra función de pérdida como en la siguiente parte.
Figura 13.5: Mínimo global VS mínimo local
Esta figura muestra que si la función no es estrictamente convexa, el algoritmo
puede caer en un mínimo local incluso si hay un mínimo global en otro lugar.
Para resolver este problema, podemos utilizar el descenso
de gradiente estocástico [16] u otra de estas derivadas.
Machine Translated by Google
13.1.3. retropropagación
Hablaremos de retropropagación. En este paso, sabemos todo lo que debemos
hacer para explicar la retropropagación. Necesitamos ensamblar las piezas.
Figura 13.6: Entrenamiento de DNN
Después de ver esta figura, podemos entender la definición de backpropagation: cambiar
el peso después de cada iteración según el descenso del gradiente para optimizar el
algoritmo y hacer mejores predicciones en el futuro.
13.2. DNN para clasificación
Esta sección explicará cómo hacer un DNN correctamente para una tarea de clasificación
usando Python. Prepararemos los datos y destacaremos algunos puntos a saber. Luego
implementaremos el DNN y crearemos una estrategia con la predicción.
Machine Translated by Google
13.3.1. Preparación de datos
En esta subsección, discutiremos sobre la preparación de los datos.
En cuanto a los algoritmos anteriores, los datos se dividirán en conjuntos de entrenamiento y
prueba. Trabajamos al precio de las acciones de Apple con un marco de tiempo diario.
Código 13.1: Preparación de los datos # Importar los datos df =
[Link]( "AAPL" ]].pct_change( 1 ) [Link] = [ "devoluciones" ]
, end= "2021-01-01" )[[ "Cerrar ajuste"
# Funciones de ingeniería
df[ "devoluciones t-1" ] = df[[ "devoluciones" ]].shift( 1 )
# Media de retornos
df[ "media devuelve 15" ] = df[[ "devuelve" ]].rolling( 15 ).mean().shift( 1 )
df[ "media devuelve 60" ] = df[[ "devuelve" ]].rolling
( 60 ).media().desplazamiento( 1 )
# Volatilidad de los
rendimientos df[ "volatilidad devuelve 15" ] =
df[[ "devoluciones" ]].rolling( 15 ).std().shift( 1 ) df[ "volatilidad devuelve 60" ] =
df[[ "devoluciones" ]].rodando( 60 ).std().shift( 1 )
# Elimina los valores que faltan
df = [Link]()
# Porcentaje de división del
conjunto de trenes = int( 0.80 * len (df))
# Creación de conjuntos de trenes
Machine Translated by Google
Tren_X = df[[ "devuelve t-1" , "media devuelve 15" , "media devuelve 60"
,
"la volatilidad devuelve ,
15" "la volatilidad devuelve 60" ]].iloc[:split]
y_train_reg = df[[ "devoluciones" ]].iloc[:dividir]
y_tren_cla = np. round (df[[ "devoluciones" ]].iloc[:split]+ 0.5 )
# Creación del conjunto de pruebas
X_test = df[[ "devuelve t-1" , "media devuelve 15" , "media devuelve 60" ,
"volatilidad devuelve 15" ,
"volatilidad devuelve 60" ]].iloc[split:]
y_test_reg = df[[ "devoluciones" ]].iloc[split:]
y_test_cla = np. round (df[[ "devoluciones" ]].iloc[split:]+ 0.5 )
# NORMALIZACIÓN #
Importar la clase desde
[Link] import StandardScaler
# Inicializar la clase
sc = StandardScaler()
# Estandarizar los datos
X_train_scaled = sc.fit_transform(X_train)
X_test_scaled = [Link](X_test)
No explicamos esta parte porque está codificada de los capítulos anteriores. Al
mismo tiempo, es fundamental estandarizar nuestros datos cuando trabajamos
con una red neuronal porque es un algoritmo muy complejo.
13.2.2. Implementación de un DNN para una tarea de clasificación
En esta parte, implementaremos un DNN para una tarea de clasificación.
Usaremos TensorFlow para crear el modelo. Los algoritmos de aprendizaje
profundo exigen un poco de comprensión para crearlos. Por lo tanto, asegúrese
de que entendemos los capítulos anteriores antes de comenzar.
Machine Translated by Google
Crear un modelo con TensorFlow nos da muchas posibilidades.
Sin embargo, por el contrario, necesitamos entender lo que queremos hacer
en lugar del algoritmo scikit-learn en el que tenemos que poner los datos.
Sin embargo, no te preocupes, te vamos a explicar paso a paso la construcción
de los diferentes pasos de la DNN.
Código 13.2: Red neuronal profunda para tareas de clasificación
#LIBAIRIAS
importar tensorflow
desde [Link] importar secuencial
desde [Link] importar denso
nb_capa_oculta = 1 1
# MODELO SECUENCIAL DE INICIALIZACIÓN
clasificador = Secuencial( ) 2
# AGREGAR CAPA OCULTA
por _ en el rango (nb_hidden_layer) : 3
[Link](Dense( 75 , input_shape = (X_train.shape[ 1 ],),
activación= "relu" ) ) 4
# CAPA DE SALIDA DENSA
[Link](Denso( 1 , activación = "sigmoide" ) ) 5
# COMPILA EL MODELO
clasificador compilar (pérdida = "binary_crossentropy" , optimizador =
"Adán" ) 6
# CAPACITACIÓN
[Link](X_train_scaled, y_train_cla, epochs= 15 , lote_tamaño=
32 , detallado= 1 ) 7
Defina el número de capas ocultas.
Machine Translated by Google
2 Inicialice la red neuronal.
3 Cree un bucle que agregue las capas ocultas.
4 input_shape = (X_train.shape[1],) es solo
necesario para la primera capa.
5 Hay que ponerle un sigmoide a la activación
porque es un clasificador.
6 Compilación del modelo utilizando el gradiente estocástico
y la entropía cruzada binaria como función de pérdida.
7 Ajuste el modelo usando solo verbose=1 para resaltar el
entrenamiento del modelo.
Ahora, explicaremos este código. Primero, necesitamos inicializar el modelo
como para los modelos de scikit-learn. Después de eso, solo tenemos un modelo
vacío; necesitamos construirlo. El bucle nos permite crear tantas capas ocultas como
queramos. La función Dense de TensorFlow crea una capa de redes neuronales.
Tenemos que ser precisos sobre cuántas neuronas queremos, la forma de las entradas
y la función de activación.
Luego necesitamos definir una capa particular para la salida porque
necesitamos predecir la clase. Entonces, queremos predecir un 0 o un 1. Elegimos
el sigmoide para activar esta neurona porque el valor estará entre 0 y 1, y
queremos una probabilidad.
Luego tenemos que explicar cómo queremos entrenar el algoritmo. Elegimos la
función de entropía cruzada y un gradiente de descenso estocástico llamado "adam".
Para ajustar el modelo, debemos elegir el número de épocas y el tamaño del lote.
Podemos poner devoluciones de llamada en la función de ajuste
para detener el algoritmo a un cierto nivel de pérdida de función,
pero esto no es relevante para este libro. Puede leer la
documentación de TensorFlow para obtener más detalles.
Machine Translated by Google
13.2.3. Predicción y Backtest
En esta parte, analizaremos el rendimiento de una estrategia creada utilizando un
DNN. Vamos a utilizar precisamente el mismo código que el backtest anterior.
Código 13.3: Calcular la estrategia de retorno utilizando las predicciones de DNN # Crear
predicciones para todo el conjunto de datos df[ "prediction" ] =
[Link]([Link]((X_train,X_test), axis= 0 )) df[ "prediction" ] = [Link](df[ "predicción" ]
== 0 # Calcular la estrategia df[ "estrategia" ] = [Link](df[ "predicción" ]) * df[ "devoluciones" ]
, -1 , 1)
# Prueba retrospectiva
backtest_dynamic_portfolio(df[ "estrategia" ].iloc[split:])
Con este código, podemos ver el backtest de una estrategia utilizando el clasificador
DNN en acciones de Apple. Como podemos ver, hay un excelente desempeño
porque ganamos más del 30% anual. En comparación, debemos considerar que no
hemos integrado las tarifas.
Figura 13.7: Backtest de una estrategia de predicción de DNN en acciones de Apple
Beta: 1,23 Alfa: 17,49 % Sharpe: 0,594 Sortino: 0,841
-------------------------------------------------- ---------------------------
VaR: 84,73 % cVaR: 100,5 % VaR/cVaR: 1,186 reducción: 81,8 %
Machine Translated by Google
Podemos ver una buena tendencia en el crecimiento del capital usando esta estrategia.
13.3. DNN para regresión
En esta sección, aprenderemos cómo crear un DNN para una tarea de regresión y cómo crear
nuestra función de pérdida. Luego, pruebe la estrategia.
Machine Translated by Google
13.3.1. Implementando un DNN para una tarea de regresión
En esta parte, crearemos un DNN para una tarea de regresión. Es muy similar
al clasificador, pero hay algunas sutilezas. Solo necesitamos cambiar la función
de pérdida para optimizar la activación de la neurona de salida. Veamos el
código y luego lo explicaremos más detalladamente.
Código 13.4: implementación del regresor DNN
nb_capa_oculta = 1
# INICIALIZACIÓN MODELO SECUENCIAL regresor
= Secuencial()
# AGREGAR CAPA OCULTA
por _ en rango (nb_hidden_layer):
[Link](Dense( 75 , input_shape
= (X_train.shape[ 1 ],),
activación= "relu" ))
# CAPA DE SALIDA DENSA
[Link](Dense( 1 , activación= "lineal" ))
# COMPILA EL MODELO
regresor compilar (pérdida = "mse" , optimizador = "adam" )
# CAPACITACIÓN
[Link](X_train_scaled, y_train_reg, epochs= 15 , lote_tamaño=
32 , detallado= 1 )
Aquí la función de activación de la neurona de salida es
esencial. Por ejemplo, si ponemos un sigmoide, el algoritmo
predice solo un retorno positivo, lo cual es imposible.
Hemos optado por entrenar el modelo utilizando el error cuadrático medio
(MSE) como función de pérdida.
Machine Translated by Google
Si comenzamos con el aprendizaje profundo, se recomienda
mantener la función de activación lineal para la salida de un
regresor. Si entendemos bien el concepto, podemos probar una
función tanh u otras como se ha visto antes.
13.3.2. Función de pérdida personalizada
Hemos visto cómo entrenar el modelo con una métrica habitual en la última
parte. Al mismo tiempo, podemos crear nuestras métricas si queremos. La pregunta es,
¿por qué queremos hacer eso? Expliquemos algunas limitaciones: Tomamos la misma
inversión si el algoritmo predice 15% o - 0.000001%.
El error es casi el mismo para el MSE entre 0.000001 o -0.000001.
Por lo tanto, debemos incorporar en nuestra función de pérdida que si la predicción
tiene un signo incorrecto, agregamos un malus. Necesitamos calcular la siguiente
ecuación en Tensorflow.
Donde está la predicción, es el valor verdadero y > 1.
Código 13.5: Función MSE personalizada
def ALPHA_MSE ( y_true , y_pred ) : 1
y_true_roll = [Link](y_true, shift= 1 , eje= 0 ) 2
y_pred_roll = [Link](y_pred, shift= , eje= 0 )
1 y_true_dif = [Link](y_true_roll-y_true)
3 y_pred_dif = [Link](y_pred_roll-y_pred)
Machine Translated by Google
booleen_vector = y_true_dif == y_pred_di f 4
alpha = [Link](booleen_vector, 1 , 3 ) 5
alpha = [Link](alpha, dtype=tf.float32 ) 6
mse = [Link](y_true-y_pred) mse =
[Link](mse, dtype=tf.float32) scale_mse =
[Link](alpha, mse) alpha_mse =
[Link](scale_mse) return alpha_mse
1 La función de pérdida personalizada debe tener dos
parámetros y_true e y_pred, que son tensores.
Por lo tanto, todos los cálculos deben usar funciones de
TensorFlow.
2 Cree una nueva variable que contenga el turno de destino
por 1.
3 Toma el signo de la variación diaria.
4 Cree un tensor booleano en el que cada valor sea Verdadero
si y_verdadero e y_pred varían de la misma manera y
Falso tampoco.
5 Crear vector multiplicador, que es igual a 1 si los dos
vectores varían de la misma manera y 3 tampoco para
penalizar el tamaño incorrecto.
6 Transformar un tensor en un vector constante.
Esta parte no es obligatoria para el libro, pero debe saber que
es posible crear una función de pérdida personalizada.
Puedes consultar la documentación de TensorFlow si quieres
profundizar en el tema.
Tenga en cuenta que personalizar una función de pérdida y crear una
métrica con scikit learn son dos cosas distintas; no los confundas. Con las
métricas personalizadas de scikit-learn, entrenamos un modelo utilizando un
MSE u otra función esencial y tomamos las mejores
Machine Translated by Google
modelos siguiendo las métricas creadas. Sin embargo, la función de
pérdida personalizada en TensorFlow es la función que calcula el error del
modelo (como MSE en scikit-learn).
13.3.3. Predicción y Backtest
En esta parte, probaremos la estrategia creada usando la pérdida personalizada
y la estrategia usando el entrenamiento DNN con pérdida MSE.
Como podemos ver en la figura y como hemos dicho en la última parte, la pérdida
personalizada no es para principiantes. De hecho, la estrategia de pérdida
personalizada es buena pero no mejor que la estrategia que utiliza el MSE.
Figura 13.8: Backtest de la estrategia usando MSE y MSE alpha
MSE alfa
Beta: 1.127 Alfa: 15.55 % Sharpe: 1.065 Sortino: 1.396
-------------------------------------------------- ---------------------------
VaR: 36,33 % cVaR: 45,6 % VaR/cVaR: 1,255 reducción: 38,52 %
Machine Translated by Google
MSE
Beta: 1.127 Alfa: 15.55 % Sharpe: 1.065 Sortino: 1.396
-------------------------------------------------- ---------------------------
VaR: 36,33 % cVaR: 45,6 % VaR/cVaR: 1,255 reducción: 38,52 %
Machine Translated by Google
Esta figura muestra que la función de pérdida personalizada no afecta el
rendimiento porque los dos backtest son similares.
Con la DNN tenemos excelentes resultados, pero la DNN no considera
que trabajemos con una serie temporal.
Resumen
Machine Translated by Google
El proceso detrás de una neurona es como una regresión lineal; en lugar
de poner la y en una función de activación.
Hay muchas funciones de activación. Sin embargo, las más utilizadas son
la función ReLu y la sigmoidea. La elección de la función es crucial en algunas
situaciones.
Lo esencial en el descenso de gradiente es la tasa de aprendizaje.
Además, usamos el descenso de gradiente estocástico para evitar caer a un
mínimo local.
La retropropagación es el momento en que cambiamos los pesos del
modelo. Por lo tanto, sin esta parte, no podemos entrenar nuestro modelo.
Podemos personalizar una función de pérdida. Sin embargo, se necesita
mucho conocimiento en aprendizaje profundo para hacerlo correctamente.
Por lo tanto, si no estamos cómodos con las nociones de los libros, no
debemos entrar en este tema.
Aplicación Live Trading and Screener
Este código se basa en la clase creada en el anexo: MetaTrader
Código 13.6: Comercio de aplicaciones / Regresor ANN
desde MT5 importar *
importar numpy como np
importar pandas como pd
importar advertencias
[Link]( "ignorar" )
tiempo de importación
Machine Translated by Google
importar pickle
desde joblib import dump, cargar
importar
sistema operativo desde [Link] importar
StandardScaler importar tensorflow desde
[Link] importar Sequential desde
[Link] importar Dense
= ""
sendero # Ex:
C:/Desktop/Python_for_finance_and_algorithmic_trading/
CapítuloN/
def ANN ():
# Crea el modelo
nb_capa_oculta = 1
# MODELO SECUENCIAL DE INICIALIZACIÓN alg
= Sequential()
# AGREGAR CAPA OCULTA
por _ en rango (nb_hidden_layer):
[Link](Dense(75 , input_shape = (5 ,), activación=
"relú" ))
# CAPA DE SALIDA DENSA
[Link](Denso( 1 , activación= "lineal" ))
# COMPILA EL MODELO
alg. compilar (pérdida = "mse" , optimizador = "adam" )
devolver alg
def create_model_weights ( símbolo ):
""" Pesos para la regresión lineal sobre el cambio porcentual"""
# Importar los datos
datos = MT5.get_data(símbolo, 3500 )[[ "cerrar" ]].pct_change( 1 )
Machine Translated by Google
# Crear nueva variable
[Link] = [ "devoluciones" ]
# Características datos de
ingeniería[ "devuelve t-1" ] = datos[[ "devuelve" ]].shift( 1 )
# Media de retornos
data[ "la media devuelve 15" ] = data[[ "returns" ]].rolling( 15 ).mean() .shift( 1 )
data[ "mean devuelve 60" ] = data[[ "returns" ]].rolling
( 60 ).media() .desplazamiento( 1 )
# Volatilidad de los datos
de retorno[ "volatilidad devuelve 15" ] =
datos[[ "devoluciones" ]].rolling( 15 ).std() .shift( 1 ) datos[ "volatilidad
devuelve 60" ] = datos[[ "devoluciones" ]].rodando( 60 ).std() .shift( 1 )
# Dividir los datos
data = [Link]()
split = int( 0.80 * len (datos))
# Creación de conjuntos de trenes
Tren_X = datos[[ "devuelve t-1" , "media devuelve 15" , "significar
devuelve 60" ,
"la volatilidad devuelve ,
15" "la volatilidad devuelve 60" ]].iloc[:split]
y_tren = datos[[ "devoluciones" ]].iloc[:dividir]
# Inicializar la clase sc
= StandardScaler()
# Estandarizar los datos
X_train = sc.fit_transform(X_train)
alg = ANA()
Machine Translated by Google
# CAPACITACIÓN
[Link](tren_X, tren_y, épocas= 13 , lote_tamaño= 32 ,
detallado = 1 )
# Guardar el modelo
alg.save_weights([Link](ruta,f "Modelos/ANN_reg_
{símbolo} " ))
def ANN_cla_sig ( símbolo ):
Función """ para predecir el valor de mañana usando
modelo ARIMA"""
# Crea los pesos si no hay en la carpeta
intente : alg =
ANN() alg.load_weights([Link](ruta, f "Modelos/ANN_reg_
{símbolo} " ))
excepto :
create_model_weights(símbolo) alg
= ANN() alg.load_weights([Link](ruta,
f "Modelos/ANN_reg_
{símbolo} " ))
# Tomar el último porcentaje de cambio de
datos = MT5.get_data(símbolo, 3500 )[[ "cerrar" ]].pct_change( 1 )
# Crear nueva variable
[Link] = [ "devoluciones" ]
# Características datos de
ingeniería[ "devuelve t-1" ] = datos[[ "devuelve" ]].shift( 1 )
# Media de retornos
data[ "la media devuelve 15" ] = data[[ "returns" ]].rolling( 15 ).mean() .shift( 1 )
data[ "mean devuelve 60" ] = data[[ "returns" ]].rolling
( 60 ).media() .desplazamiento( 1 )
# Volatilidad de los retornos
Machine Translated by Google
data[ "volatilidad devuelve 15" ] =
data[[ "devoluciones" ]].rolling( 15 ).std() .shift( 1 ) data[ "volatilidad
devuelve 60" ] = data[[ "devoluciones" ]].rolling ( 60 ).std() .shift( 1 )
X = datos[[ "devuelve t-1" , "media devuelve 15" , "rendimientos medios
60" ,
"volatilidad devuelve ,
15" "volatilidad devuelve 60" ]].iloc[ -1 :,:].values
# Encuentra la
señal predicción =
[Link](X) predicción = , -1 , 1)
[Link](prediction== 0 comprar =
predicción[ 0 ][ 0 ] > 0 vender = no comprar
volver comprar, vender
# Verdadero = Comercio en vivo y Falso = Screener en
vivo = Verdadero
if live:
current_account_info = mt5.account_info()
print ( "-------------------------------------- ----------------------" ) print
( "Fecha: " , [Link]().strftime(
%S" )) print ( f "Saldo:
"%Y-%m-%d
{info_cuenta_actual.saldo}
%H :%M:
USD,
\t"
f "Patrimonio: {info_cuenta_actual.equity} USD, \t" f
"Beneficio: {info_cuenta_actual.beneficio} USD" ) print
( "--------------------- --------------------------------------------" )
info_pedido = {
"Apple" : [ "AAPL.a" , 1.00 ]
}
Machine Translated by Google
inicio = [Link]().strftime( "%H:%M:%S" ) #"23:59:59"
mientras que es cierto :
# Verificación para el lanzamiento
si [Link]().weekday() no está en ( 5 , 1 ):
es_hora = [Link]().strftime( "%H:%M:%S" ) ==
comienzo
más :
es_tiempo = Falso
# Inicie el algoritmo si es_tiempo:
# Abra las operaciones
de activos en info_order.keys():
# Inicializar el símbolo de
entrada = info_pedido[activo][ 0 ] lote =
info_pedido[activo][ 1 ]
# Crear las señales
comprar, vender = ANN_cla_sig(símbolo)
# Ejecutar el algoritmo
si está
activo: [Link] (símbolo, compra, venta, lote)
más :
print ( f "Símbolo: {símbolo} \t" f "Comprar:
{comprar} \t" f "Vender: {vender} " )
[Link]( 1 )
El parámetro en vivo establece el comercio en vivo (en vivo
= Verdadero) o el modo de filtro (en vivo = Falso).
Machine Translated by Google
Machine Translated by Google
Capítulo 14: Red neuronal recurrente
En este capítulo, hablaremos sobre las Redes Neuronales Recurrentes (RNN).
Este algoritmo especializado en series de tiempo puede ser un valioso aliado en la
creación de una estrategia comercial porque los precios de los activos son series de tiempo.
Además, es uno de los algoritmos de aprendizaje profundo más complejos.
Implementaremos las estrategias utilizando las acciones de Netflix.
14.1 Principios de RNN
En esta sección, aprenderemos cómo funciona un RNN. Aquí veremos la base de
RNN, pero puede consultar algunos documentos de Internet si desea profundizar en el
tema.
14.1.1. Cómo funciona un RNN
Esta parte discutirá la intuición detrás de la RNN. Los modelos RNN están
especializados en el modelado de series temporales. De hecho, la estructura de la
red es ligeramente diferente de la ANN porque las capas ocultas están interconectadas.
La interconexión entre la capa oculta permite que el modelo "recuerde" el pasado. En
la RNN, hay dos tipos de memoria en lugar de la ANN. La RNN tiene su memoria a
largo plazo pero también una memoria a corto plazo creada por la interconexión de la
que hablamos anteriormente.
Necesitamos un poco de representación para entender mejor cómo funciona un RNN.
Para hacerlo, necesitamos simplificar la representación de la RNA.
Esquematizaremos la RNA solo con su capa y no con todas las neuronas.
Nos permite visualizar el modelo directamente para crear la representación de la RNN
más fácilmente. Veamos la figura 14.1.
Machine Translated by Google
Figura 14.1: Nueva esquematización de la RNA
Esta figura mostraba la representación de una ANN usando la capa solo con el
cuadrado en lugar de la izquierda con todas las neuronas. Sin embargo, es la
misma ANN.
Figura 14.2: Esquematización de RNN
Como vemos, la RNN no es otra cosa que la ANN conectada. Vemos que la
información de la capa oculta se da directamente a la siguiente capa oculta,
y no se integra solo con los pesos de los modelos.
Machine Translated by Google
El problema con la RNN es que el modelo puede tener algunos problemas con
el gradiente, ya que hay muchas más derivaciones que en el caso de la ANN, lo
que puede causar problemas de gradiente que se desvanece. Al mismo tiempo,
los investigadores han encontrado una solución a este problema.
Han creado nuevas neuronas llamadas neuronas de memoria a corto plazo
(LSTM). Es ligeramente diferente de la estructura de una neurona que vemos en
la última sección, por lo que debemos estudiarla.
14.1.2. neurona LSTM
¿Cómo funciona una celda LSTM? Naturalmente, no es un curso de aprendizaje
profundo. Por lo tanto, si desea comprender mejor la celda LSTM, debe conectarse
a Internet porque este tema es irrelevante para este libro. Háganos saber cómo se
ve una celda LSTM. Luego, explicamos la diferencia entre las células densas y LSTM.
Figura 14.3: Celda LSTM
Esta figura muestra el funcionamiento de una celda LSTM donde la memoria
, yque
en el momento t es la información
hay una memoria
en el momento
a largo plazo
t es . Entonces, podemos decir
ya corto plazo.
Machine Translated by Google
Para comprender mejor la celda LSTM, tomaremos un pequeño ejemplo.
Supongamos que tenemos un algoritmo que predice la siguiente
palabra, por ejemplo. Necesitamos C, que es la oración, y h, que es algún
adjetivo, y x, la palabra anterior.
La sigma es la función de activación sigmoidea. La mayoría agrega
información, funciona como una válvula de plomería, dejará pasar la
información o no usará la propiedad de la función sigmoidea.
Así que no vamos más lejos. Es comprensible que no se entienda esta
noción. Sin embargo, esta sección solo nos brinda información para
comprender mejor cómo vamos a crear la estrategia utilizando la RNN y
no será un curso completo de aprendizaje profundo. Si no entiendes
esta explicación, no te preocupes, podemos continuar el libro sin entenderlo.
14.1.3. célula GRU
En esta parte, veremos derivados de la neurona LSTM, la Unidad
Recurrente Gated (GRU). Es una excelente alternativa al LSTM porque
toma solo la información de la neurona anterior y no la memoria, lo que
puede ser problemático en nuestro caso. De hecho, supongamos que
recordamos cómo reaccionó el mercado hace 15 años. En ese caso, no
será lo mismo que la reacción del mercado ahora porque las instituciones
del mercado han cambiado, las tecnologías han evolucionado, etc.
Figura 14.4: Célula GRU
Machine Translated by Google
Como podemos ver en la celda GRU, sólo la información , Nosotros no
considere la memoria en su lugar como en el LSTM.
Incluso si el GRU y el LSTM difieren, debe probar ambos al
crear su estrategia comercial en un modelo RNN.
En esta sección, hemos visto mucha información sobre RNN. Podemos volver a
leer esta sección si no nos sentimos cómodos con esta noción o pasar a la siguiente
sección porque la teoría es necesaria para entender lo que hacemos pero no para
crear el modelo. Después de todo, ya conocemos el funcionamiento de una ANN. El RNN
es similar aunque tiene algunas especificidades. Ahora, estamos listos para comenzar el
código de la RNN usando TensorFlow.
14.2. RNN para clasificación
Veremos cómo transformar nuestros datos en datos 3d (necesarios para la clasificación
y regresión e implementar nuestro modelo) y cómo hacer backtesting de la estrategia
creada.
14.2.1. Transformar datos 2d a datos 3d
Machine Translated by Google
Esta parte explicará por qué y cómo transformar nuestros datos 2D en datos 3D.
Si hemos entendido muy bien la teoría detrás de la RNN (aunque sea muy difícil con
la información que te dan), hemos entendido que esta red toma para cada una una
matriz de forma (lags, m) donde lag es el número de retraso y m es el número de
características. Entonces, si tenemos n observaciones, tenemos una matriz con una
forma (n, rezagos, m). La figura 14.5 representa la base de datos que necesitamos.
Figura 14.5: Esquematización de los datos para una RNN
una observación Todas las observaciones
Como podemos ver, la base de datos para un RNN debe ser tridimensional. Son las
mismas reglas que para la ANN. Sin embargo, para ANN, tenemos una línea como
observación, por lo tanto, una matriz unidimensional, y cuando tenemos más de una,
la matriz se vuelve bidimensional, en lugar de RNN, que necesita una matriz
bidimensional POR observación. Naturalmente, si tenemos más de uno, la matriz será
tridimensional.
Código 14.1: Transformar datos 2d en datos 3d
def X_3d_RNN ( X_s , y_s , retraso ):
Machine Translated by Google
# Verificación simple
si len (X_s) != len (y_s):
print ( "Advertencias" )
# Crea el X_train
X_train = [] para la
variable en el rango ( 0 , X_s.shape[ 1 ]): X =
[] para i en el rango (lag, X_s.shape[ 0 ]):
[Link](X_s[i- retraso:i, variable])
Tren_X.append(X)
Tren_X, [Link](tren_X)
Tren_X = [Link]([Link](X_tren, 0 , 1 ), 1 ,2)
# Crea el y_train
y_train = [] para i en
el rango (lag, y_s.shape[ 0 ]):
y_train.append(y_s[i, :].reshape( -1 , 1 ).transponer())
y_train = [Link](y_train, axis= 0 )
return X_train, y_train
Para verificar si X_train e y_train tienen el mismo tamaño, mostramos
un mensaje pero no generamos un error porque, por alguna razón,
podemos usar X_train e y_train con diferentes longitudes.
Notamos que la forma y_train no cambiará, pero la ponemos en la función
para cambiar el valor debido al retraso. Ahora, tenemos los datos en un
formato adecuado. Podemos comenzar a implementar el clasificador RNN
usando TensorFlow.
14.2.2. Implementando el modelo
Machine Translated by Google
Crear la red en Python será muy similar a la ANN. Por lo tanto, solo destacaremos
los nuevos puntos. Con la función LSTM, tenemos un nuevo argumento que es
return_sequences. Para hacerlo más fácil, si este parámetro es falso, devolveremos
una matriz bidimensional, y si es verdadero, devolveremos una matriz
tridimensional. Por lo tanto, tenemos que ponerlo en el lugar correcto. Si no usamos
nuestra función de pérdida, no tendremos ningún problema con eso, pero si
usamos nuestra función de pérdida, necesitamos usar este parámetro correctamente.
Código 14.2: clasificador RNN
#LIBAIRIAS
importar tensorflow
desde [Link] importar secuencial
desde [Link] importar Dense, LSTM
# INICIALIZACION DEL MODELO clasificador
= Sequential()
# AGREGAR CAPA LSTM
[Link](LSTM(units = 10 , return_sequences = True ,
input_shape =
(X_train_3d.shape[ 1 ],X_train_3d.shape[ 2 ],)))
# BUCLE QUE AGREGAR CAPA LSTM
por _ en el rango
( 1 ): [Link] (LSTM (unidades= 10 , return_sequences = True ))
# ÚLTIMA CAPA LSTM PERO CON return_sequences = False
[Link](LSTM(units = 10 , return_sequences = False ))
# SALIDA CAPA DENSA
[Link](Denso( 1 , activación = "sigmoide" ))
# COMPILA EL MODELO
clasificador compilar (pérdida = "binary_crossentropy" , optimizador
= "adam" )
# CAPACITACIÓN
[Link](X_tren_3d, y_tren_3d, épocas= 15 , lote_tamaño= 32
, detallado = 1 )
Machine Translated by Google
Como vemos, la RNN necesita muchos recursos. Para evitar el cálculo,
puede tomar un modelo ya entrenado en Internet y modificarlo un poco
para adaptarlo a sus datos. También puede usar GPU, CPU o TPU en
Google Colab.
14.2.3. Predicción y backtest
Ahora que tenemos nuestro algoritmo, veremos las ligeras diferencias en el
código cuando queramos hacer una predicción y una prueba retrospectiva con
una estrategia usando un RNN.
Código 14.3: Predicciones y backtest # Crear
predicciones para todo el conjunto de datos
y_pred_train = [Link](([Link]([lag, 1 ]),
[Link](X_train_3d)),axis= 0 ) y_pred_test
= [Link](( [Link]([retraso, 1 ]),
[Link](X_test_3d)),eje= 0 )
df[ "predicción" ] = [Link]((y_pred_train,y_pred_test),
eje=0 )
df[ "predicción" ] = [Link](df[ "predicción" ] == 0 , -1 , 1 )
# Calcular la estrategia
df[ "estrategia" ] = [Link](df[ "predicción" ]) * df[ "devoluciones" ]
# Prueba retrospectiva
backtest_dynamic_portfolio(df[ "estrategia" ].iloc[split+lag:])
Necesitamos agregar un vector de 0 de las longitudes de
retraso para garantizar que los datos estén en un buen lugar.
Hemos eliminado 15 datos cada día usando la función para
transformar los datos en 3D.
Como podemos ver en el backtest, es un algoritmo excelente porque el crecimiento
del capital es muy estable. Tenemos excelentes indicadores como el índice de
Sharpe de más de uno, pero tenemos una reducción del 45%; por eso veremos en
el capítulo en el que vamos a crear el
Machine Translated by Google
proyecto, cómo podemos crear una cartera de estrategias para disminuir la
volatilidad de la cartera (como en el capítulo 3 anterior sobre la optimización de
la cartera estática).
Figura 14.6: Backtest de estrategia usando predicciones RNN en
acciones de Netflix
Beta: 0,953 Alfa: 28,52 % Sharpe: 1,04 Sortino: 1,539
-------------------------------------------------- ---------------------------
VaR: 52,82 % cVaR: 66,92 % VaR/cVaR: 1,267 reducción: 44,18 %
Machine Translated by Google
En esta figura podemos ver que el crecimiento del capital está muy
bien, excepto del 2018-07 al 2019-07 con un drawdown del 45%.
14.3. regresor RNN
Esta sección explicará cómo hacer un regresor RNN y crear una
función para automatizar el edificio. Para ello, haremos una pequeña
precisión sobre la estandarización. Luego veremos una nueva función de
aprendizaje profundo llamada abandono y cómo realizar nuestra estrategia
comercial creada con el regresor RNN.
14.3.1. Precisión sobre la estandarización
Anteriormente, dijimos que la normalización no debe aplicarse al destino.
¡CIERTO! Sin embargo, al usar RNN, tanto X como Y se usarán para entrenar
el modelo. Entonces, será mejor normalizar la y para disminuir el tiempo de
cálculo. Además, más adelante tendremos que hacer la transformación
inversa en las y para obtener los valores de escala correctos para tomar
nuestras decisiones de inversión.
Código 14.4: Estandarización del objetivo
# ESTANDARIZACIÓN
sc_y = StandardScaler()
y_train_scaled = sc_y.fit_transform(y_train_reg) y_test_scaled
= sc_y.transform(y_test_reg)
Es esencial crear una nueva variable sc_y para estandarizar estos
datos y mantenerlos porque tenemos la transformada inversa una
vez que el algoritmo da predicciones.
Machine Translated by Google
14.3.2. Implementando el modelo
Esta parte explicará un nuevo concepto, la capa de abandono. Para una mejor
utilización, creamos una función RNN que nos permite crear un modelo tomando solo
algunos parámetros necesarios.
Primero, hablemos de la deserción. Es algo emocionante y muy simple. Es una capa
que añadimos al modelo, que apaga un porcentaje de las neuronas de una capa. Sin
embargo, ¿por qué queremos hacer eso?
Agregar alguna capa de abandono es muy útil de dos maneras principales:
Mejor entrenamiento : apaga algunas neuronas y obliga a las otras
a aprender más de lo habitual para que el modelo esté mejor
entrenado.
Reducir el riesgo de sobreajuste : el abandono nos permite reducir el
riesgo de sobreajuste porque apagar aleatoriamente algunas neuronas
obliga a las otras neuronas a no enfocarse en un punto.
Código 14.5: Factorizar la implementación de RNN en una función
def RNN ( número_neuronas , número_capa_oculta , forma , métricas
= "mse" , de pérdida =[ "mae" ], activación = "lineal" , optimizador =
"Adán" , pct_dropout = 0.5 ):
#LIBAIRIAS
importar tensorflow
desde [Link] importar secuencial
desde [Link] importar Dense, LSTM, Dropout
# INICIALIZACION DE LOS DATOS
modelo = Secuencial()
# ADD LSTM LAYER
[Link](LSTM(units = number_neurons, return_sequences = True
,
Machine Translated by Google
input_shape = forma))
# AGREGAR CAPA DE
ABANDONO [Link](Dropout(pct_dropout))
# BUCLE QUE AGREGAR LSTM Y CAPA DE ABANDONO
for _ en rango (number_hidden_layer):
[Link](LSTM(units = number_neurons, return_sequences =
Verdadero )) [Link](Dropout(pct_dropout))
# ÚLTIMA CAPA LSTM PERO CON return_sequences = False TO
TIENE MATRIZ 2D
[Link](LSTM(unidades = número_neuronas, retorno_secuencias
= Falso ))
# AGREGAR CAPA DE SALIDA
[Link](Abandono(pct_dropout))
# SALIDA CAPA DENSA
[Link](Dense( 1 , activación=activación))
# COMPILA EL MODELO
modelo. compilar (pérdida=pérdida, optimizador=optimizador, métricas=métricas)
modelo de vuelta
regresor = , 3 , taille = (X_tren_3d.forma[ 1
RNN( 15 ],X_tren_3d.forma[ 2 ]),
pérdida = "mse" , métricas=[ "mae" ], activación= "lineal" ,
optimizador = "adam" , pct_dropout = 0.65 )
[Link](X_tren_3d, y_tren_3d, épocas= 1 , lote_tamaño= 32 ,
detallado= 1 )
14.3.3. Predicciones y backtest
Esta parte verá cómo hacer la transformación inversa de la estandarización
y probar la estrategia comercial utilizando un regresor RNN.
Machine Translated by Google
Código 14.6: Transformación de estandarización inversa y backtest # Crear
predicciones para todo el conjunto de datos
# Transformación
inversa y_tren_sc = sc_y.inverse_transform([Link](X_train_3d))
# predicciones
y_pred_train = [Link](([Link]([lag, 1 ]),y_train_sc), eje=0 )
# Transformación
inversa y_test_sc = sc_y.inverse_transform([Link](X_test_3d))
# predicciones
y_pred_test = [Link](([Link]([retraso, 1 ]),y_test_sc),
eje=0 )
df[ "predicción" ] = [Link]((y_pred_train,y_pred_test), eje=0 )
# Calcular la estrategia
df[ "estrategia" ] = [Link](df[ "predicción" ]) * df[ "devoluciones" ]
# Prueba retrospectiva
backtest_dynamic_portfolio(df[ "estrategia" ].iloc[split+lag:])
Como se muestra en la figura 14.7, es lo mismo que para el clasificador en lugar del
abandono. Eso significa que no hay sobreajuste en el clasificador.
Figura 14.7: Backtest de estrategia usando predicciones RNN en acciones
de Netflix
Beta: 0,953 Alfa: 28,52 % Sharpe: 1,04 Sortino: 1,539
-------------------------------------------------- ---------------------------
VaR: 52,82 % cVaR: 66,92 % VaR/cVaR: 1,267 reducción: 44,18 %
Machine Translated by Google
La estrategia tiene los mismos rendimientos que el clasificador RNN, lo que puede ser
posible porque se entrena con los mismos datos.
Antes de cerrar este capítulo, hay algunos puntos sobre el aprendizaje profundo que
deben destacarse:
Los algoritmos necesitan muchos datos , casi 50.000 o 100.000 como
mínimo, para ser entrenados aunque hayamos tomado una base de datos diminuta
Machine Translated by Google
aquí.
Los algoritmos de aprendizaje profundo son los más potentes pero
también los más difíciles de entrenar debido a la cantidad de hiperparámetros.
El riesgo de sobreajuste aumenta con el número de parámetros. Entonces,
las redes neuronales están muy afectadas por estos problemas.
Resumen
Los datos deben ser tridimensionales para entrenar una RNN porque
cada observación es una matriz bidimensional.
La red neuronal Recurrente es útil cuando trabajamos en
series de tiempo.
La capa de abandono nos permite desactivar algunos neurales para
optimizar el entrenamiento y evitar el sobreajuste.
Aplicación Live Trading and Screener
Este código se basa en la clase creada en el anexo: MetaTrader
Código 14.7: Comercio de aplicaciones / Regresor RNN
desde MT5 importar *
importar numpy como np
importar pandas como pd
importar advertencias
[Link]( "ignorar" ) tiempo
de importación importar pickle de joblib volcado
de importación , cargar sistema operativo de
importación
Machine Translated by Google
desde [Link] importar StandardScaler
desde [Link] importar Sequential
desde [Link] importar Dense, LSTM, Dropout
= ""
sendero # Ex:
C:/Desktop/Python_for_finance_and_algorithmic_trading/
CapítuloN/
def X_3d_RNN ( X_s , y_s , retraso ):
# Verificación simple
si len (X_s) != len (y_s):
print ( "Advertencias" )
# Crea el X_train
X_train = [] para la
variable en el rango ( 0 , X_s.shape[ 1 ]): X =
[] para i en el rango (lag, X_s.shape[ 0 ]):
[Link](X_s[i- retraso:i, variable])
Tren_X.append(X)
Tren_X, [Link](tren_X)
Tren_X = [Link]([Link](X_tren, 0 , 1 ), 1 , 2 )
# Crea el y_train
y_train = [] para i en
el rango (lag, y_s.shape[ 0 ]):
y_train.append(y_s[i, :].reshape( -1 , 1 ).transponer())
y_train = [Link](y_train, axis= 0 )
return X_train, y_train
def RNN ():
# Crea el modelo
número_capa_oculta = 15
número_neuronas = 10
pérdida = "mse"
métricas=[ "mae" ]
activación= "lineal"
optimizador = "adam"
pct_dropout = 0.5
Machine Translated by Google
# INICIALIZACIÓN DEL DATO modelo =
Secuencial()
# AGREGAR CAPA LSTM
[Link](LSTM(unidades = numero_neuronas, return_sequences = True ,
input_shape = ( 15 , 5 ,)))
# AGREGAR CAPA DE
ABANDONO [Link](Dropout(pct_dropout))
# BUCLE QUE AGREGAR LSTM Y CAPA DE ABANDONO
for _ en rango (number_hidden_layer):
[Link](LSTM(units = number_neurons, return_sequences = True ))
[Link](Dropout(pct_dropout))
# ÚLTIMA CAPA LSTM PERO CON return_sequences = False
[Link](LSTM(unidades = número_neuronas, retorno_secuencias =
Falso ))
# AGREGAR CAPA DE SALIDA
[Link](Abandono(pct_dropout))
# SALIDA CAPA DENSA
[Link](Dense( 1 , activación=activación))
# COMPILA EL MODELO
modelo. compilar (pérdida=pérdida, optimizador=optimizador,
métricas=métricas)
modelo de vuelta
def create_model_weights ( símbolo ):
""" Pesos para la regresión lineal sobre el cambio porcentual"""
# Importar los datos
data = MT5.get_data(símbolo, 3500 )[[ "cerrar" ]].pct_change( 1 )
# Crear nueva variable
[Link] = [ "devoluciones" ]
# Características datos de
ingeniería[ "devuelve t-1" ] = datos[[ "devuelve" ]].shift( 1 )
Machine Translated by Google
# Media de retornos
data[ "la media devuelve 15" ] = data[[ "returns" ]].rolling( 15 ).mean() .shift( 1 )
data[ "mean devuelve 60" ] = data[[ "returns" ]].rolling
( 60 ).media() .desplazamiento( 1 )
# Volatilidad de los retornos
data["volatilidad devuelve 15" ] = data[[ "devoluciones" ]].rolling( 15 ).std() .shift( 1 )
data["volatilidad devuelve 60" ] = data[[ "devoluciones" ]].rolling ( 60 ).std() .shift( 1 )
# Dividir los datos
data = [Link]()
split = int( 0.80 * len (datos))
# Creación de conjuntos de trenes
Tren_X = datos[[ "devuelve t-1" , "media devuelve 15" , "rendimientos medios
60" ,
"la volatilidad devuelve ,
15" "la volatilidad devuelve 60" ]].iloc[:split]
y_tren = np. round (datos[[ "devoluciones" ]].iloc[:split]+ 0.5 )
# Inicializar la clase sc
= StandardScaler()
# Estandarizar los datos
X_train = sc.fit_transform(X_train)
retraso =
15 tren_X, tren_y = X_3d_RNN(tren_X, tren_y.valores, 15 )
alg = RNN()
# CAPACITACIÓN
Machine Translated by Google
[Link](X_tren, y_tren, épocas= 1 , lote_tamaño= 32 , detallado= 1
)
# Guardar el modelo
print ( "Entrena al modelo porque no existen pesos" )
alg.save_weights([Link](ruta, f "Modelos/RNN_reg_
{símbolo} " ))
def RNN_reg_sig ( símbolo ):
""" Función para predecir el valor de mañana usando el modelo ARIMA"""
# Crea los pesos si no hay en la carpeta
pruebe : alg =
RNN() alg.load_weights([Link](ruta, f "Modelos/RNN_reg_
{símbolo} " ))
excepto :
create_model_weights(símbolo) alg
= RNN() alg.load_weights([Link](ruta,
f "Modelos/RNN_reg_ {símbolo} " ))
# Tomar el último porcentaje de cambio de
datos = MT5.get_data(símbolo, 3500 )[[ "cerrar" ]].pct_change( 1 )
# Crear nueva variable
[Link] = [ "devoluciones" ]
# Características datos de
ingeniería[ "devuelve t-1" ] = datos[[ "devuelve" ]].shift( 1 )
# Media de retornos
data[ "la media devuelve 15" ] = data[[ "returns" ]].rolling( 15 ).mean() .shift( 1 )
data[ "mean devuelve 60" ] = data[[ "returns" ]].rolling ( 60 ).media() .desplazamiento( 1 )
Machine Translated by Google
# Volatilidad de los retornos
data["volatilidad devuelve 15" ] =
data[[ "devoluciones" ]].rolling( 15 ).std() .shift( 1 ) data["volatilidad devuelve
60" ] = data[[ "devoluciones" ]].rolling ( 60 ).std() .shift( 1 )
X = datos[[ "devuelve t-1" , "media devuelve 15" , "media devuelve 60" ,
"la volatilidad devuelve ,
15" "la volatilidad devuelve 60" ]]
# Inicializar la clase sc
= StandardScaler()
# Estandarizar los datos
X = sc.fit_transform(X)
y = datos[[ "devuelve t-1" ]]
X, _ = X_3d_RNN(X, [Link], 15 )
X = X[ -1 :,:,:]
# Encuentra la
señal predicción = [Link](X)
comprar = predicción[ 0 ][ 0 ] > 0
vender = no comprar
volver comprar, vender
# True = Live Trading y Flse = Screener live =
True
if live:
current_account_info = mt5.account_info() print
( "-------------------------------------- ----------------------" )
Machine Translated by Google
imprimir ( "Fecha: " , [Link]().strftime( "%Y-%m-%d
%H:%M:%S" ))
print ( f "Saldo: {info_cuenta_actual.saldo} USD, \t"
f "Patrimonio: {current_account_info.equity} USD, \t" f
"Beneficio: {current_account_info.profit} USD" )
imprimir ( "----------------------------------------------- ------------" )
info_pedido = {
"Netflix" : [ "Netflix_Inc_(NFLX.O)" , 1.00 ]
}
inicio = [Link]().strftime( "%H:%M:%S" ) #"23:59:59"
mientras que es cierto :
# Verificación para el lanzamiento
si [Link]().weekday() no está en ( 5 , 1 ):
is_time = [Link]().strftime( "%H:%M:%S" ) == iniciar otra cosa :
es_tiempo = Falso
# Inicie el algoritmo si
es_tiempo:
# Abra las
operaciones de activos en info_order.keys():
# Inicializar el símbolo de
entrada = info_pedido[activo][ 0 ] lote
= info_pedido[activo][ 1 ]
# Crear las señales
comprar, vender = RNN_reg_sig(símbolo)
# Ejecuta el algoritmo si
está activo:
[Link](símbolo, comprar, vender, lote)
más :
imprimir ( f "Símbolo: {símbolo} \t"
Machine Translated by Google
f "Comprar: {comprar}
\t" f "Vender: {vender}
" ) [Link]( 1 )
El parámetro en vivo establece el comercio en vivo (en vivo
= Verdadero) o el modo de filtro (en vivo = Falso).
Machine Translated by Google
Capítulo 15: Bono / Ejemplo de RNN
con CNN (RCNN)
En este bono, veremos un ejemplo de un algoritmo avanzado de aprendizaje
profundo, el RCNN, que combina un 1d-CNN [17] y un RNN. Nos permite quedarnos
con lo mejor de los dos modelos.
De hecho, el RNN es bueno para encontrar relaciones en el tiempo porque es un
algoritmo de análisis de series de tiempo. Al mismo tiempo, CNN puede capturar
más funciones porque tiene un método diferente para adaptarse.
15.1. Intuición de CNN
La especialidad de la red neuronal convolucional (CNN) es que funciona con filtros.
Los filtros en una capa CNN son como el número de neuronas con un RNN. Cuantos
más filtros hay, más complejo es el algoritmo. CNN se utiliza principalmente para la
detección de imágenes. Explicaremos un poco la noción usando el ejemplo de una
imagen.
Figura 15.1: Intuición detrás de CNN
En esta figura podemos ver la representación del funcionamiento de CNN .
M es la longitud de la franja, que es un parámetro importante.
Si la franja es demasiado pequeña, nuestro algoritmo tarda demasiado
en entrenarse, lo que aumenta el riesgo de sobreajuste. No olvides que el
Machine Translated by Google
cuanto más aumente la complejidad, más aumentará el riesgo de
sobreajuste.
N es el número de filtros. Cuantos más filtros haya, más potente y
llevará tiempo entrenar.
La capa convolucional es creada por la función conv1D o conv2D de
TensorFlow.
La capa de agrupación nos permite reducir la forma, mientras que no
la usaremos en nuestro modelo.
15.2. Crear un RCNN
Cada red neuronal tiene muchas estructuras, particularmente esta, porque las
combina. Usaremos una CNN unidimensional porque necesita datos
tridimensionales como la RNN.
Figura 15.2: Descripción del modelo
Nuestro modelo es un poco más complejo que el otro. De hecho, combina RNN,
CNN y abandono .
Código 15.1: RCNN
def RCNN ( número_neuronas , número_capa_oculta , forma , métricas
= "mse" , de pérdida =[ "mae" ], activación = "lineal" , optimizador =
"Adán" , pct_dropout = 0.5 ):
Machine Translated by Google
#LIBAIRIAS
importar tensorflow
desde [Link] importar secuencial
desde [Link] importar Conv1D, Dense, LSTM,
Dropout
# INICIALIZACION DE LOS DATOS
modelo = Secuencial()
# AGREGAR CAPA LSTM
[Link](LSTM(unidades = numero_neuronas, retorno_secuencias
Verdadero
= , entrada_forma = forma))
# AGREGAR CAPA DE SALIDA
[Link](Abandono(pct_dropout))
# BUCLE QUE AGREGAR LSTM Y CAPA DE ABANDONO
por _ en el rango (number_hidden_layer):
[Link](Conv1D( 64 , 3 , activación = 'relu' ))
[Link](LSTM(units = number_neurons, return_sequences = True ))
[Link](Dropout(pct_dropout))
# ÚLTIMA CAPA LSTM PERO CON return_sequences = False
[Link](LSTM(units = number_neurons, return_sequences = False ))
# SALIDA CAPA DENSA
[Link](Dense( 1 , activación=activación))
# COMPILA EL MODELO
modelo. compilar (pérdida=pérdida, optimizador=optimizador, métricas=métricas)
modelo de vuelta
regresor = , 3 , forma = (X_tren_3d.forma[ 1
RNN( 15 ],X_tren_3d.forma[ 2 ]),
pérdida = "mse" , métricas=[ "mae" ], activación= "lineal" ,
optimizador = "adam" , pct_dropout = 0.65 )
[Link](X_tren_3d, y_tren_3d, épocas= 1 , lote_tamaño= 32 ,
detallado= 1 )
Machine Translated by Google
15.3. prueba retrospectiva
En esta sección, probaremos la estrategia comercial basada en un RCNN.
Para eso usaremos la misma función que se creó anteriormente en el
capítulo 5.
Figura 15.3: Backtest de la estrategia usando RCNN
predicciones de Google
Beta: 1,054 Alfa: 6,37 % Sharpe: 0,721 Sortino: 0,926
-------------------------------------------------- ---------------------------
VaR: 48,25 % cVaR: 59,27 % VaR/cVaR: 1,229 reducción: 30,79 %
Machine Translated by Google
La estrategia es buena porque las proporciones alfa, Sharpe y Sortino son
positivas. La beta está cerca de 1, lo que significa que nos correlacionamos con
los rendimientos del mercado. El drawdown es cercano al 30%, lo cual es alto
pero bueno para una estrategia sin combinar otras estrategias.
Machine Translated by Google
Capítulo 16: Proyecto completo de la vida real
En el capítulo anterior, hemos visto muchas técnicas y algoritmos de muchos
campos. Veremos que para implementar un algoritmo de comercio cuantitativo
sólido, la clave es usar todos estos campos simultáneamente para aprovechar cada
uno. Combinaremos el aprendizaje automático para crear algoritmos predictivos,
estadísticas para hacer ingeniería de características y gestión de carteras para
combinar nuestras estrategias para disminuir el riesgo de esta inversión.
Primero, buscaremos muchos activos para nuestra estrategia. Luego seleccionaremos
los mejores activos usando un criterio de ratio de Sharpe. Además, encontraremos el
stop loss, el take profit y el apalancamiento óptimos.
16.1. Preparación de los datos
En todos los proyectos en finanzas, los datos son lo más importante. El algoritmo
más poderoso no puede predecir si le pedimos que prediga el precio de las
acciones de Google usando la consumación del helado. Es exagerado, pero
debemos preparar los datos con la mayor atención posible porque podemos perder
dinero por un error en ellos. Por lo general, la preparación de datos es del 60 al 80%
del proyecto.
16.1.1. Importar los datos
El objetivo de la estrategia es probar algunos algoritmos en muchos activos.
El punto es que ya sabemos cómo importar datos usando un símbolo.
Entonces, ¿por qué hay una parte para explicar eso? Queremos trabajar con
todos los activos disponibles en nuestro corredor. Hay más de 2000. Por lo tanto,
necesitamos ejecutar un pequeño código para tenerlos todos.
Machine Translated by Google
Además, trabajaremos directamente con los datos de nuestro bróker porque
necesitamos estar lo más cerca posible del mercado. De hecho, en el capítulo anterior,
exploramos cada técnica utilizando datos de Yahoo.
De hecho, el punto era explicar que las técnicas no crean una estrategia en los capítulos
anteriores. Sin embargo, cuando trabajamos en un proyecto de la vida real, es mejor tener
los datos del corredor usando la plataforma MetaTrader 5 porque está más cerca de la
realidad.
Código 16.1: Cómo desechar todo el nombre del símbolo
# INICIALIZAR EL DISPOSITIVO
[Link]()
# Crear símbolos de
lista vacía = []
sectores = []
descripciones = []
# Obtenga la información para todos los símbolos
información_símbolos = mt5.símbolos_get( ) 1
# Tupla para
listar lista_información_símbolos = lista(información_símbolos) 2
# Extraiga el nombre del símbolo para
el elemento en symbols_information_list:
sí[Link](lista(elemento)[ -3 ]) 3
[Link](lista(elemento)[ -1 ].split( "\\" )[ 0 ]) 4
[Link](lista(elemento)[ -7 ]) 5
# Crear una información
de trama de datos = [Link]([símbolos, sectores, descripciones], índice=[
"Símbolo" , "Sector" , "Descripción" ]).transpose() 6
1 La función symbols_get() nos da la información de todos los
símbolos que el bróker nos ofrece para operar.
2 symbols_get() devuelve una tupla, por lo que debemos
transformarla en una lista para trabajar con este objeto.
Machine Translated by Google
3 Tome el símbolo del activo.
4 Tome el camino para tener el sector del activo.
5 Tome una descripción del activo.
6 Coloque toda la información en un marco de datos.
Figura 16.1: Extracción de los símbolos y su sector
Símbolo Sector Descripción
AUDUSD Mayores de FX Vs australianos
A NOSOTROS
EURUSD FX Majors EE. UU. vs euro
Podemos ver que hemos desechado todos los símbolos con su sector.
Por lo tanto, es fácil de hacer si queremos probar un algoritmo solo en un sector.
Seleccionar un sector puede ser interesante si creamos un algoritmo que utilice
bagging sobre activos.
Nuestra estrategia tomará solo los activos con un margen exiguo. Es una elección personal.
Podemos elegir otro criterio de selección de activos, como la volatilidad del activo.
Código 16.2: Encuentre el activo con menor margen # Crear un
margen de lista vacío = []
# Computze el margen para
el símbolo en las informaciones [ "Símbolo" ]:
intente : preguntar = mt5.symbol_info_tick(símbolo).pedir
oferta = mt5.symbol_info_tick(símbolo).oferta
[Link]((preguntar - ofertar) / preguntar )
excepto :
[Link] ( Ninguno )
Machine Translated by Google
# Tome los activos con el diferencial < 0.07%
informations[ "Spread" ] = spread
lower_spread_asset = [Link]().\
loc[informations[ "Spread" ]< 0.0007 ]
16.1.2. Ingeniería de características
Como se dijo anteriormente, los datos son una parte esencial del proyecto.
Por lo tanto, no podemos darle al algoritmo solo los datos OHLC porque es
insuficiente. Necesitamos ayudar a nuestro algoritmo. Para ello, utilizaremos
el método de ingeniería de las características anteriores. De hecho, crearemos
algunos promedios móviles y alguna volatilidad móvil en la función. Luego,
aplicaremos un algoritmo PCA al conjunto de datos para reducir el número de
columnas.
Código 16.3: Crear nuevas funciones y aplicar PCA
def características_engeeniring ( df ):
""" Esta función que crea todos los conjuntos necesarios para los algoritmos"""
# Permite llamar a las variables fuera de la función
global X_train
global X_test
global y_train_reg
global y_train_cla
global X_train_scaled
global X_test_scaled
global split_train_test
global split_test_valid
global X_valid global
X_valid_scaled global
X_train_pca global
X_test_pca global
X_val_pca
Machine Translated by Google
# Crear nuestras propias métricas para calcular la estrategia
devuelve df[ "devoluciones" ] = ((df[ "cerrar" ] - df[ "cerrar" ].shift( 1 )) /
df[ "cerrar" ]) .shift( 1 ) df[ "lento" ] = ((df[ "bajo" ] - df[ "cerrar" ].shift( 1 )) /
df[ "cerrar" ] .shift( 1 )).shift( 1 ) df[" sAlto" ] = ((df[ "alto" ] - df[ "cerrar" ].shift( 1 )) /
df[
"cerrar" ]
.cambio( 1 )).cambio( 1 )
# Ingeniería de funciones
df[ "devoluciones t-1" ] = df[[ "devoluciones" ]].shift( 1 )
# Media de retornos
df[ "media devuelve 15" ] = df[[ "devuelve" ]].rolling( 15
).media().desplazamiento( 1 )
df[ "media devuelve 60" ] = df[[ "devuelve" ]].rolling( 60
).media().desplazamiento( 1 )
# Volatilidad de los
rendimientos df[ "volatilidad devuelve 15" ] =
df[[ "devoluciones" ]].rolling( 15 ).std() .shift( 1 ) df[ "volatilidad devuelve 60" ]
= df[[ "devoluciones" ]].rodando( 60 ).std() .shift( 1 )
# Elimina los valores que
faltan df = [Link]()
# Porcentaje de división del
conjunto de trenes = int( 0.80 * len (df))
list_x = [ "devuelve t-1" , "media devuelve 15" , "media devuelve 60" ,
"volatilidad devuelve 15" ,
"volatilidad devuelve 60" ]
split_train_test = int( 0.70 * len (df))
split_test_valid = int( 0.90 * len (df))
Machine Translated by Google
# Creación de conjuntos de trenes
X_tren = df[lista_x].iloc[:split_train_test]
y_train_reg = df[[ "devoluciones" ]].iloc[:split_train_test]
y_tren_cla = np. ronda (df[[ "devoluciones" ]].iloc[:split_train_test]+ 0.5 )
# Creación del conjunto de pruebas
X_test = df[lista_x].iloc[split_train_test:split_test_valid]
# Creación del conjunto de pruebas
X_val = df[lista_x].iloc[split_test_valid:]
#NORMALIZACION
# Importar la clase
desde [Link] import StandardScaler
# Inicializar la clase
sc = StandardScaler()
# Estandarizar los
datos X_train_scaled = sc.fit_transform(X_train)
X_test_scaled = [Link](X_test)
X_val_scaled = [Link](X_val)
#PCA
# Importa la clase
desde [Link] import PCA
# Inicializar la clase
pca = PCA(n_componentes= 3 )
# Aplicar el PCA
X_train_pca = pca.fit_transform(X_train_scaled)
X_test_pca = [Link](X_test_scaled)
X_val_pca = [Link](X_val_scaled)
Machine Translated by Google
Si la función modifica los valores de la variable global, entonces debe
declararse precediéndola con la palabra clave global.
En la siguiente sección, entrenaremos todos los algoritmos con los
mismos datos, como en el capítulo 10. Es mejor entrenar diferentes
modelos con características diferentes (independientes) para obtener
mejores resultados. Entonces, en su proyecto, puede encontrar las
mejores características para cada activo, pero lleva mucho tiempo.
16.1.3. Conjuntos de entrenamiento, prueba y validación
En los capítulos anteriores, para probar el rendimiento de nuestros algoritmos, hemos
utilizado el conjunto de entrenamiento para entrenar el algoritmo y el conjunto de prueba
para probar su rendimiento. En un proyecto más significativo, necesitamos crear tres
conjuntos de datos: el conjunto de tren, el conjunto de prueba y el conjunto de validación.
Este proyecto debe tener tres conjuntos porque trabajamos con modelos predictivos, y
necesitamos un conjunto para entrenarlo y dos conjuntos para trabajar con técnicas de
administración de cartera. Veamos en la figura 14.3 la utilidad de cada conjunto en nuestro
proyecto.
Conjunto de entrenamiento: Nos permite entrenar los modelos predictivos. No
entrenamos la asignación óptima de cartera con el conjunto de trenes porque
las predicciones en el conjunto de trenes no son significativas (porque el algoritmo
ya conoce los datos porque se ajusta a ellos).
Conjunto de prueba: Nos permite encontrar los mejores modelos predictivos
sobre los datos desconocidos. Luego, debido a que los rendimientos de la
estrategia basada en las predicciones son significativos aquí (porque el algoritmo
no conoce los datos antes), elegimos los mejores modelos (con el criterio de su
elección). Entonces, tenemos nuestro mejor
Machine Translated by Google
modelos Podemos encontrar la asignación de cartera óptima entre nuestras n mejores
estrategias (solo en los rendimientos del conjunto de prueba).
Conjunto de validación: ahora tenemos los mejores modelos y la mejor asignación de
nuestro capital entre los modelos (la mejor asignación de cartera). Podemos realizar una
prueba retrospectiva de la cartera con estos datos anónimos.
Figura 16.2: Utilidad de cada conjunto de datos
Podemos ver un pequeño resumen del proceso de decisión para encontrar la mejor cartera de
estrategias comerciales.
16.2. Modelando la estrategia
Hemos preparado muchas funciones para los datos: importación, ingeniería de características y
transformación. Esta sección tiene como objetivo encontrar activos con un margen bajo que no
estén sujetos al mercado de eficiencia débil.
En primer lugar, encontraremos las mejores estrategias utilizando un criterio de ratio de Sharpe.
Luego, tomaremos las estrategias más rentables y usaremos una votación
Machine Translated by Google
método en el algoritmo. Además, utilizaremos un método de cartera en los datos del
conjunto de prueba para encontrar la mejor asignación en nuestras estrategias de cartera.
16.2.1. Encuentre los mejores activos
Tomaremos los símbolos con un margen inferior a nuestro umbral de margen del 0,07 %.
Luego, calcularemos la relación de Sharpe de una estrategia comercial creada
utilizando cada algoritmo de aprendizaje automático. Además, tomamos la estrategia
con el índice de Sharpe más alto. Usaremos solo algoritmos de clasificador para este
proyecto, pero podemos usar algoritmos de regresión en nuestro proyecto. Es lo mismo.
No podemos trabajar con algoritmos de aprendizaje profundo para
este proyecto porque algunos activos solo tienen 1000 datos.
Entonces, necesitamos usar los algoritmos apropiados: regresión
lineal, SVR y árbol de decisión.
Primero, para automatizar el funcionamiento, necesitamos crear una función que produzca
una estrategia y calcular el índice de Sharpe de esta estrategia en el conjunto de prueba. El
único parámetro requerido es el modelo que queremos usar. Si vamos a probar un algoritmo
de regresión, tenemos que usar el parámetro reg=True.
Código 16.4: Función predictora
predictor de definición ( modelo , reg = Verdadero, propagación
= 0.035 ): global df [Link](X_train, y_train_cla)
df = [Link]()
# Crear predicciones para todo el conjunto de datos
df[ "prediction" ] = [Link]([Link]((X_train,
X_test, X_valid), eje= 0 ))
Machine Translated by Google
if reg== False :
df[ "predicción" ] = [Link](df[ "predicción" ]== 0 , -1 , 1 )
# Calcular la estrategia
df[ "estrategia" ] = [Link](df[ "predicción" ]) * df[ "devoluciones" ]
devuelve = df[ "estrategia" ].iloc[split_train_test:split_test_valid]
devuelve [Link]( 252 ) * ([Link]()-(spread/100))/
[Link]()
Agregamos el margen del activo en el cálculo del índice
de Sharpe porque no todos los activos tienen el mismo
margen. Por lo tanto, cuanto más significativo sea el
diferencial de activos, más se penalizará.
Mantenga la atención en la propagación, a veces es en
porcentaje ya veces no. Por lo tanto, verifique antes de
usarlo.
Con esta función, podemos automatizar el cálculo de 450 estrategias
comerciales. De hecho, tomaremos 150 activos y probaremos 3 algoritmos
de aprendizaje automático.
Código 16.5: Automatización de las pruebas # Importar la
clase de [Link] importar SVR de [Link] importar
DecisionTreeRegressor de sklearn.linear_model importar
LinearRegression
desde tqdm importar tqdm
# Modelos
árbol = DecisionTreeRegressor(max_ depth= 6 )
svr = SVR(epsilon= 1.5 ) lin = LinearRegression()
# Inicialización
símbolos = símbolos[: 150 ] #["EURUSD", "GBPAUD"] listas =
[]
Machine Translated by Google
para símbolo en tqdm(símbolos):
prueba :
df = data(símbolo, 3500 )[[ "cerrar" ]].dropna().pct_change( 1 ).dropna() [Link]
= [ "devoluciones" ] características_engeeniring(df)
""" Árbol de decisión rgressor"""
sharpe_tree = predictor(tree, reg= True )
[Link]([símbolo, "Árbol" , sharpe_tree])
""" RVS """
sharpe_svr = predictor(svr, reg= True )
[Link]([símbolo, "SVR" , sharpe_svr])
""" Regresión lineal"""
sharpe_linreg = predictor(lin, reg= True )
[Link]([símbolo, "LinReg" , sharpe_linreg])
excepto :
pasar
Con este código hemos encontrado el ratio de Sharpe para cada estrategia.
Tomaremos el activo con la mejor relación de Sharpe y obtendremos buenos resultados
con los tres algoritmos.
Los tres algoritmos elegidos son muy diferentes. La regresión
lineal encuentra patrones lineales, la SVR los no lineales y el árbol
de decisión también tiene otra forma de ajustarlo. Entonces, si
estos tres algoritmos tienen buenos resultados, optimizamos
nuestras posibilidades de obtener mejores resultados.
Figura 16.3: Mejores activos elegidos
Activo Bitcoin JPN225 NAS100 US2000 XPTUSD
Sortino 2.9 1.6 1.2 1.1 0.7
Esta tabla muestra los mejores activos de nuestra selección con su relación de Sortino
calculada en el conjunto de prueba.
Machine Translated by Google
16.2.2. Combina los algoritmos
En el capítulo 10, hemos visto el poder del método de conjunto. Aquí, aplicaremos el
método de votación. Este método combinará los tres algoritmos anteriores: árbol de
decisión, SVC y regresión logística.
Tenemos siete activos con una excelente relación de Sharpe en el conjunto de prueba.
Antes de crear una cartera usando estas estrategias, necesitamos crear un algoritmo para
predecir cada activo. Para ello, utilizaremos un clasificador de votaciones.
Código 16.6: Implementación del clasificador de votaciones
votación def ( df , reg = True ):
""" Crear una estrategia utilizando un método de votación"""
# Importar la clase
# Importar los modelos si
reg: árbol =
DecisionTreeRegressor(max_ depth= 6 ) svr = SVR(epsilon=
1.5 ) lin = LinearRegression() vot =
VotingRegressor(estimators=[ ( 'lr' , lin), ( "tree" , tree) ,
( "svr" , svr)])
más :
tree = DecisionTreeClassifier(max_ depth= 6 ) svr = SVC()
lin = LogisticRegression()
vot = VotingClassifier(estimators=[ ( 'lr' , lin),
( "tree" , tree), ( "svr" , svr)])
# Entrenar al modelo
if reg== False :
[Link](X_train_pca, y_train_cla) else :
[Link](X_train_pca, y_train_reg)
Machine Translated by Google
# Eliminar los valores
perdidos df = [Link]()
# Crear predicciones para todo el conjunto
de datos df[ "prediction" ] = [Link]([Link]((X_train_pca,
X_test_pca, X_val_pca), axis= 0 ))
# Eliminar los valores
perdidos df = [Link]()
if reg== False :
df[ "predicción" ] = [Link](df[ "predicción" ]== 0 , -1 , 1)
# Calcular la estrategia
df[ "estrategia" ] = [Link](df[ "predicción" ]).shift( 1 ) *
df[ "devoluciones" ]
df[ "estrategia_baja" ] = [Link](df[ "predicción" ]> 0 , df[
"lento" ], -df[ "alto" ])
df[ "estrategia_alta" ] = [Link](df[ "predicción" ]> 0 , df[
"alto" ], -df[ "lento" ])
voto de retorno , df[ "estrategia" ], df[ "estrategia_baja" ], df[
"alta_estrategia" ]
También devolvemos el modelo de votación para guardarlo en una
carpeta para la implementación del algoritmo de comercio en vivo
(Anexo: Cómo guardar un modelo en scikit-learn y Tensorflow).
Como podemos ver en la figura 16.4, la rentabilidad de cada activo por sí sola no es muy
rentable, teniendo en cuenta la volatilidad de estas estrategias. La siguiente subsección aplicará
un método de cartera a las estrategias comerciales para disminuir el riesgo de inversión.
Figura 16.4.: Rendimientos acumulados de los activos de la cartera en la prueba
establecer
Machine Translated by Google
Esta figura muestra el rendimiento acumulado de cada activo de la cartera.
Como podemos ver, las estrategias son poco rentables y muy arriesgadas por sí
solas.
16.2.3. Aplicar técnicas de gestión de cartera
Tenemos siete estrategias para operar y utilizaremos técnicas de gestión de
carteras para crear una cartera con la que trabajar como una estrategia en la
siguiente sección. Además, utilizaremos el criterio de media varianza-sesgo-
curtosis porque nos permite tener una cartera menos riesgosa.
Figura 16.5: Backtest de la cartera en el conjunto de prueba
Beta: -0,144 Alfa: 27,36 % Sharpe: 0,603 Sortino: 0,954
-------------------------------------------------- ---------------------------
VaR: 66,69 % cVaR: 79,23 % VaR/cVaR: 1,188 reducción: 20,91 %
Machine Translated by Google
Esta figura nos muestra el backtest de la cartera sin apalancamiento, stop loss o
take profit. Como podemos ver, el backtest es bueno, con un alfa del 27%. Hay una
buena tendencia en la ganancia pero con alta volatilidad.
La asignación de la cartera consiste en eliminar dos activos. Así, tomamos el
31% de nuestro presupuesto de Russel 2000, el 50% de Bitcoin y el 19% de
JPN 225. El criterio considera que los demás activos son demasiado riesgosos
o no lo suficientemente rentables para entrar en la cartera. Además, el desembolso
Machine Translated by Google
permanece alto porque la mayoría de los activos subyacentes son muy volátiles.
16.3. Encuentre toma de ganancias, stop loss y apalancamiento óptimos
Como se muestra en la figura 16.6, el desempeño de la cartera es bueno porque
hemos ganado un 15% en 12 meses. La estrategia es arriesgada incluso si hemos
disminuido el riesgo (drawdown max: 20%). Hasta ahora, hemos trabajado con aprendizaje
automático para predecir el comportamiento del activo. Hemos aplicado la gestión de
carteras para disminuir el riesgo. Usaremos un método estadístico para encontrar el mejor
take profit, stop loss y apalancamiento para la estrategia.
16.3.1. Toma de ganancias óptima (tp)
El umbral de toma de ganancias de una estrategia es crítico. Puede cambiar una
estrategia no rentable en una estrategia rentable. Esta subsección verá una técnica de
búsqueda en cuadrícula para encontrar el mejor umbral de toma de ganancias. Crearemos
una función que devuelva el ratio de Sharpe en función de su umbral de toma de beneficios
para encontrar los valores óptimos.
Código 16.7: Mejor función de umbral de toma de ganancias
def encontrar_mejor_tp ( tp ):
tp = tp/ 100
# Crear el portafolio pf =
[Link]((low_portfolio, portfolio_return_test, high_portfolio),
axis= 1 ).dropna()-spread
[Link] = [ "bajo" , "Devolver" , "alto" ]
# Aplicar el tp
pf[ "Return" ] = [Link](pf[ "high" ].values>tp, tp, pf[ "Return" ].values)
Machine Translated by Google
pf[ "Retorno" ] = [Link](pf[ "Retorno" ].valores>tp, tp,
pf[ "Retorno" ].valores)
# Retorna la relación
aguda return [Link]( 252 )*pf[ "Return" ].mean()/pf[ "Return" ].std()
[Link]([find_best_tp(tp) para tp en [Link]( 1.5 )],, 3 , 10
10 ), columnas=[ "Sharpe" ]) 1.5 , 3 ,
índice=[Link](
Reemplazamos el retorno por la toma de ganancias cuando
el máximo del día está por encima del umbral tp. Hacemos lo
mismo con los retornos porque a veces, en la vida real, hay
problemas en los datos (alto < cierre, por ejemplo).
Usando esta función, convergeremos a un tp de 0.
Sin embargo, el umbral de mejor beneficio no considera el
intercambio, una penalización o una bonificación otorgada por
el corredor para incitar a las personas a ir de cierta manera. Si
el tp es muy bajo en el backtest, tendrá una estrategia rentable,
pero el swap se llevará todas sus ganancias en la vida real. Es
necesario mantener un umbral de toma de ganancias lo
suficientemente alto.
Con nuestro cálculo, hemos encontrado un umbral óptimo de obtención de
beneficios del 2,1 % en el conjunto de prueba con un índice de Sharpe de 3,7 en el
período de validación, pero menor en la vida real porque hay tarifas adicionales que
no podemos considerar con precisión. Por lo tanto, el 40 % en 9 meses del período
de validación no significa que debamos poner en producción con 100 000 $ ahora.
Necesitamos ingresar una cuenta de demostración para encontrar los mejores
parámetros de la vida real para nuestras estrategias y asegurarnos de que no
haya problemas en nuestros cálculos.
16.3.2. Stop loss óptimo (sl)
Machine Translated by Google
Anteriormente hemos visto cómo ganar dinero, pero la utilidad del stop loss es evitar perder
dinero. En esta subsección, solo crearemos una estrategia con un stop loss porque no podemos
combinar tp y sl con los datos diarios (consulte el capítulo 6). De hecho, no podemos decir qué
umbral se pasa primero.
Usando la función find_best_sl, vamos a encontrar el mejor sl. Además,
veremos una convergencia del ratio de Sharpe después del 9,6% de sl.
Significa que no hay valores después de este punto. Por lo tanto,
podemos poner este umbral en nuestra estrategia porque necesitamos
un sl en el comercio, y este umbral nunca se toca en la prueba.
establecer.
Código 16.7: encuentra el mejor umbral de stop loss
def encontrar_mejor_sl ( sl ):
sl = sl/ 100
# Crear el portafolio
pf = [Link]((low_portfolio, portfolio_return_test,
high_portfolio),axis= 1 ).dropna()-spread
[Link] = [ "low" , "Devolver" , "alto" ]
# Aplicar el sl
pf[ "Return" ] = [Link](pf[ "low" ].values<-sl, -sl, pf[ "Return" ].values)
pf[ "Return" ] = [Link]( pf[ "Retorno" ].valores<-sl, -sl,
pf[ "Retorno" ].valores)
# Retorna la relación
aguda return [Link]( 252 )*pf[ "Return" ].mean()/pf[ "Return" ].std()
[Link]([find_best_sl(sl) para sl en [Link]( 3 , 10 , 30 )],
índice=[Link]( 3 , 10 , 30 ), columnas=[ "Sharpe" ])
Machine Translated by Google
Entonces, tenemos un tp en 2.1% y un sl en 9.6% para nuestra estrategia. Solo falta
apalancamiento para optimizar la ganancia de la estrategia.
16.3.3. Apalancamiento óptimo
El apalancamiento multiplica nuestro poder de inversión y nuestras ganancias. Sin embargo,
también multiplica nuestro riesgo de la misma manera. Si somos nuevos en el comercio,
debemos dominar esta herramienta y comprender cómo usarla de manera efectiva.
Dependiendo de nuestro nivel de aversión al riesgo, hay varias formas de determinar el mejor
apalancamiento a utilizar. Uno de los más conocidos es el criterio de Kelly.
Usaremos otro método: el método de reducción. En finanzas, todas las personas son únicas,
por lo que no puede ser un método para encontrar el mejor apalancamiento porque depende de
la aversión al riesgo de cada inversor.
El método de reducción es fácil de calcular, tomamos el
reducción máxima de nuestra estrategia sin apalancamiento ( ), y nosotros
debemos saber la reducción máxima que queremos (el ). Después
apalancamiento es:
Entonces, supongamos que trabajamos con nuestra estrategia usando 2.1% para el umbral
tp y 9% para el sl. En ese caso, queremos una reducción máxima del 15% porque no somos
amantes del riesgo, y la reducción máxima es del 10%. Entonces el apalancamiento de la
estrategia es 15/10 = 1,5.
Disponemos de todos los hiperparámetros financieros de la estrategia. Umbral de obtención
de beneficios del 2,1 %, umbral de stop loss del 9 % y apalancamiento óptimo del 1,5
Machine Translated by Google
Figura 16.6: Backtest de la cartera con apalancamiento, sl y tp
Beta: -0,174 Alfa: 93,37 %. Sharpe: 2.178 Sortino: 2.529
-------------------------------------------------- ---------------------------
VaR: 5,95 %. cVaR: 20,88 % VaR/cVaR: 3,508 disposición: 13,32 %
Machine Translated by Google
¿Cómo mejorar el proyecto?
Use ticks para hacer el backtest para encontrar mejores combinaciones
entre la toma de ganancias y el umbral de stop-loss.
Use ticks para calcular el diferencial en el tiempo y no en un día para
seleccionar el activo porque no es representativo.
Use ticks para trabajar con stop loss subsiguientes.
Intente utilizar el embolsado de activos en un algoritmo de aprendizaje profundo.
Pruebe con otro criterio que no sea el diferencial para seleccionar los activos.
Ajustar el apalancamiento en función del cálculo del interés
Trailing stop loss para optimizar la ganancia
Aplicación Live Trading and Screener
Este código se basa en la clase creada en el anexo: MetaTrader
Código 16.6: Comercio de aplicaciones / Proyecto
de MT5 importar *
importar numpy como
np importar pandas
como pd importar
advertencias
[Link]( "ignorar" )
de [Link] importar SVC de [Link] importar
DecisionTreeClassifier de sklearn.linear_model importar LogisticRegression
tiempo de
importación de [Link] importar
VotingClassifier importar pickle de joblib importar
volcar , cargar
Machine Translated by Google
importar
sistema operativo desde [Link] importar StandardScaler
""
sendero = # Ex:
C:/Desktop/Python_for_finance_and_algorithmic_trading/
CapítuloN/
def create_model_weights ( símbolo ):
""" Pesos para la regresión lineal sobre el cambio porcentual"""
# Importar los datos
data = MT5.get_data(símbolo, 3500 )[[ "cerrar" ]].pct_change( 1 )
# Crear nueva variable
[Link] = [ "devoluciones" ]
# Características datos de
ingeniería[ "devuelve t-1" ] = datos[[ "devuelve" ]].shift( 1 )
# Media de retornos
data[ "la media devuelve 15" ] = data[[ "returns" ]].rolling( 15 ).mean() .shift( 1 )
data[ "mean devuelve 60" ] = data[[ "returns" ]].rolling ( 60 ).media() .desplazamiento( 1 )
# Volatilidad de los retornos
data["volatilidad devuelve 15" ] = data[[ "devoluciones" ]].rolling( 15 ).std() .shift( 1 )
data["volatilidad devuelve 60" ] = data[[ "devoluciones" ]].rolling ( 60 ).std() .shift( 1 )
# Dividir los datos
data = [Link]()
split = int( 0.80 * len (datos))
# Creación de conjuntos de trenes
Tren_X = datos[[ "devuelve t-1" , "media devuelve 15" , "rendimientos medios
60" ,
Machine Translated by Google
"la volatilidad devuelve ,
15" "la volatilidad devuelve 60" ]].iloc[:split]
y_tren = np. round (datos[[ "devoluciones" ]].iloc[:split]+ 0.5 )
sc = escalador estándar()
tren_X = sc.fit_transform(tren_X)
# Crea el modelo
tree = DecisionTreeClassifier(max_ depth= 6 ) svr =
SVC() lin = LogisticRegression()
alg = VotingClassifier(estimators=[ ( 'lr' ,
lin), ( "tree" , tree), ( "svr" , svr)])
# Ajustar el
modelo [Link](X_train, y_train)
# Guardar el modelo
alg_var = [Link](alg)
alg_pickel = [Link](alg_var)
dump(alg_pickel ,[Link](ruta, f "Modelos/ {símbolo} _reg.joblib" ))
def vot_cla_sig ( símbolo ):
""" Función para predecir el valor de mañana usando el modelo ARIMA"""
# Crea los pesos si no hay en la carpeta
prueba :
alg = load([Link](ruta, f "Modelos/ {símbolo} _reg.joblib"
))
excepto :
create_model_weights(símbolo) alg
= load([Link](ruta, f "Modelos/ {símbolo} _reg.joblib"
))
# Tomar el último porcentaje de cambio de
datos = MT5.get_data(símbolo, 3500 )[[ "cerrar" ]].pct_change( 1 )
# Crear nueva variable
Machine Translated by Google
[Link] = [ "devoluciones" ]
# Características datos de
ingeniería[ "devuelve t-1" ] = datos[[ "devuelve" ]].shift( 1 )
# Media de retornos
data[ "la media devuelve 15" ] = data[[ "returns" ]].rolling( 15 ).mean() .shift( 1 )
data[ "mean devuelve 60" ] = data[[ "returns" ]].rolling
( 60 ).media() .desplazamiento( 1 )
# Volatilidad de los retornos
data["volatilidad devuelve 15" ] = data[[ "devoluciones" ]].rolling( 15 ).std() .shift( 1 )
data["volatilidad devuelve 60" ] = data[[ "devoluciones" ]].rolling ( 60 ).std() .shift( 1 )
X = datos[[ "devuelve t-1" , "media devuelve 15" , "media devuelve 60" ,
"volatilidad devuelve 15" ,
"volatilidad devuelve 60" ]].iloc[ -1 :,:].values
# Encuentra la
señal predicción = [Link](X)
predicción = [Link](prediction== 0 , -1 , 1)
comprar = predicción[ 0 ] > 0 vender = no
comprar
volver comprar, vender
# Verdadero = Comercio en vivo y Falso = Screener en
vivo = Verdadero
if live:
current_account_info = mt5.account_info() print
( "-------------------------------------- ----------------------" )
Machine Translated by Google
imprimir ( "Fecha: " , [Link]().strftime( "%Y-%m-%d
%H:%M:%S" ))
print ( f "Saldo: {info_cuenta_actual.saldo} USD, \t"
f "Patrimonio: {current_account_info.equity} USD, \t" f
"Beneficio: {current_account_info.profit} USD" )
imprimir ( "----------------------------------------------- --------------
info_pedido = {
"RUSSEL 2000" : [ "US2000" , 1.1 ],
"Bitcoin" : [ "Bitcoin" , 0.1 ],
"Nasdaq 100" : [ "NAS100" , 0.3 ]
}
inicio = [Link]().strftime( "%H:%M:%S" )
mientras que es cierto :
# Verificación para el lanzamiento
si [Link]().weekday() no está en ( 5 , 3 ):
is_time = [Link]().strftime( "%H:%M:%S" ) == inicio
#"23:59:59"
más :
es_tiempo = Falso
# Inicie el algoritmo si
es_tiempo:
# Abra las
operaciones de activos en info_order.keys():
# Inicializar el símbolo
de entrada = info_pedido[activo][ 0 ]
lote = info_pedido[activo][ 1 ]
# Crear las señales
comprar, vender = vot_cla_sig(símbolo)
# Ejecutar el algoritmo
si está
activo: [Link] (símbolo, compra, venta, lote)
Machine Translated by Google
más :
print ( f "Símbolo: {símbolo} \t" f
"Comprar: {comprar} \t" f "Vender:
{vender} " )
[Link]( 1 )
Machine Translated by Google
Capítulo 17: De la nada al comercio en vivo
Este capítulo analiza el proceso de creación y puesta en producción de una estrategia
comercial, la gestión de una estrategia comercial en vivo y la combinación de estrategias
entre ellas.
17.1 Directrices para la creación de estrategias comerciales
Esta sección primero recapitulará todo el proceso para crear una estrategia comercial
adecuada para minimizar el riesgo de error. Luego discutiremos el plan comercial y el
diario comercial.
17.1.1 El plan comercial
Muchas personas descuidan el plan comercial, pero recuerden que muchas personas
también pierden dinero. No es una relación perfecta, pero existe una relación negativa
entre hacer un plan comercial y ser rentable.
¿Por qué? Porque el plan comercial se crea con una mente fresca antes de comenzar
a operar manualmente. Por lo tanto, será más fácil seguir el plan si tenemos nuestras
pautas al buscar durante más de 50 horas una estrategia comercial rentable. Porque
modificar el plan comercial según las dificultades no es bueno.
Como no estamos haciendo comercio manual aquí, el plan comercial será ligeramente
diferente, como ya sabemos. Un plan de trading nos dará el punto de entrada y salida con
la gestión del dinero a seguir para cada estrategia. Sin embargo, si hemos automatizado
esto, no necesitamos verificarlo para cada operación. Entonces, en el comercio algorítmico,
¿cómo se ve un plan comercial?
Necesitamos poner todas las características de la estrategia en el mismo lugar, es
decir, el rendimiento, el riesgo, cuántas operaciones queremos realizar (máximo una
operación y al menos tres operaciones en un día), qué período de tiempo queremos
usar (diariamente). , por hora, semanalmente), qué activo queremos operar (activo de
bajo margen, activo volátil), en qué mercado queremos operar (forex, acciones, cripto),
queremos estar expuestos durante la noche, etc.,
Machine Translated by Google
Figura 17.1: Componente del plan comercial
Este es un ejemplo de las diferentes cosas que podemos incorporar a nuestro plan
comercial; No es una lista exhaustiva. Siéntase libre de crear el suyo propio, de
acuerdo con sus intentos.
Para concluir, el plan comercial nos permitirá planificar qué tipo de estrategia queremos
para comenzar el proceso de investigación con tranquilidad.
Tenemos que pensar en todas las características principales de nuestra
estrategia antes de hacer la investigación. Es importante no cambiar el plan
porque no encontramos lo que buscamos; ¡sigue buscando! Encuentre una
estrategia comercial que demande, en promedio, 100 intentos.
17.1.2 El proceso de construcción de una estrategia comercial
Crear una estrategia comercial requiere disciplina, creatividad y práctica.
Tenemos que seguir varios pasos:
1. Haga un plan comercial que acepte o rechace una estrategia. Siempre
créalo antes de hacer nada, para que no tengamos que ajustar el
Machine Translated by Google
intente en el futuro si la parte de codificación es demasiado difícil.
2. Importar los datos parece fácil, pero es crucial; recuerda la cita: "basura entra, basura sale".
Por lo tanto, tenga cuidado con la fuente que usamos e importe siempre la mayor cantidad
de datos posible del corredor.
3. La parte de preprocesamiento contiene las funciones y la ingeniería de destino,
transformación como estandarización y PCA. Ayudará al algoritmo a comprender mejor la
relación entre los datos.
4. Modelar el comportamiento objetivo usando algoritmos de aprendizaje automático o
aprendizaje profundo en nuestro caso o condiciones simples si usamos solo análisis
técnico o acción del precio.
5. Hacer un backtest de la estrategia dos veces como máximo para evitar sobreajustar los
resultados y perder nuestro capital en el futuro.
6. Aplicar la predicción de acuerdo con el plan comercial durante la incubación
(condiciones de entrada y salida, take-profit, stop-loss)
7. Verifique los resultados de la incubación y compárelos con los resultados del backtest para
ver si la distribución es similar (más detalles en la siguiente sección)
8. Repita este proceso para cada estrategia.
Como podemos ver, el proceso parece sencillo, pero hemos tomado todo el libro para
explicarlo. Por lo tanto, no subestime la dificultad de este proceso; necesitaremos al menos
100 intentos para encontrar una buena estrategia (en promedio). No nos rindamos y seamos
estables en nuestro trabajo; encontrará estrategias rentables pero requiere mucho tiempo.
17.1.3 Diario de negociación
Machine Translated by Google
En las operaciones discrecionales (manuales), el diario de operaciones contiene información
sobre cada operación que realizará en el mercado: entrada y salida, obtención de beneficios,
stop-loss, tamaño de apuestas, gestión de riesgos, etc.
El objetivo es tener un diario comercial (la práctica) lo más cerca posible del plan comercial
(teoría). Sin embargo, cuando trabajemos en un proyecto de comercio algorítmico, adoptaremos
un enfoque diferente. ¿Por qué? Debido a que todos los parámetros se configuran usando el
algoritmo, no pueden cambiar. Entonces, ¿qué escribiremos en nuestro diario comercial?
Cuando trabajamos en el comercio algorítmico, también necesitamos un diario comercial,
pero para varias otras cosas:
Analice el comercio manualmente y escriba lo que piensa al respecto: puntos positivos
y negativos para corregir. Aquí hay una idea para entender mejor la utilidad: Stop-loss
por encima del soporte demasiadas veces, otra forma de colocar stop-loss.
Definir
Señales falsas después de algunas noticias No opere 1 hora antes de
algunas noticias.
Verificar la distribución de retornos entre producción y backtest y ver
que los retornos de producción son cada vez menores Actualizar la
estrategia o detenerla
Mantenga un historial del problema de codificación y cómo resolverlo; es valioso
cuando estamos en otros proyectos para resolver nuestros problemas fácilmente.
17.2 No pongas todos los huevos en la misma cesta
Pensamos que una vez que teníamos una estrategia rentable, el trabajo estaba hecho.
No, una vez que tenemos una estrategia, necesitamos crear otras para combinarlas y
encontrar una cartera sólida de estrategias comerciales.
17.2.1 Tamaño de la apuesta
Machine Translated by Google
La primera regla es que NUNCA invertiremos todo nuestro capital en una sola estrategia. Es simple, pero es
esencial. Además, hay varias reglas simples a seguir para minimizar el riesgo de perder mucho dinero:
1. Nunca arriesgue más del 1% de su capital en una operación (adapte el
volumen)
2. Dependiendo de la estrategia, detenga el algo durante el día después de 3 pérdidas o deténgalo
durante la semana después del 5% de pérdida, etc.
Si usamos interés compuesto, veamos el peligro de tomar posiciones demasiado prominentes. En la
figura 17.1, vemos que cuanto más aumenta el tamaño de la posición, más aumenta el riesgo de ser un
operador perdedor.
Figura 17.1: Posibilidades de ser un trader perdedor dependiendo del tamaño de la apuesta
Como podemos ver, si tenemos un 50 % de posibilidades de ganar un 1 % o un 50 % de
posibilidades de perder un 1 %, con una operación al día durante un año, las posibilidades de ser
un trader perdedor rondan el 52 %. Sin embargo, si aumentamos el tamaño de la apuesta del 1 % al
30 % por operación, vemos que las posibilidades de ser un operador perdedor rondan el 100 %. Es
lógico porque después de tres operaciones perdedoras consecutivas, dejó solo el 10% de nuestro capital, y
necesitaremos el 900% de las ganancias para volver a nuestra cantidad inicial.
El punto principal del tamaño de la apuesta es que es mejor usar el interés compuesto para obtener el
beneficio del crecimiento exponencial, pero debemos administrar el riesgo.
Machine Translated by Google
porque cuanto más significativa es la pérdida, más difícil es volver a la cantidad inicial,
como se muestra en la figura 17.2
Figura 17.2: Beneficio necesario para recuperar el % de la pérdida
Como podemos ver, utilizando el interés compuesto (representado por un lote dinámico en
el comercio), cuanto más grande es la pérdida, más difícil es volver a la cantidad inicial.
17.2.2 ¿Por qué crear una cartera de estrategia comercial?
Hay muchas razones para crear una cartera de estrategia comercial. La mejor manera
de crearlo es verificar activos no correlacionados o, mejor aún, una correlación negativa
entre activos.
Sobre todo, la creación de una cartera de estrategia comercial es
fundamental para reducir el riesgo de su inversión: reducción, VaR,
etc.
Principalmente, supongamos que usamos apalancamiento e interés compuesto. En ese
caso, necesitamos crear una cartera para diversificar nuestro riesgo y disminuir el riesgo de
posición (que es posible aumentando el número de estrategias comerciales). Además, las
partes de la cartera y el tamaño de la apuesta encajan muy bien porque cuanto más
añadimos estrategias comerciales a la cartera, más podemos disminuir el peso de una
estrategia en la cartera y luego crear una estrategia de inversión sólida.
El punto principal de crear una cartera de estrategia comercial es disminuir la reducción
de la cartera mientras se mantiene un rendimiento cómodo. Veamos un ejemplo.
Machine Translated by Google
Figura 17.3: Ventaja de la cartera en comparación con la estrategia individual
Como vemos, combinando la estrategia, la rentabilidad de la cartera es la media entre las
tres estrategias. Sin embargo, el punto principal es que el drawdown es muy bajo en
comparación con una estrategia individual.
17.3. Proceso de comercio en vivo
El proceso de comercio en vivo no es la parte más difícil, pero si hay un error en esto,
perderemos mucho dinero. Por lo tanto, debemos ser lo más meticulosos posible.
17.3.1. Seguridad primero
Cuando ponemos nuestra estrategia en operaciones en vivo, debemos prestar atención
a la seguridad de nuestro capital. Entonces, la mejor manera de hacerlo es colocando algunos
valores como el siguiente ejemplo:
1. Detenga el algoritmo después de una pérdida de X% en un día: será bueno
hacerlo si el algo hace algo mal, como tomar 100 posiciones simultáneamente.
Sin embargo, necesitamos realizar una prueba retrospectiva de las pérdidas
consecutivas en la distribución de un día para encontrar el mejor valor. Por
ejemplo, supongamos que vemos que solo hay un 1% de probabilidad de tener
más de dos operaciones perdedoras al día. En ese caso, podemos poner la
siguiente seguridad: “si tenemos tres operaciones perdedoras al día, detenemos
el algoritmo por el día”.
Machine Translated by Google
2. Detenga el algoritmo después de una pérdida del X% en un mes: a veces,
las condiciones del mercado pueden ser difíciles para nuestro algoritmo;
intente encontrar el mejor momento para detenerlo en el backtest y verifique
el rendimiento teniendo en cuenta que detenemos el algoritmo en algunas
situaciones de mercado.
3. Detenga el algoritmo si la reducción en el comercio en vivo se vuelve dos
veces mayor que la reducción en la incubación: es muy interesante encontrar
cuándo se debe detener un algoritmo, pero lo discutiremos más adelante
en el capítulo.
Estas tres reglas no son exhaustivas; hay muchas reglas similares diferentes para administrar
nuestro riesgo y ser un comerciante rentable.
17.3.2 Fase de incubación
Esta parte es una de las más importantes. En esta parte, comprobaremos si nuestra
estrategia comercial rentable teórica se puede poner en operaciones reales o no.
Afortunadamente, es la parte más fácil del proyecto en el lado de la programación.
Sin embargo, también es el más difícil en el aspecto psicológico. Entonces, veamos todo el
proceso en detalle:
1. Ponemos nuestra estrategia en incubación en una cuenta de demostración o
con un capital muy pequeño en el comercio en vivo para comprobar cómo
funciona la estrategia en el comercio en vivo. Necesitamos entender si no
hemos cometido ningún error u olvidado algo esencial para la rentabilidad
de la estrategia.
2. NECESITAMOS ELEGIR SI MANTENDREMOS LA ESTRATEGIA:
parece fácil, pero no lo es. Después de un mes mínimo de operaciones en
vivo, debemos verificar si los resultados de la incubación son buenos o no.
Machine Translated by Google
¿Cómo saber si los rendimientos de la incubación son buenos o no? Hay muchas formas,
pero esta es la más fácil. Para hacerlo, podemos comparar la distribución entre los retornos
del backtest y los retornos de incubación. La mejor forma de hacerlo es comparando las
estadísticas con los valores teóricos obtenidos en el backtest sobre el tren y los conjuntos
de prueba. Luego calcule el rendimiento en el período de incubación utilizando nuestra
función de prueba retrospectiva.
Será emocionante entender si no cometemos ningún error porque deberíamos tener
algo muy cerca. Veamos la siguiente figura con dos casos para entender cuando tenemos
un problema o no.
Figura 17.4: dos situaciones después de un período de incubación
Como podemos ver, las primeras distribuciones son similares en lugar de las segundas,
por lo que debemos revisar todo nuestro código para encontrar el problema (frecuente
en la función backtest).
Puede usar una prueba estadística de Kolmogorov para comparar dos
distribuciones si necesita automatizar el proceso en lugar de hacerlo solo
con un gráfico.
17.3.3 ¿Cuándo dejar de fumar?
Machine Translated by Google
Es la eterna pregunta de cuándo hay que parar el algoritmo. Es muy difícil decir
eso, y necesitamos adaptar nuestro análisis a las condiciones del mercado. Es
una elección subjetiva.
Sin embargo, podemos encontrar algunos consejos para detener el algoritmo,
especialmente el cálculo de la reducción: el método se denomina método de gestión
de reducción.
Es fácil de entender que detengamos el algoritmo cuando la reducción cae por
debajo de un umbral. Entonces, el objetivo cuando hemos detenido el algoritmo es
determinar si activaremos el algoritmo nuevamente o no. Para hacer esto, no hay
reglas. Sin embargo, necesitamos analizar el rendimiento de la estrategia de la A
a la Z. Si los rendimientos fueron extraordinarios y durante la crisis de COVID, tenemos
una reducción anormal y el algoritmo se apaga; entonces yo personalmente volveré a
poner el algo en producción cuando vea que las condiciones del mercado son
normales.. En el segundo caso, si tenemos un algoritmo con retornos estables y desde
hace 6 meses hasta ahora el drawdown no deja de aumentar , , No lo activaré después
del cierre de la gestión de reducción.
Espero que hayas disfrutado el libro. No dude en unirse al foro de discord (QRCODE
en el capítulo 1) si tiene preguntas sobre el libro o si ve las preguntas de otros
comerciantes. ¡Les deseo una continuación fantástica!
Machine Translated by Google
Machine Translated by Google
Anexo: interés compuesto versus
interés simple
Este documento aprenderá la diferencia entre la estrategia de interés
compuesto y la estrategia de interés simple. Vamos a explicar por qué
la diferencia entre este tipo de cálculos. Luego, veremos cómo calcular
los rendimientos acumulativos utilizando estos métodos.
¿Cuál es la diferencia entre el método simple
y el compuesto?
La estrategia de interés simple es una estrategia de lote fijo. Significa que
cada día invertiremos capital. Tenemos
comportamiento
C*r mayúscula.
durante
Si días,
simulamos
tenemos
este
la
siguiente ecuación:
Donde está el beneficio de la es el capital invertido, y es
estrategia, el retorno en el porcentaje del día.
Sin embargo, el interés compuesto funciona con un coeficiente
, del día 1, tenemos *
multiplicador global. Si tenemos un capital inicial
y día2 * * . Así, el día n, nosotros
tener * *...* . Con esta estrategia, todo el
Machine Translated by Google
se invertirá capital en lugar del interés simple, que invierte constantemente el
mismo capital:
Donde está el beneficio de la es el capital invertido, y es
estrategia, el retorno en el porcentaje del día.
Cómo calcular el interés simple y
compuesto
Para calcular el rendimiento acumulativo de una estrategia de interés simple,
necesitamos calcular el rendimiento acumulativo. Para hacerlo, podemos usar la
función numpy cumsum().
Código: Rentabilidad acumulada usando el método de interés simple
acumula_return = [Link](returns)
Sin embargo, para calcular el rendimiento acumulativo de una estrategia de interés
compuesto, es necesario utilizar el producto del coeficiente multiplicador. Para
hacerlo, usaremos la función cumprod() de numpy.
Código: Rentabilidad acumulada usando el método de interés compuesto
acumula_return = [Link](1+devoluciones) - 1
Machine Translated by Google
Machine Translated by Google
Anexo: Guardar y cargar scikit-learn y
Modelos de flujo de tensor
En este documento, aprenderemos cómo guardar y cargar modelos ajustados de
scikit-learn y TensorFlow. Comenzaremos guardando un modelo de scikit-learn.
Para hacerlo, usaremos la librería pickle y joblib usando el siguiente código.
Código: guardar y cargar el modelo scikit-learn
desde [Link] import SVC import
pickle from joblib import dump, load
# Ahorrar
svc = SVC()
alg_pickle = [Link](svc)
dump(alg_pickle, "[Link]" )
# Carga
alg = load( "votació[Link]" )
Para guardar modelos con TensorFlow, necesitamos usar el comando de
TensorFlow.
Código: cómo guardar y cargar modelos de TensorFlow
def crear_modelo ():
# Clasificador de MODELO SECUENCIAL DE
INICIALIZACIÓN = Secuencial()
# AJUSTE DEL CAMINO DENSO Y ABANDONO
por _ en el rango (nb_hidden_layer):
[Link](Dense( 75 , input_shape
= (X_train.shape[ 1 ],), activación= "relu" ))
# AJOUT SOFÁ DENSO
[Link](Denso( 1 , activación = "sigmoide" ))
Machine Translated by Google
# COMPILACIÓN DEL MODELO
clasificador compilar (pérdida = "binary_crossentropy" , optimizador = "adam" )
clasificador de retorno
# Guarda el clasificador
de pesos.save_weights ( 'clasificador' )
# Crear una nueva instancia de
modelo model = create_model()
# Restaurar los pesos
model.load_weights( 'classifier' )
Machine Translated by Google
Anexo: clase MetaTrader
Para obtener más información sobre la configuración del dispositivo MetaTrader.
Consulta el archivo [Link] del repositorio de Github (enlace disponible
en el capítulo 1).
importar
advertencias de fecha y hora
importar fecha y hora importar
pandas como pd importar
MetaTrader5 como mt5
[Link]( "ignorar" ) [Link]()
clase MT5:
def get_data ( símbolo , norte
, marco de tiempo =mt5.TIMEFRAME_D1):
""" Función para importar los datos del símbolo elegido"""
# Inicializar la conexión si no hay [Link]()
# Extracto de fecha actual
utc_from = [Link]()
# Importar los datos en una tupla
rates = mt5.copy_rates_from(symbol, timeframe, utc_from, n)
# Tupla a dataframe
rates_frame = [Link](tarifas)
# Convierte el tiempo en segundos al formato de fecha y hora
rate_frame[ 'time' ] = pd.to_datetime(rates_frame[ 'time' ], unit= 's' )
# Convierta la columna "hora" en el formato correcto
rate_frame[ 'time' ] = pd.to_datetime(rates_frame[ 'time' ],
formato= '%Y-%m-%d' )
# Establecer el tiempo de la columna como el índice del marco de datos
Machine Translated by Google
rate_frame = rates_frame.set_index( 'time' ) return
rates_frame
órdenes def ( símbolo , lote , comprar = Verdadero , id_posición = Ninguno ):
""" Enviar las órdenes """
# Inicializar la conexión si no hay
si [Link]() == Falso :
[Link]()
# Modo de orden de llenado (debe probar 0, 1 o 2 #
porque depende del corredor)
yo = 1
# Tomar el precio
de venta ask_price = mt5.symbol_info_tick(símbolo).ask
# Tomar precio de
oferta bid_price = mt5.symbol_info_tick(símbolo).oferta
# Tomar el punto del activo point
= mt5.symbol_info(symbol).point
desviación = 20 # [Link](símbolo)
#************************ Abrir una operación
************************
si id_posición == Ninguno :
# Parámetros de la orden
de compra if buy: type_trade
= mt5.ORDER_TYPE_BUY sl = ask_price -
100 * punto tp = ask_price + 100 * punto de
precio = ask_price
# Parámetros de orden de venta
else :
type_trade = mt5.ORDER_TYPE_SELL sl =
bid_price + 100 * punto tp = bid_price - 100 *
punto precio = bid_price
Machine Translated by Google
# Abra la solicitud
comercial =
{ "acción" : mt5.TRADE_ACTION_DEAL,
"símbolo" : símbolo, "volumen" : lote,
"tipo" : type_trade,
"precio" : precio,
"desviación" : desviación,
"sl" : sl,
"tp" : tp,
"magic" : 234000 ,
"comment" : "python script order" ,
"type_time" : mt5.ORDER_TIME_GTC,
"type_filling" : i, } # enviar un resultado de
solicitud comercial = mt5.order_send(request)
result_comment = [Link]
*************************** Cerrar una operación
***********************
más :
# Parámetros de orden de
compra si compra:
type_trade = mt5.ORDER_TYPE_SELL precio
= bid_price
# Parámetros de orden de venta
más :
type_trade = mt5.ORDER_TYPE_BUY precio
= ask_price
# Cerrar la solicitud
comercial =
{ "acción" : mt5.TRADE_ACTION_DEAL,
"símbolo" : símbolo, "volumen" : lote,
"tipo" : type_trade,
"posición" : id_posición,
"precio" : precio,
Machine Translated by Google
"desviación" : desviación,
"magia" : 234000 ,
"comentario" : "orden de script de Python" ,
"type_time" : mt5.ORDER_TIME_GTC,
"type_filling" : i,
}
# enviar un resultado de
solicitud comercial = mt5.order_send
(solicitud) resultado_comentario = [Link]
devolver [Link]
def reanudar ():
""" Devuelve las posiciones actuales. Position=0 --> Buy """
# Inicializar la conexión si no hay [Link]()
# Definir el nombre de las columnas que crearemos
colonnes = [ "boleto" , "posición" , "símbolo" , "volumen" ]
# Ve a tomar las operaciones abiertas
actuales = mt5.positions_get()
# Crear un resumen de marco
de datos vacío = [Link]()
# Bucle para agregar cada fila en el marco de datos
# (Se puede mejorar usando una lista de listas)
para elemento en corriente:
elemento_pandas = [Link]([[Link],
[Link] ,
elemento.símbolo,
[Link]],
índice=dos puntos) .transpose ()
resumen = [Link]((resumen, elemento_pandas), eje=0 )
resumen de devolución
def ejecutar ( símbolo , largo , corto , mucho ):
# Inicializar la conexión si no hay
si [Link]() == Falso :
Machine Translated by Google
[Link]()
# Elija su símbolo print
( "----------------------------------------------------------- ------------" ) print ( "Fecha:
" , [Link]().strftime( "%Y-%m-%d
%H:%M:%S" ))
imprimir ( "SÍMBOLO:" , símbolo)
# Inicializar el dispositivo
current_open_positions = [Link]()
# Compre o
venda print ( f "COMPRAR: { largo } \t CORTO: {corto} " )
""" Cerrar comercio eventualmente """
# Comercio de tipo de extracción
prueba :
=
posición
"símbolo"
posiciones_abiertas_actuales.loc[posiciones_abiertas_actuales[ ]==símbolo].valores[ 0 ][ 1 ]
identificador =
"símbolo"
posiciones_abiertas_actuales.loc[posiciones_abiertas_actuales[ ]==símbolo].valores[ 0 ][ 0 ]
excepto :
posición = Ninguno
identificador = Ninguno
print ( f "POSICIÓN: {posición} \t ID: {identificador} " )
# Cerrar operaciones
si largo == Verdadero y posición == 0 : largo =
Falso
elif long == False and position== 0 : res =
[Link](símbolo, lote, comprar= identificador) Verdadero
, id_posición=
print ( f "CERRAR COMERCIO LARGO: {res} " )
elif short== Verdadero y posición == 1 :
corto = falso
Machine Translated by Google
elif corto == Falso y posición == 1 :
res = [Link](símbolo, lote, compra= Falso , id_posición= identificador) print
( f "CERRAR COMERCIO CORTO: {res} " )
más :
pasar
""" Comprar o corto """ si
es largo == Verdadero :
Verdadero
res = [Link] (símbolo, lote, compra = , id_posición=
Ninguno ) imprimir ( f "ABRIR COMERCIO LARGO: {res}
")
si corto == Verdadero :
res = [Link](símbolo, lote, comprar= Falso , id_posición= Ninguno ) imprimir
( f "ABRIR COMERCIO CORTO: {res} " )
imprimir ( "----------------------------------------------- --------" )
def cerrar_toda_la_noche ():
resultado = [Link]() for
i in range ( len (resultado)): before =
mt5.account_info().balance fila = [Link][ 0
+i: 1 +i,:]
si fila[ "posición" ][ 0 ]== 0 :
res = [Link](fila[ "símbolo" ][ 0 ], fila[ "volumen" ][ 0 ], compra= True ,
id_position=fila[ "boleto" ][ 0 ])
más :
res = [Link](fila[ "símbolo" ][ 0 ], fila[ "volumen" ][ 0 ], compra= False ,
id_position=fila[ "boleto" ][ 0 ])
Machine Translated by Google
Lecturas adicionales
Capítulo 3
“Selección de carteras” de Markowitz: una
retrospectiva de cincuenta años, The University
of Chicago Press [Link]
Gestión de carteras: análisis de media-varianza en el
mercado de activos de EE. UU., Narela (Bajram) Spaseski ,
[Link]
OLIO_MANAGEMENT_MEAN
VARIANCE_ANALYSIS_IN_THE_US_ASSET_MARKET
Optimización basada en la curtosis de lade desviación
la varianza,
portfolio
media
KingKeung Lai, Shouyang Wand, Lean yu https://
[Link]/viewdoc/download ?
doi=[Link].991&rep=rep1&type=pdf
Capítulo 4
Asignación táctica de activos (TAA), ADAM BARONE .
[Link]
áspid
Capítulo 5
Optimización del valor en riesgo condicional, R. Tyrrell
Rockafellar [Link]
.
CVaR1_JOR.p df
Capítulo 7
Estacionariedad y
diferenciación . [Link]
~rnau/[Link] Cointegración, Niti
Gupta. [Link]
cointegration/ Comercio de pares, James
Chen. [Link]
Machine Translated by Google
Capítulo 8
¿Qué es una serie temporal?, Adam
Hayes. [Link]
[Link] Modelo de promedio móvil autorregresivo,
Wikipedia. [Link]
moving average_model
Capítulo 9
Regresión lineal para el aprendizaje automático,
Jason Brownlee. [Link]
regresión-lineal-para-el-aprendizaje-de-máquinas/
Capítulo 11
Máquina de vectores de soporte,
Wikipedia. [Link]
Capítulo 12
Árboles de decisión en el aprendizaje automático, Prashant
Gupta. [Link]
machine learning-641b9c4e8052 Métodos de conjunto en
aprendizaje automático: ¿qué son y por qué usarlos? Evan
Lutins. [Link]
machine-learning-what-are-the-y-why-use-them 68ec3f9fef5f
Capítulo 13
Descenso del gradiente estocástico: ¡claramente
explicado!, Aishwarya V Srinivasan. https://
[Link]/stochastic-gradient-descent claramente-
explicado-53d239905d31
capitulo 14
Machine Translated by Google
Hoja de referencia de redes neuronales recurrentes, Afshine
Amidi y Shervine Amidi. [Link]
cs-230/cheatsheet redes-neuronales recurrentes
Capítulo 15
Introducción a las Redes Neuronales Convolucionales (CNN),
Manav mandal .
[Link] l-
neural-networks-cnn/
[1]
Conferencia adicional : "Selección de cartera" de Markowitz: una retrospectiva de cincuenta años
[2]
Conferencia adicional: Gestión de cartera: análisis de media-varianza en el activo de EE. UU.
mercado .
[3]
Conferencia adicional : Optimización de cartera basada en la media-varianza-sesgo-curtosis [4]
Conferencia adicional: Conferencia adicional: Asignación de activos tácticos (TAA), Adam
BARÓN [5]
Conferencia adicional https:// :
[Link]/wiki/Capital_asset_pricing_model [6]
Conferencia adicional: Optimización del valor en riesgo condicional, R. Tyrrell Rockafellar [7]
Clase adicional: Estacionariedad y diferenciación
[8]
Conferencia adicional : Cointegración, Niti Gupta [9]
Conferencia adicional : Comercio de pares, James Chen
[10]
Conferencia adicional: ¿Qué es una serie de tiempo? Adán Hayes
[11]
Conferencia adicional : modelo autorregresivo de promedio móvil, Wikipedia [12]
Conferencia adicional: Regresión lineal para el aprendizaje automático, Jason Brownlee [13]
Conferencia adicional : máquina de vectores de soporte, Wikipedia
[14]
Conferencia adicional : Árboles de decisión en el aprendizaje automático, Prashant Gupta
[15]
Conferencia adicional : Métodos de conjunto en el aprendizaje automático: ¿Qué son y
¿Por qué usarlos? Evan Lutins [16]
Conferencia adicional : Descenso de gradiente estocástico: ¡claramente explicado!, Aishwarya
V Srinivasan
Machine Translated by Google
[17]
Conferencia adicional : Introducción a las redes neuronales convolucionales (CNN), Manav
Mandal