Обсуждение статьи "Нейросети — это просто (Часть 66): Проблематика исследования в офлайн обучении"

 

Опубликована статья Нейросети — это просто (Часть 66): Проблематика исследования в офлайн обучении:

Обучение моделей в офлайн режиме осуществляется на данных ранее подготовленной обучающей выборки. Это дает нам ряд преимуществ, но при этом информация об окружающей среде сильно сжимается до размеров обучающей выборки. Что, в свою очередь, ограничивает возможности исследования. В данной статье хочу предложить познакомиться с методом, позволяющем наполнить обучающую выборку максимально разнообразными данными.

Метод ExORL можно разделить на 3 основных этапа. Первый этап — сбор неразмеченных исследовательских данных. Для этого возможно использование различных алгоритмов обучения без учителя. Авторы метода не ограничивают круг используемых алгоритмов. При этом в процессе взаимодействия с окружающей средой на каждом эпизоде используем политику π, зависящую от истории предыдущих взаимодействий. Каждый эпизод сохраняется в наборе данных в виде последовательности состояния St, дейcтвия At и последующего состояния St+1. Сбор обучающих данных осуществляется до полного заполнения обучающей выборки, размер которой органичен техническим заданием или доступными ресурсами.

После сбора набора данных о состояниях и действиях, осуществляется их переоценка с использованием заданной функции вознаграждения. На этом этапе просто необходимо оценить вознаграждение для каждого кортежа в наборе данных.

Практический опыт показывает о возможности параллельного использования в одном буфере воспроизведения собранных различными методами. Я использовал как траектории собранных ранее рассмотренным советником "Research.mq5", так и советником "ResearchExORL.mq5". Первый указывает на преимущества и недостатки выученной политики Актера. Второй позволяет максимально исследовать окружающую среду и оценить неучтенные возможности.

В процессе итерационного обучения модели мне удалось повысить её результативность.

Результаты тестирования

Результаты тестирования

При общем снижении количества сделок за тестовый период в 3 раза (56 против 176) прибыль увеличилась практически в 3 раза. Сумма максимальной прибыльной сделки увеличилась более чем в 2 раза. А средняя прибыльная сделка увеличилась в 5 раз. При этом мы наблюдаем рост баланса на протяжении всего периода тестирования. В итоге профит фактор модели увеличился с 1.3 до 2.96. 

Автор: Dmitriy Gizlyk

 
Дмитрий здравствуйте. У вас написано что Вы использовали 5 агентов и собрали ими 100 проходов. Те Вы запускали сбор 20 раз? Просто иначе 5 агентами будет собрано только 5 проходов. К тому же если запустить советник с одними и теме же параметрами, то он не расчитывается повторно, а подтягивает результат с кэша. Или Вы сдвигали эти  5 агентов при каждом последующем сборе? Объясните пожалуйста этот момент.
 
Viktor Kudriavtsev #:
Дмитрий здравствуйте. У вас написано что Вы использовали 5 агентов и собрали ими 100 проходов. Те Вы запускали сбор 20 раз? Просто иначе 5 агентами будет собрано только 5 проходов. К тому же если запустить советник с одними и теме же параметрами, то он не расчитывается повторно, а подтягивает результат с кэша. Или Вы сдвигали эти  5 агентов при каждом последующем сборе? Объясните пожалуйста этот момент.

Я запускал 20 раз, но перед запуском очищал кэш. Смещать агентов нельзя, так как к номеру агента привязан файл модели. Следовательно, при смещении агентов каждый раз будет создаваться новая случайная модель и мы не получим требуемого эффекта.

 
Dmitriy Gizlyk #:

I ran it 20 times, but cleared the cache before starting. You can't shift agents because the model file is linked to the agent number. Therefore, if the agents are shifted, a new random model will be created each time and we will not get the desired effect.

Hi Dmitriy, I did it by using this... will it have the same effect?

input ENUM_TIMEFRAMES         TimeFrame      =    PERIOD_H1;

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

then set agent to 5 and Optimization to 20 
Total of 100... 


 
JimReaper #:
Hi Dmitriy, I did it by using this... will it have the same effect?

input ENUM_TIMEFRAMES         TimeFrame      =    PERIOD_H1;

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

then set agent to 5 and Optimization to 20 
Total of 100... 


Hi,
How many cores you have used?

 
Dmitriy Gizlyk #:

Hi,
How many cores you have used?

I only used 4 cores. 


Файлы:
Dimi_1.png  2 kb
Dimi_2.png  5 kb
 
JimReaper #:
I only used 4 cores. 


I don't know how MetaTrader Tester select inputs for every core. Main idea in online study use pretrained model from one pass to other. But if Tester run Optimithation 1..4 to Agent 1 at one pass the they all use random (not pretrained) model.

 
Dmitriy Gizlyk #:

I don't know how MetaTrader Tester select inputs for every core. Main idea in online study use pretrained model from one pass to other. But if Tester run Optimithation 1..4 to Agent 1 at one pass the they all use random (not pretrained) model.

Understood! Thank you Very Much!

I also added some indicators and Parameters, total 27 BarDescr... Momentum, Bands & Ichimoku Kinko Hyo =)

int OnInit()

{

Set symbol and refresh

if(! Symb.Name(_Symbol))

          return 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;

Initialize the Ichimoku Kinko Hyo indicator

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()

{

//---

if(! 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();

Refresh Ichimoku values for the current bar

     Ichimoku.Refresh();

--- History Data

     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 the calculated value

float kijun = (float)Ichimoku.KijunSen(1); Use the calculated value

float senkasa = (float)Ichimoku.SenkouSpanA(2); Use the calculated value

float senkb = (float)Ichimoku.SenkouSpanB(3); Use the calculated value

Check for EMPTY_VALUE and division by 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 ||

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

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

                    {

                         continue;

                    }

Ensure buffers are not resized within the 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();

               // Refresh Ichimoku values for the current bar

               Ichimoku.Refresh();

               //---

               Print("State 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 #:
Understood! Thank you Very Much!

I also added some indicators and Parameters, total 27 BarDescr... Momentum, Bands & Ichimoku Kinko Hyo =)

int OnInit()

{

Set symbol and refresh

if(! Symb.Name(_Symbol))

          return 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;

Initialize the Ichimoku Kinko Hyo indicator

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()

{

//---

if(! 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();

Refresh Ichimoku values for the current bar

     Ichimoku.Refresh();

--- History Data

     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 the calculated value

float kijun = (float)Ichimoku.KijunSen(1); Use the calculated value

float senkasa = (float)Ichimoku.SenkouSpanA(2); Use the calculated value

float senkb = (float)Ichimoku.SenkouSpanB(3); Use the calculated value

Check for EMPTY_VALUE and division by 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 ||

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

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

                    {

                         continue;

                    }

Ensure buffers are not resized within the 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();

               // Refresh Ichimoku values for the current bar

               Ichimoku.Refresh();

               //---

               Print("State 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 - How many cycles did you study your version before getting the result in your picture? (data collection - training). And how long did it take?


What is your computer configuration (processor, video card, RAM)?


Thank you

 
Dear guys, it takes me around 8 hours to collect from 5 agents. I used 8 cores processors. Is it too slow or normal? Plz share.
 
JimReaper #:
Здравствуйте Дмитрий, я сделал это с помощью этого... будет ли такой же эффект?

input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1;

input double MinProfit = 10;
input int Агент = 1;
input int Оптимизация = 1;

затем устанавливаем агента на 5 и оптимизацию на 20
Итого 100...


Привет, Джим

Я вижу в коде ссылку на агента, но не вижу оптимизацию. Было ли дополнительное дополнение к коду, которое вы сделали, чтобы использовать этот новый параметр?
Спасибо
Пол