Discussão do artigo "Redes neurais de maneira fácil (Parte 66): Problemáticas da pesquisa em treinamento off-line"

 

Novo artigo Redes neurais de maneira fácil (Parte 66): Problemáticas da pesquisa em treinamento off-line foi publicado:

O treinamento de modelos em modo off-line é realizado com dados de uma amostra de treinamento previamente preparada. Isso nos oferece várias vantagens, mas também comprime significativamente as informações sobre o ambiente em relação às dimensões da amostra de treinamento. Isso, por sua vez, limita as possibilidades de pesquisa. Neste artigo, quero apresentar um método que permite enriquecer a amostra de treinamento com dados o mais diversificados possível.

O método ExORL pode ser dividido em três etapas principais. A primeira etapa é a coleta de dados exploratórios não rotulados. Para isso, é possível usar diferentes algoritmos de aprendizado não supervisionado. Os autores do método não limitam o conjunto de algoritmos utilizados. Durante a interação com o ambiente, em cada episódio é utilizada uma política π, que depende do histórico de interações anteriores. Cada episódio é salvo no conjunto de dados como uma sequência de estado St, ação At e o estado subsequente St+1. A coleta de dados de treinamento continua até que a amostra de treinamento esteja completamente preenchida, limitada pelo escopo técnico ou recursos disponíveis.

Após a coleta do conjunto de dados sobre estados e ações, é realizada uma reavaliação usando uma função de recompensa definida. Nesta etapa, é essencial avaliar a recompensa para cada tupla no conjunto de dados.

A experiência prática mostra a possibilidade de uso paralelo em um único buffer de reprodução coletado por diferentes métodos. Usei tanto as trajetórias coletadas anteriormente pelo EA "Research.mq5" quanto pelo "ResearchExORL.mq5". O primeiro destaca as vantagens e desvantagens da política aprendida pelo Ator. O segundo permite explorar ao máximo o ambiente e avaliar as oportunidades não contabilizadas.

Durante o processo iterativo de treinamento do modelo, consegui aumentar sua eficácia.

Resultados dos testes

Resultados dos testes

Com uma redução geral no número de negociações durante o período de teste em 3 vezes (56 contra 176), o lucro aumentou quase 3 vezes. O valor da negociação mais lucrativa aumentou mais de duas vezes. E a média de lucro por negociação aumentou cinco vezes. Durante todo o período de teste, observamos um aumento no saldo. Como resultado, o fator de lucro do modelo aumentou de 1.3 para 2.96. 

Autor: Dmitriy Gizlyk

 
Olá, Dmitry. O relatório diz que você usou 5 agentes e coletou 100 passes com eles. Você executou a coleta 20 vezes? Caso contrário, apenas 5 passes serão coletados por 5 agentes. Além disso, se você executar o Expert Advisor com os mesmos parâmetros, ele não recalculará, mas extrairá o resultado do cache. Ou você trocou esses 5 agentes a cada coleta subsequente? Por favor, explique esse ponto.
 
Viktor Kudriavtsev #:
Olá, Dmitry. O relatório diz que você usou 5 agentes e coletou 100 passes com eles. Você executou a coleta 20 vezes? Caso contrário, apenas 5 passes serão coletados por 5 agentes. Além disso, se você executar o Expert Advisor com os mesmos parâmetros, ele não recalculará, mas extrairá o resultado do cache. Ou você trocou esses 5 agentes a cada coleta subsequente? Por favor, explique esse ponto.

Eu o executei 20 vezes, mas limpei o cache antes de executá-lo. Não é possível deslocar agentes porque o arquivo de modelo está vinculado ao número do agente. Portanto, se você mudar os agentes a cada vez, um novo modelo aleatório será criado e não obteremos o efeito desejado.

 
Dmitriy Gizlyk #:

Executei-o 20 vezes, mas limpei o cache antes de começar. Não é possível mudar os agentes porque o arquivo de modelo está vinculado ao número do agente. Portanto, se os agentes forem deslocados, um novo modelo aleatório será criado a cada vez e não obteremos o efeito desejado.

Olá, Dmitriy, eu fiz isso usando o seguinte... Isso terá o mesmo efeito?

input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1;

input double MinProfit = 10;
input int Agent = 1;
input int Optimisation = 1;

em seguida, defina o agente para 5 e a otimização para 20
Total de 100...


 
JimReaper #:
Oi Dmitriy, eu fiz isso usando este... O efeito será o mesmo?

input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1;

input double MinProfit = 10;
input int Agent = 1;
input int Optimisation = 1;

em seguida, defina o agente para 5 e a otimização para 20
Total de 100...


Olá,
Quantos núcleos você usou?

 
Dmitriy Gizlyk #:

Olá,
Quantos núcleos você usou?

Eu usei apenas 4 núcleos.


Arquivos anexados:
Dimi_1.png  2 kb
Dimi_2.png  5 kb
 
JimReaper #:
Usei apenas 4 núcleos.


Não sei como o MetaTrader Tester seleciona as entradas para cada núcleo. A ideia principal no estudo on-line é usar o modelo pré-treinado de uma passagem para outra. Mas se o testador executar o Optimithation 1..4 para o Agente 1 em uma passagem, todos eles usarão um modelo aleatório (não pré-treinado).

 
Dmitriy Gizlyk #:

Não sei como o MetaTrader Tester seleciona as entradas para cada núcleo. A ideia principal no estudo on-line é usar o modelo pré-treinado de uma passagem para outra. Mas se o testador executar o Optimithation 1..4 para o Agente 1 em uma passagem, todos eles usarão um modelo aleatório (não pré-treinado).

Entendido! Muito obrigado!

Também adicionei alguns indicadores e parâmetros, totalizando 27 BarDescr.... Momentum, Bands & Ichimoku Kinko Hyo =)

int OnInit()

{

Definir símbolo e atualizar

if(! Symb.Name(_Symbol))

retorna INIT_FAILED;

Symb.Refresh();

//---

if(! RSI. Create(Symb.Name(), TimeFrame, RSIPeriod, RSIPrice))

return INIT_FAILED;

//---

if(! CCI.Create(Symb.Name(), TimeFrame, CCIPeriod, CCIPrice))

return INIT_FAILED;

//---

if(! ATR. Create(Symb.Name(), TimeFrame, ATRPeriod))

return INIT_FAILED;

//---

if(! MACD. Create(Symb.Name(), TimeFrame, FastPeriod, SlowPeriod, SignalPeriod, MACDPrice)))

return INIT_FAILED;

//---

if (! Momentum.Create(Symb.Name(), TimeFrame, MomentumMaPeriod, MomentumApplied))

return INIT_FAILED;

Inicializar o indicador Ichimoku Kinko Hyo

if (! Ichimoku.Create(Symb.Name(), TimeFrame, Ichimokutenkan_senPeriod, Ichimokukijun_senPeriod, Ichimokusenkou_span_bPeriod)))

return INIT_FAILED;

//---

if (! Bands.Create(Symb.Name(), TimeFrame, BandsMaPeriod, BandsMaShift, BandsDeviation, BandsApplied))

return INIT_FAILED;

//---

if(! RSI. BufferResize(HistoryBars) || ! CCI.BufferResize(HistoryBars) ||

! ATR. BufferResize(HistoryBars) || ! MACD. BufferResize(HistoryBars))

{

PrintFormat("%s -> %d", __FUNCTION__, __LINE__);

return INIT_FAILED;

}

//---


void OnTick()

{

//---

se(! IsNewBar())

return;

//---

int bars = CopyRates(Symb.Name(), TimeFrame, iTime(Symb.Name(), TimeFrame, 1), HistoryBars, Rates);

if(! ArraySetAsSeries(Rates, true))

return;

//---

RSI. Refresh();

CCI.Refresh();

ATR. Refresh();

MACD. Refresh();

Symb.Refresh();

Momentum.Refresh();

Bands.Refresh();

Symb.RefreshRates();

Atualizar os valores de Ichimoku para a barra atual

Ichimoku.Refresh();

--- Dados do histórico

float atr = 0;

for (int b = 0; b < (int)HistoryBars; b++)

{

float open = (float)Rates[b].open;

float close = (float)Rates[b].close;

float rsi = (float)RSI. Main(b);

float cci = (float)CCI.Main(b);

atr = (float)ATR. Main(b);

float macd = (float)MACD. Main(b);

float sign = (float)MACD. Signal(b);

float mome = (float)Momentum.Main(b);

float bandzup = (float)Bands.Upper(b);

float bandzb = (float)Bands.Base(b);

float bandzlo = (float)Bands.Lower(b);

float tenkan = (float)Ichimoku.TenkanSen(0); Use o valor calculado

float kijun = (float)Ichimoku.KijunSen(1); Use o valor calculado

float senkasa = (float)Ichimoku.SenkouSpanA(2); Use o valor calculado

float senkb = (float)Ichimoku.SenkouSpanB(3); Use o valor calculado

Verifique se há EMPTY_VALUE e divisão por zero

if (rsi == EMPTY_VALUE || cci == EMPTY_VALUE || atr == EMPTY_VALUE || macd == EMPTY_VALUE ||

sign == EMPTY_VALUE || mome == EMPTY_VALUE || bandzup == EMPTY_VALUE || bandzb == EMPTY_VALUE || bandzb == EMPTY_VALUE ||

bandzlo == EMPTY_VALUE || tenkan == EMPTY_VALUE || kijun == EMPTY_VALUE || senkasa == EMPTY_VALUE || senkasa == EMPTY_VALUE ||

senkb == EMPTY_VALUE || kijun == 0.0 || senkb == 0.0)

{

continue;

}

Assegurar que os buffers não sejam redimensionados dentro do loop

int shift = b * BarDescr;

sState.state[shift] = (float)(Rates[b].close - open);

sState.state[shift + 1] = ((float)(Rates[b].close - open) + (tenkan - kijun)) / 2.0f;

sState.state[shift + 2] = (float)(Rates[b].high - open);

sState.state[shift + 3] = (float)(Rates[b].low - open);

sState.state[shift + 4] = (float)(Rates[b].high - close);

sState.state[shift + 5] = (float)(Rates[b].low - close);

sState.state[shift + 6] = (tenkan - kijun);

sState.state[shift + 7] = (float)(Rates[b].tick_volume / 1000.0f);

sState.state[shift + 8] = ((float)(Rates[b].high) - (float)(Rates[b].low));

sState.state[shift + 9] = (bandzup - bandzlo);

sState.state[shift + 10] = rsi;

sState.state[shift + 11] = cci;

sState.state[shift + 12] = atr;

sState.state[shift + 13] = macd;

sState.state[shift + 14] = sign;

sState.state[shift + 15] = mome;

sState.state[shift + 16] = (float)(Rates[b].open - tenkan);

sState.state[shift + 17] = (float)(Rates[b].open - kijun);

sState.state[shift + 18] = (float)(Rates[b].open - bandzb);

sState.state[shift + 19] = (float)(Rates[b].open - senkasa);

sState.state[shift + 20] = (float)(Rates[b].open - senkb);

sState.state[shift + 21] = (float)(Rates[b].close - tenkan);

sState.state[shift + 22] = (float)(Rates[b].close - kijun);

sState.state[shift + 23] = (float)(Rates[b].close - bandzb);

sState.state[shift + 24] = (float)(Rates[b].close - senkasa);

sState.state[shift + 25] = (float)(Rates[b].close - senkb);

sState.state[shift + 26] = senkasa - senkb;

//---

RSI.Refresh();

CCI.Refresh();

ATR.Refresh();

MACD.Refresh();

Symb.Refresh();

Momentum.Refresh();

Bands.Refresh();

Symb.RefreshRates();

// Atualizar os valores do Ichimoku para a barra atual

Ichimoku.Refresh();

//---

Imprimir ("Estado 0: ", sState.state[shift]);

Imprimir ("Estado 1: ", sState.state[shift + 1]);

Print("State 2: ", sState.state[shift + 2]);

Print("State 3: ", sState.state[shift + 3]);

Print("State 4: ", sState.state[shift + 4]);

Print("State 5: ", sState.state[shift + 5]);

Print("State 6: ", sState.state[shift + 6]);

Print("State 7: ", sState.state[shift + 7]);

Print("State 8: ", sState.state[shift + 8]);

Print("State 9: ", sState.state[shift + 9]);

Print("State 10: ", sState.state[shift + 10]);

Print("State 11: ", sState.state[shift + 11]);

Print("State 12: ", sState.state[shift + 12]);

Print("State 13: ", sState.state[shift + 13]);

Print("State 14: ", sState.state[shift + 14]);

Print("State 15: ", sState.state[shift + 15]);

Print("State 16: ", sState.state[shift + 16]);

Print("State 17: ", sState.state[shift + 17]);

Print("State 18: ", sState.state[shift + 18]);

Print("State 19: ", sState.state[shift + 19]);

Print("State 20: ", sState.state[shift + 20]);

Print("State 21: ", sState.state[shift + 21]);

Print("State 22: ", sState.state[shift + 22]);

Print("State 23: ", sState.state[shift + 23]);

Print("State 24: ", sState.state[shift + 24]);

Print("State 25: ", sState.state[shift + 25]);

Print("State 26: ", sState.state[shift + 26]);

Print("Tenkan Sen: ", tenkan);

Print("Kijun Sen: ", kijun);

Print("Senkou Span A: ", senkasa);

Print("Senkou Span B: ", senkb);

}

bState.AssignArray(sState.state);


Arquivos anexados:
 
JimReaper #:
Entendido! Muito obrigado!

Também adicionei alguns indicadores e parâmetros, totalizando 27 BarDescr.... Momentum, Bandas e Ichimoku Kinko Hyo =)

int OnInit()

{

Definir símbolo e atualizar

se(! Symb.Name(_Symbol))

retorna INIT_FAILED;

Symb.Refresh();

//---

if(! RSI. Create(Symb.Name(), TimeFrame, RSIPeriod, RSIPrice))

return INIT_FAILED;

//---

if(! CCI.Create(Symb.Name(), TimeFrame, CCIPeriod, CCIPrice))

return INIT_FAILED;

//---

if(! ATR. Create(Symb.Name(), TimeFrame, ATRPeriod))

return INIT_FAILED;

//---

if(! MACD. Create(Symb.Name(), TimeFrame, FastPeriod, SlowPeriod, SignalPeriod, MACDPrice))

return INIT_FAILED;

//---

Se (! Momentum.Create(Symb.Name(), TimeFrame, MomentumMaPeriod, MomentumApplied))

return INIT_FAILED;

Inicializar o indicador Ichimoku Kinko Hyo

If (! Ichimoku.Create(Symb.Name(), TimeFrame, Ichimokutenkan_senPeriod, Ichimokukijun_senPeriod, Ichimokusenkou_span_bPeriod))

return INIT_FAILED;

//---

se (! Bands.Create(Symb.Name(), TimeFrame, BandsMaPeriod, BandsMaShift, BandsDeviation, BandsApplied))

return INIT_FAILED;

//---

if(! RSI. BufferResize(HistoryBars) || ! CCI.BufferResize(HistoryBars) ||

! ATR. BufferResize(HistoryBars) || ! MACD. BufferResize(HistoryBars))

{

PrintFormat("%s -> %d", __FUNCTION__, __LINE__);

return INIT_FAILED;

}

//---


void OnTick()

{

//---

se(! IsNewBar())

return;

//---

int bars = CopyRates(Symb.Name(), TimeFrame, iTime(Symb.Name(), TimeFrame, 1), HistoryBars, Rates);

if(! ArraySetAsSeries(Rates, true))

return;

//---

RSI. Refresh();

CCI.Refresh();

ATR. Refresh();

MACD. Refresh();

Symb.Refresh();

Momentum.Refresh();

Bands.Refresh();

Symb.RefreshRates();

Atualizar os valores do Ichimoku para a barra atual

Ichimoku.Refresh();

--- Dados do histórico

float atr = 0;

for (int b = 0; b < (int)HistoryBars; b++)

{

float open = (float)Rates[b].open;

float close = (float)Rates[b].close;

float rsi = (float)RSI. Main(b);

float cci = (float)CCI.Main(b);

atr = (float)ATR. Main(b);

float macd = (float)MACD. Main(b);

float sign = (float)MACD. Signal(b);

float mome = (float)Momentum.Main(b);

float bandzup = (float)Bands.Upper(b);

float bandzb = (float)Bands.Base(b);

float bandzlo = (float)Bands.Lower(b);

float tenkan = (float)Ichimoku.TenkanSen(0); Use o valor calculado

float kijun = (float)Ichimoku.KijunSen(1); Use o valor calculado

float senkasa = (float)Ichimoku.SenkouSpanA(2); Use o valor calculado

float senkb = (float)Ichimoku.SenkouSpanB(3); Use o valor calculado

Verifique se há EMPTY_VALUE e divisão por zero

se (rsi == EMPTY_VALUE || cci == EMPTY_VALUE || atr == EMPTY_VALUE || macd == EMPTY_VALUE ||

sign == EMPTY_VALUE || mome == EMPTY_VALUE || bandzup == EMPTY_VALUE || bandzb == EMPTY_VALUE || bandzb == EMPTY_VALUE ||

bandzlo == EMPTY_VALUE || tenkan == EMPTY_VALUE || kijun == EMPTY_VALUE || senkasa == EMPTY_VALUE || senkasa == EMPTY_VALUE ||

senkb == EMPTY_VALUE || kijun == 0.0 || senkb == 0.0)

{

continue;

}

Assegure-se de que os buffers não sejam redimensionados dentro do loop

int shift = b * BarDescr;

sState.state[shift] = (float)(Rates[b].close - open);

sState.state[shift + 1] = ((float)(Rates[b].close - open) + (tenkan - kijun)) / 2.0f;

sState.state[shift + 2] = (float)(Rates[b].high - open);

sState.state[shift + 3] = (float)(Rates[b].low - open);

sState.state[shift + 4] = (float)(Rates[b].high - close);

sState.state[shift + 5] = (float)(Rates[b].low - close);

sState.state[shift + 6] = (tenkan - kijun);

sState.state[shift + 7] = (float)(Rates[b].tick_volume / 1000.0f);

sState.state[shift + 8] = ((float)(Rates[b].high) - (float)(Rates[b].low));

sState.state[shift + 9] = (bandzup - bandzlo);

sState.state[shift + 10] = rsi;

sState.state[shift + 11] = cci;

sState.state[shift + 12] = atr;

sState.state[shift + 13] = macd;

sState.state[shift + 14] = sign;

sState.state[shift + 15] = mome;

sState.state[shift + 16] = (float)(Rates[b].open - tenkan);

sState.state[shift + 17] = (float)(Rates[b].open - kijun);

sState.state[shift + 18] = (float)(Rates[b].open - bandzb);

sState.state[shift + 19] = (float)(Rates[b].open - senkasa);

sState.state[shift + 20] = (float)(Rates[b].open - senkb);

sState.state[shift + 21] = (float)(Rates[b].close - tenkan);

sState.state[shift + 22] = (float)(Rates[b].close - kijun);

sState.state[shift + 23] = (float)(Rates[b].close - bandzb);

sState.state[shift + 24] = (float)(Rates[b].close - senkasa);

sState.state[shift + 25] = (float)(Rates[b].close - senkb);

sState.state[shift + 26] = senkasa - senkb;

//---

RSI.Refresh();

CCI.Refresh();

ATR.Refresh();

MACD.Refresh();

Symb.Refresh();

Momentum.Refresh();

Bands.Refresh();

Symb.RefreshRates();

// Atualizar os valores de Ichimoku para a barra atual

Ichimoku.Refresh();

//---

Imprimir ("Estado 0: ", sState.state[shift]);

Print("State 1: ", sState.state[shift + 1]);

Print("State 2: ", sState.state[shift + 2]);

Print("State 3: ", sState.state[shift + 3]);

Print("State 4: ", sState.state[shift + 4]);

Print("State 5: ", sState.state[shift + 5]);

Print("State 6: ", sState.state[shift + 6]);

Print("State 7: ", sState.state[shift + 7]);

Print("State 8: ", sState.state[shift + 8]);

Print("State 9: ", sState.state[shift + 9]);

Print("State 10: ", sState.state[shift + 10]);

Print("State 11: ", sState.state[shift + 11]);

Print("State 12: ", sState.state[shift + 12]);

Print("State 13: ", sState.state[shift + 13]);

Print("State 14: ", sState.state[shift + 14]);

Print("State 15: ", sState.state[shift + 15]);

Print("State 16: ", sState.state[shift + 16]);

Print("State 17: ", sState.state[shift + 17]);

Print("State 18: ", sState.state[shift + 18]);

Print("State 19: ", sState.state[shift + 19]);

Print("State 20: ", sState.state[shift + 20]);

Print("State 21: ", sState.state[shift + 21]);

Print("State 22: ", sState.state[shift + 22]);

Print("State 23: ", sState.state[shift + 23]);

Print("State 24: ", sState.state[shift + 24]);

Print("State 25: ", sState.state[shift + 25]);

Print("State 26: ", sState.state[shift + 26]);

Print("Tenkan Sen: ", tenkan);

Print("Kijun Sen: ", kijun);

Print("Senkou Span A: ", senkasa);

Print("Senkou Span B: ", senkb);

}

bState.AssignArray(sState.state);


JimReaper - Quantos ciclos você estudou a sua versão antes de obter o resultado da sua imagem (coleta de dados - treinamento)? E quanto tempo isso levou?


Qual é a configuração do seu computador (processador, placa de vídeo, RAM)?


Obrigado, Jim

 
Caros colegas, levo cerca de 8 horas para coletar de 5 agentes. Usei processadores de 8 núcleos. Isso é muito lento ou é normal? Por favor, compartilhem.
 
JimReaper #:
Olá, Dmitriy, eu fiz isso usando isto... isso terá o mesmo efeito?

input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1;

input double MinProfit = 10;
input int Agent = 1;
input int Optimisation = 1;

em seguida, defina o agente para 5 e a otimização para 20
Total de 100...


Olá Jim

Vejo a referência ao Agent no código, mas não vejo a Optimisation. Você fez alguma outra adição ao código para usar esse novo parâmetro?
Obrigado
Paul