0% encontró este documento útil (0 votos)
50 vistas157 páginas

Ingeniería de características para SVM

aiif

Cargado por

lui
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
50 vistas157 páginas

Ingeniería de características para SVM

aiif

Cargado por

lui
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

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

También podría gustarte