Aprendizaje automático en el trading: teoría, práctica, operaciones y más - página 213
![MQL5 - Lenguaje de estrategias comerciales para el terminal de cliente MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
Está perdiendo oportunidades comerciales:
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Registro
Entrada
Usted acepta la política del sitio web y las condiciones de uso
Si no tiene cuenta de usuario, regístrese
Otro ejemplo para una simulación.
Construimos 20.000 modelos lineales (1.000 observaciones en todas partes, número de predictores de 1 a 20 (1.000 modelos para cada número), más una variable independiente). Datos i.i.d., N(0,1).
El objetivo de la simulación es asegurarse de que el estadístico F no supera el valor crítico cuando la regresión MNA se construye sobre datos independientes (que no contienen dependencias), satisfaciendo los requisitos del modelo lin. Por lo tanto, puede utilizarse como indicador de la formación del modelo.
############### simulate lm f-stats with random vars
rm(list=ls());gc()
library(data.table)
library(ggplot2)
start <- Sys.time()
set.seed(1)
x <- as.data.table(matrix(rnorm(21000000, 0, 1), ncol = 21))
x[, sampling:= sample(1000, nrow(x), replace = T)]
lm_models <- x[,
{
lapply(c(1:20), function(x) summary(lm(data = .SD[, c(1:x, 21), with = F], formula = V21 ~ . -1))$'fstatistic'[[1]])
}
, by = sampling
]
lm_models_melted <- melt(lm_models, measure.vars = paste0('V', c(1:20)))
crtitical_f_stats <- qf(p = 0.99, df1 = c(1:20), df2 = 1000, lower.tail = TRUE, log.p = FALSE)
boxplot(data = lm_models_melted, value ~ variable); lines(crtitical_f_stats, type = 's', col = 'red')
Sys.time() - start
gc()
Tiempo de ejecución del código: 1,35 minutos.
Código útil. Visualiza las secuencias de transacciones en tres hipóstasis.
##########################
rm(list=ls());gc()
library(data.table)
library(ggplot2)
library(gridExtra)
library(tseries)
start <- Sys.time()
set.seed(1)
x <- as.data.table(matrix(rnorm(1000000, 0.1, 1), ncol = 1)) #random normal value with positive expectation
x[, variable:= rep(1:1000, times = 1000)]
x[, trade:= 1:.N, by = variable]
x.cast = dcast.data.table(x, variable ~ trade, value.var = 'V1', fun.aggregate = sum)
x_cum <- x.cast[, as.list(cumsum(unlist(.SD))), by = variable]
monte_trades <- melt(x_cum, measure.vars = names(x_cum)[-1], variable.name = "trade", value.name = 'V1')
setorder(monte_trades, variable, trade)
monte_trades_last <- as.data.table(monte_trades[trade == '1000', V1])
quantile_trade <- monte_trades[, quantile(V1, probs = 0.05), by = trade]
RF_last <- monte_trades[, V1[.N] / maxdrawdown(V1)[[1]], by = variable]
p1 <- ggplot(data = monte_trades, aes(x = trade, y = V1, group = variable)) +
geom_line(size = 2, color = 'blue', alpha = 0.01) +
geom_line(data = quantile_trade, aes(x = trade, y = V1, group = 1), size = 2, alpha = 0.5, colour = 'blue') +
ggtitle('Simulated Trade Sequences of Length 1000')
p2 <- ggplot(data = monte_trades_last, aes(V1)) +
geom_density(alpha = 0.1, size = 1, color = 'blue', fill = 'blue') +
scale_x_continuous(limits = c(min(monte_trades$V1), max(monte_trades$V1))) +
coord_flip() +
ggtitle('Cumulative Profit Density')
p3 <- ggplot(data = RF_last, aes(V1)) +
geom_density(alpha = 0.1, size = 1, color = 'blue', fill = 'blue') +
geom_vline(xintercept = mean(RF_last$V1), colour = "blue", linetype = 2, size = 1) +
geom_vline(xintercept = median(RF_last$V1), colour = "red", linetype = 2, size = 1) +
ggtitle('Recovery Factor Density + Mean (blue) and Median (red)')
grid.arrange(p1, p2, p3, ncol = 3)
Sys.time() - start
gc()
Funciona durante unos 45 segundos. Se dibuja durante aproximadamente 1,5 minutos.
El objetivo de la simulación es garantizar que el estadístico F no supere un valor crítico cuando la regresión MNA se construye sobre datos independientes (que no contienen dependencias), satisfaciendo los requisitos de un modelo lineal. Por lo tanto, puede utilizarse como indicador de la formación del modelo.
¿Cómo puedo interpretar correctamente el resultado de ese ejemplo?
Entiendo que el primer predictor puede considerarse más cualitativo que el primero + el segundo. Y 1+2 es mejor que 1+2+3. ¿Es así? ¿Es razonable seleccionar por genética el conjunto de predictores que dará el mayor fstatistic?
No entendí bien lo del fstatistic. Los datos aquí son aleatorios, pero el modelo ha aprendido algo, por lo que se puede concluir que el modelo está ajustado y sobreentrenado. Lo que significa que la evaluación del modelo debe ser mala. Es decir, esperaba un fstatistis negativo, o alguna otra indicación de que las cosas están mal en el gráfico.
¿Cómo puedo interpretar correctamente el resultado de ese ejemplo?
Entiendo que el primer predictor puede considerarse más cualitativo que el primero + el segundo. Y 1+2 es mejor que 1+2+3. ¿Es así? ¿Es razonable seleccionar por genética el conjunto de predictores que dará el mayor fstatistic?
Mira la tabla de distribución F.http://www.socr.ucla.edu/applets.dir/f_table.html
El estadístico F es un valor que depende de los grados de libertad. Siempre es positivo, porque tenemos una distribución unilateral.
Pero el modelo no aprende nada, porque un modelo entrenado debe tener un elevado estadístico F (mayor o igual que el crítico a un determinado alfa - como suena al probar la hipótesis nula).
En todos los casos, no se supera el valor crítico en alfa = 0,01, pero se podría fijar en 0,0001, por ejemplo.
Dicho esto, quería asegurarme (no estudié esto en la universidad) de que al añadir variables de ruido el modelo lineal no mostraría un aumento del aprendizaje. Como puedes ver...
Código útil. Visualiza las secuencias de transacciones en tres hipóstasis.
Con respecto al código anterior. Por favor, escriba al menos un breve comentario en el código. Especialmente cuando se utilizan expresiones complejas. No todo el mundo conoce y utiliza el paquete "data.table", no está de más explicar qué hace dcast.data.table, fundir qué es .N, .SD. No publicas el código para demostrar lo mucho que sabes del tema. En mi opinión, el código publicado debería ayudar a otros usuarios (incluso con un nivel de formación elemental) a entender el script.
Está muy bien que R permita programar la acción de varias maneras, pero es deseable que no se pierda la legibilidad del código.
Algunas sugerencias sobre el código:
- las variables intermedias x, x.cast, x.cum no son necesarias en los cálculos y sólo ocupan memoria. Todos los cálculos que no requieran guardar resultados intermedios deben realizarse preferentemente a través de la tubería
Por ejemplo
rm(list=ls());gc()
library(data.table)
library(ggplot2)
library(gridExtra)
library(tseries)
#----
require(magrittr)
require(dplyr)
start <- Sys.time()
monte_trades <- as.data.table(matrix(rnorm(1000000, 0.1, 1), ncol = 1)) %>%
.[, variable := rep(1:1000, times = 1000)]%>%
.[, trade := 1:.N, by = variable] %>%
dcast.data.table(., variable ~ trade, value.var = 'V1', fun.aggregate = sum)%>%
.[, as.list(cumsum(unlist(.SD))), by = variable]%>%
melt(., measure.vars = names(.)[-1], variable.name = "trade", value.name = 'V1')%>%
setorder(., variable, trade)
monte_trades_last <- as.data.table(monte_trades[trade == '1000', V1])
quantile_trade <- monte_trades[, quantile(V1, probs = 0.05), by = trade]
RF_last <- monte_trades[, V1[.N] / maxdrawdown(V1)[[1]], by = variable]
Sys.time() - start
#Time difference of 2.247022 secs
Por supuesto, se necesita mucho tiempo para construir gráficos.
No es una crítica.
Buena suerte
No entendí bien lo del fstatistic. Los datos aquí son aleatorios, pero el modelo ha aprendido algo, por lo que se puede concluir que el modelo está ajustado y sobreentrenado. Lo que significa que la evaluación del modelo debe ser mala. Es decir, esperaba un fstatistis negativo, o alguna otra indicación de que las cosas están mal en el gráfico.
¿Cómo puedo interpretar correctamente el resultado de ese ejemplo?
Entiendo que el primer predictor puede considerarse más cualitativo que el primero + el segundo. Y 1+2 es mejor que 1+2+3. ¿Es así? ¿Es razonable seleccionar por genética el conjunto de predictores que dará el mayor fstatistic?
Y aquí tenemos un ejemplo en el que suponemos que el modelo completamente entrenado incluirá 20 variables, con pesos crecientes (1 variable - peso 1, la 20ª variable - peso 20). Y veamos cómo cambiará la distribución de los estadísticos F tras la adición sucesiva de predictores al modelo:
############### simulate lm f-stats with non-random vars
rm(list=ls());gc()
library(data.table)
library(ggplot2)
start <- Sys.time()
set.seed(1)
x <- as.data.table(matrix(rnorm(20000000, 0, 1), ncol = 20))
x[, (paste0('coef', c(1:20))):= lapply(1:20, function(x) rnorm(.N, x, 1))]
x[, output:= Reduce(`+`, Map(function(x, y) (x * y), .SD[, (1:20), with = FALSE], .SD[, (21:40), with = FALSE])), .SDcols = c(1:40)]
x[, sampling:= sample(1000, nrow(x), replace = T)]
lm_models <- x[,
{
lapply(c(1:20), function(x) summary(lm(data = .SD[, c(1:x, 41), with = F], formula = output ~ . -1))$'fstatistic'[[1]])
}
, by = sampling
]
lm_models_melted <- melt(lm_models, measure.vars = paste0('V', c(1:20)))
crtitical_f_stats <- qf(p = 0.99, df1 = c(1:20), df2 = 1000, lower.tail = TRUE, log.p = FALSE)
boxplot(data = lm_models_melted, value ~ variable, log = 'y'); lines(crtitical_f_stats, type = 's', col = 'red')
summary(lm(data = x[sample(1000000, 1000, replace = T), c(1:20, 41), with = F], formula = output ~ . -1))
Sys.time() - start
gc()
Gráfico con eje Y logarítmico:
Aparentemente, sí...
> summary(lm(data = x[sample(1000000, 1000, replace = T), c(1:20, 41), with = F], formula = output ~ . -1))
Call:
lm(formula = output ~ . - 1, data = x[sample(1e+06, 1000, replace = T),
c(1:20, 41), with = F])
Residuals:
Min 1Q Median 3Q Max
-19.6146 -2.8252 0.0192 3.0659 15.8853
Coefficients:
Estimate Std. Error t value Pr(>|t|)
V1 0.9528 0.1427 6.676 4.1e-11 ***
V2 1.7771 0.1382 12.859 < 2e-16 ***
V3 2.7344 0.1442 18.968 < 2e-16 ***
V4 4.0195 0.1419 28.325 < 2e-16 ***
V5 5.2817 0.1479 35.718 < 2e-16 ***
V6 6.2776 0.1509 41.594 < 2e-16 ***
V7 6.9771 0.1446 48.242 < 2e-16 ***
V8 7.9722 0.1469 54.260 < 2e-16 ***
V9 9.0349 0.1462 61.806 < 2e-16 ***
V10 10.1372 0.1496 67.766 < 2e-16 ***
V11 10.8783 0.1487 73.134 < 2e-16 ***
V12 11.9129 0.1446 82.386 < 2e-16 ***
V13 12.8079 0.1462 87.588 < 2e-16 ***
V14 14.2017 0.1487 95.490 < 2e-16 ***
V15 14.9080 0.1458 102.252 < 2e-16 ***
V16 15.9893 0.1428 111.958 < 2e-16 ***
V17 17.4997 0.1403 124.716 < 2e-16 ***
V18 17.8798 0.1448 123.470 < 2e-16 ***
V19 18.9317 0.1470 128.823 < 2e-16 ***
V20 20.1143 0.1466 137.191 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 4.581 on 980 degrees of freedom
Multiple R-squared: 0.9932, Adjusted R-squared: 0.993
F-statistic: 7123 on 20 and 980 DF, p-value: < 2.2e-16
Gracias. Todavía no sabía cómo hacerlo. Pero, en realidad, hay que tener en cuenta los cálculos en la medida de lo posible. Será más rápido. Buen kung fu...
Con sus retoques:
#---variant-------------
rm(list=ls());gc()
library(data.table)
library(ggplot2)
library(gridExtra)
library(tseries)
#----
require(magrittr)
require(dplyr)
start <- Sys.time()
monte_trades <- as.data.table(matrix(rnorm(1000000, 0.1, 1), ncol = 1)) %>%
.[, variable := rep(1:1000, times = 1000)]%>%
.[, trade := 1:.N, by = variable] %>%
dcast.data.table(., variable ~ trade, value.var = 'V1', fun.aggregate = sum)%>%
.[, as.list(cumsum(unlist(.SD))), by = variable]%>%
melt(., measure.vars = names(.)[-1], variable.name = "trade", value.name = 'V1')%>%
setorder(., variable, trade)
monte_trades_last <- as.data.table(monte_trades[trade == '1000', V1])
quantile_trade <- monte_trades[, quantile(V1, probs = 0.05), by = trade]
RF_last <- monte_trades[, V1[.N] / maxdrawdown(V1)[[1]], by = variable]
p1 <- ggplot(data = monte_trades, aes(x = trade, y = V1, group = variable)) +
geom_line(size = 2, color = 'blue', alpha = 0.01) +
geom_line(data = quantile_trade, aes(x = trade, y = V1, group = 1), size = 2, alpha = 0.5, colour = 'blue') +
ggtitle('Simulated Trade Sequences of Length 1000')
p2 <- ggplot(data = monte_trades_last, aes(V1)) +
geom_density(alpha = 0.1, size = 1, color = 'blue', fill = 'blue') +
scale_x_continuous(limits = c(min(monte_trades$V1), max(monte_trades$V1))) +
coord_flip() +
ggtitle('Cumulative Profit Density')
p3 <- ggplot(data = RF_last, aes(V1)) +
geom_density(alpha = 0.1, size = 1, color = 'blue', fill = 'blue') +
geom_vline(xintercept = mean(RF_last$V1), colour = "blue", linetype = 2, size = 1) +
geom_vline(xintercept = median(RF_last$V1), colour = "red", linetype = 2, size = 1) +
ggtitle('Recovery Factor Density + Mean (blue) and Median (red)')
grid.arrange(p1, p2, p3, ncol = 3)
Sys.time() - start
La duración es de 47 segundos. Es decir, el código es más bonito y más compacto, pero no hay diferencia en la velocidad... Dibujo, sí, muy largo. 1000 líneas con transparencia - por ellos...
Gracias. Todavía no sabía cómo hacerlo. Pero, en realidad, hay que tener en cuenta los cálculos en la medida de lo posible. Será más rápido. Buen kung fu...
Duración 47 segundos. Es decir, el código es más bonito y más compacto, pero no hay diferencia en la velocidad... El dibujo, sí, es muy largo. 1000 líneas con transparencia - por ellos...
Mi cálculo toma
# tiempo de ejecución en segundos
# min lq mean median uq max neval
# 2.027561 2.253354 2.254134 2.275785 2.300051 2.610649 100
Pero no es tan importante. Se trataba de la legibilidad del código.
Buena suerte
PS. Y paraleliza el cálculo de lm(). Este es exactamente el caso cuando se necesita
Tengo un cálculo que toma
#Tiempo de ejecución en segundos
# min lq mean median uq max neval
# 2.027561 2.253354 2.254134 2.275785 2.300051 2.610649 100
Pero no es tan importante. Se trataba de la legibilidad del código.
Buena suerte
PS. Y paraleliza el cálculo de lm(). Esto es exactamente el caso cuando es necesario.
No. Estás dando el tiempo de una parte del código antes de los gráficos. Lo he indicado, junto con los gráficos.
Tengo 1,5 segundos antes de los gráficos. Su método es de 1,15 segundos.
rm(list=ls());gc()
library(data.table)
library(ggplot2)
library(gridExtra)
library(tseries)
start <- Sys.time()
set.seed(1)
x <- as.data.table(matrix(rnorm(1000000, 0.1, 1), ncol = 1)) #random normal value with positive expectation
x[, variable:= rep(1:1000, times = 1000)]
x[, trade:= 1:.N, by = variable]
x.cast = dcast.data.table(x, variable ~ trade, value.var = 'V1', fun.aggregate = sum)
x_cum <- x.cast[, as.list(cumsum(unlist(.SD))), by = variable]
monte_trades <- melt(x_cum, measure.vars = names(x_cum)[-1], variable.name = "trade", value.name = 'V1')
setorder(monte_trades, variable, trade)
monte_trades_last <- as.data.table(monte_trades[trade == '1000', V1])
quantile_trade <- monte_trades[, quantile(V1, probs = 0.05), by = trade]
RF_last <- monte_trades[, V1[.N] / maxdrawdown(V1)[[1]], by = variable]
Sys.time() - start
rm(list=ls());gc()
library(data.table)
library(ggplot2)
library(gridExtra)
library(tseries)
#----
require(magrittr)
require(dplyr)
start <- Sys.time()
monte_trades <- as.data.table(matrix(rnorm(1000000, 0.1, 1), ncol = 1)) %>%
.[, variable := rep(1:1000, times = 1000)]%>%
.[, trade := 1:.N, by = variable] %>%
dcast.data.table(., variable ~ trade, value.var = 'V1', fun.aggregate = sum)%>%
.[, as.list(cumsum(unlist(.SD))), by = variable]%>%
melt(., measure.vars = names(.)[-1], variable.name = "trade", value.name = 'V1')%>%
setorder(., variable, trade)
monte_trades_last <- as.data.table(monte_trades[trade == '1000', V1])
quantile_trade <- monte_trades[, quantile(V1, probs = 0.05), by = trade]
RF_last <- monte_trades[, V1[.N] / maxdrawdown(V1)[[1]], by = variable]
Sys.time() - start
Resulta que su método es más rápido...