L'apprendimento automatico nel trading: teoria, modelli, pratica e algo-trading - pagina 213
![MQL5 - Linguaggio delle strategie di trading integrato nel client terminal MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
Ti stai perdendo delle opportunità di trading:
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Registrazione
Accedi
Accetti la politica del sito e le condizioni d’uso
Se non hai un account, registrati
Un altro esempio di simulazione.
Costruiamo 20.000 modelli lineari (1.000 osservazioni ovunque, numero di predittori da 1 a 20 (1.000 modelli per ogni numero), più una variabile indipendente). Dati i.i.d., N(0,1).
Lo scopo della simulazione è assicurarsi che la statistica F non superi il valore critico quando la regressione MNA è costruita su dati indipendenti (non contenenti dipendenze), soddisfacendo i requisiti del modello lin. Quindi, può essere usato come un indicatore della formazione del modello.
############### 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()
Tempo di esecuzione del codice: 1,35 minuti.
Codice utile. Visualizza le sequenze di transazioni in tre ipostasi.
##########################
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()
Funziona per circa 45 secondi. Disegna per circa 1,5 minuti.
Lo scopo della simulazione è quello di garantire che la statistica F non superi un valore critico quando la regressione MNA è costruita su dati indipendenti (non contenenti dipendenze), soddisfacendo i requisiti di un modello lineare. Quindi, può essere usato come un indicatore della formazione del modello.
Come posso interpretare correttamente il risultato di questo esempio?
Capisco che il primo predittore può essere considerato più qualitativo del primo + il secondo. E 1+2 è meglio di 1+2+3. È così? È ragionevole selezionare per via genetica il set di predittori che darà la più alta fstatistica?
Non ho capito bene la fstatistica. I dati qui sono casuali, ma il modello ha imparato qualcosa, quindi si può concludere che il modello è adatto e sovrallenato. Il che significa che la valutazione del modello deve essere cattiva. Cioè mi aspettavo un fstatistis negativo, o qualche altra indicazione che le cose vanno male sul grafico.
Come posso interpretare correttamente il risultato di questo esempio?
Capisco che il primo predittore può essere considerato più qualitativo del primo + il secondo. E 1+2 è meglio di 1+2+3. È così? È ragionevole selezionare per via genetica il set di predittori che darà la più alta fstatistica?
Guarda la tabella di distribuzione F.http://www.socr.ucla.edu/applets.dir/f_table.html
La statistica F è un valore che dipende dai gradi di libertà. È sempre positivo, perché abbiamo una distribuzione unilaterale.
Ma il modello non impara nulla, perché un modello addestrato deve avere una F-statistica alta (maggiore o uguale al critico ad una data alfa - come suona quando si testa l'ipotesi nulla).
In tutti i casi, non superando il valore critico ad alfa = 0,01, ma si potrebbe impostarlo a 0,0001, per esempio.
Detto questo, volevo essere sicuro (non ho studiato questo all'università) che aggiungendo variabili di rumore il modello lineare non avrebbe mostrato un aumento dell'apprendimento. Come potete vedere...
Codice utile. Visualizza le sequenze di transazioni in tre ipostasi.
Per quanto riguarda il codice di cui sopra. Si prega di scrivere almeno brevi commenti nel codice. Soprattutto quando si usano espressioni complesse. Non tutti conoscono e usano il pacchetto "data.table", non è superfluo spiegare cosa fa dcast.data.table, fondere cos'è .N, .SD. Non si pubblica il codice per mostrare quanto a fondo lo si conosce. Secondo me il codice pubblicato dovrebbe aiutare altri utenti (anche con un livello elementare di formazione) a capire lo script.
È fantastico che R permetta di programmare l'azione in diversi modi, ma è auspicabile che non si perda la leggibilità del codice.
Alcuni suggerimenti sul codice:
- le variabili intermedie x, x.cast, x.cum non sono necessarie nei calcoli e occupano solo memoria. Tutti i calcoli che non richiedono il salvataggio dei risultati intermedi dovrebbero essere eseguiti preferibilmente tramite pipe
Per esempio
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
Naturalmente, ci vuole molto tempo per costruire i grafici.
Non è una critica.
Buona fortuna
Non ho capito bene la fstatistica. I dati qui sono casuali, ma il modello ha imparato qualcosa, quindi si può concludere che il modello è adatto e sovrallenato. Il che significa che la valutazione del modello deve essere cattiva. Cioè mi aspettavo un fstatistis negativo, o qualche altra indicazione che le cose vanno male sul grafico.
Come posso interpretare correttamente il risultato di questo esempio?
Capisco che il primo predittore può essere considerato più qualitativo del primo + il secondo. E 1+2 è meglio di 1+2+3. È così? È ragionevole selezionare per via genetica il set di predittori che darà la più alta fstatistica?
Ed ecco un esempio in cui assumiamo che il modello completamente addestrato includerà 20 variabili, con pesi crescenti (1 variabile - peso 1, la 20° variabile - peso 20). E vediamo come cambia la distribuzione delle statistiche F dopo l'aggiunta successiva di predittori al modello:
############### 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()
Grafico con asse y logaritmico:
A quanto pare, 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
Grazie! Non sapevo ancora come farlo. Ma in realtà, si dovrebbe tenere conto dei calcoli il più possibile. Sarà più veloce. Buon kung fu...
Con le tue modifiche:
#---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
Il tempo di esecuzione è di 47 secondi. Voglio dire, il codice è più bello e più compatto, ma non c'è differenza di velocità... Disegno, sì, molto lungo. 1000 linee con trasparenza...
Grazie! Non sapevo ancora come farlo. Ma in realtà, si dovrebbe tenere conto dei calcoli il più possibile. Sarà più veloce. Buon kung fu...
Tempo di esecuzione 47 secondi. Voglio dire, il codice è più bello e più compatto, ma non c'è differenza di velocità... Il disegno, sì, è molto lungo. 1000 linee con trasparenza...
Il mio calcolo prende
# tempo di esecuzione in secondi
# min lq media mediana uq max neval
# 2.027561 2.253354 2.254134 2.275785 2.300051 2.610649 100
Ma non è così importante. Si trattava di leggibilità del codice.
Buona fortuna
PS. E parallelizzare il calcolo lm(). Questo è esattamente il caso in cui avete bisogno di
Ho un calcolo che prende
#-tempo di esecuzione in secondi
# min lq media mediana uq max neval
# 2.027561 2.253354 2.254134 2.275785 2.300051 2.610649 100
Ma non è così importante. Si trattava di leggibilità del codice.
Buona fortuna
PS. E parallelizzare il calcolo lm(). Questo è esattamente il caso in cui è necessario.
No. Stai dando il tempo per una parte del codice prima dei grafici. L'ho indicato, insieme ai grafici.
Ho 1,5 secondi prima delle classifiche. Il vostro metodo è di 1,15 secondi.
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
Si scopre che il tuo metodo è più veloce...