Оптимизация metatrader 5. Почему так долго? По сравнению с tslab в 14 раз!

 

Переписал алгоритм с tslab. Запустил тестер - и ужаснулся. То, что у меня занимало там меньше 30 секунд, здесь 7 минут. Переписал код с использование Trade библиотеки. Убрал все,  тоже условие - вход один раз на баре. И ничего более. Еще хуже стало, в два раза. Т.е. мои виртуальные позиции еще улучшают скорость теста. Может, что то не то делаю?

Опишите, как настроить под оптимизацию? Или бесполезно?  

 

К сожалению, заявление голословно:

1) нет кода

2) нет точного описания условий тестирования

3) нет логов и отчетов

Большая разница просто по готовым барам пробежаться против даже минимального моделирования OHLC и рыночных условий.

 
//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2020, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
CTrade trade;


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

input int periodLongI=10;//Период длинной скользящей
input int periodMiddleI=6;//Период средней скользящей

input ENUM_TIMEFRAMES timeframesI = PERIOD_M1;//Временной период таймфрейм

input double sharesBuyI=1;//Объем позиции лонга
input double sharesSellI=1;//Объем позиции шорта


//input ENUM_MA_METHOD typeSmoothingI = MODE_EMA;//Тип скользящей средней
//input ENUM_APPLIED_PRICE typePriceI = PRICE_CLOSE;//Используемая цена скользящей средней По закрытию

double    sharesBuy=sharesBuyI;
double   sharesSell=sharesSellI;



int barWait;

//Algorithm
bool signalBuy;
bool signalShort;

//Indicator
int handleLong;
int handleMiddle;

//DATA
double listLong[];
double listMiddle[];
int barsCount;
double price;

MqlTick tick;



//+------------------------------------------------------------------+
int OnInit()
  {
   IndicatorReturn();
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   int iMax=ChartIndicatorsTotal(0,0);
   for(int i = 0 ; i<iMax; i++)
     {
      ChartIndicatorDelete(0,0,ChartIndicatorName(0,0,i));
     }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
   DataReturn();

   if(barWait==barsCount)
     {
      return;
     }
   barWait=barsCount;


   signalBuy = listMiddle[barsCount-2]> listLong[barsCount-2];   
   signalShort = listMiddle[barsCount-2]<listLong[barsCount-2]; 
  

   
   if(PositionsTotal()<1)
     {
      
      if(signalBuy)
        {
         if( trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,1,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0))
           {
            
           }
        }
      else
         if(signalShort)
           {
            if( trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,1,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0))
              {
              
              }
           }
     }
   else
     {

      if(PositionSelect(_Symbol))
        {
        
         if((((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) && signalShort)
            ||
            ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL && signalBuy))
           {
            if(trade.PositionClose(_Symbol))
              {

              }
           }
        }
     }


  }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IndicatorReturn()
  {

handleLong=iMA(_Symbol,timeframesI,periodLongI,0,MODE_EMA,PRICE_CLOSE);
handleMiddle=iMA(_Symbol,timeframesI,periodMiddleI,0,MODE_EMA,PRICE_CLOSE);


   ChartIndicatorAdd(0,0,handleLong);
   ChartIndicatorAdd(0,0,handleMiddle);


   return true;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool DataReturn()
  {
   barsCount=SeriesInfoInteger(_Symbol,timeframesI,SERIES_BARS_COUNT);
   CopyBuffer(handleLong,0,0,barsCount,listLong);
   CopyBuffer(handleMiddle,0,0,barsCount,listMiddle);

   SymbolInfoTick(_Symbol,tick);
   if(tick.last==0)
     {
      price=tick.bid;
     }
   else
     {
      price=tick.last;
     }


   return true;
  }
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Text;


using TSLab.DataSource;
using TSLab.Script;
using TSLab.Script.GraphPane;
using TSLab.Script.Handlers;
using TSLab.Script.Helpers;
using TSLab.Script.Optimization;
using TSLab.Utils;


namespace ClassLibrary1
{
    public class TestSpeed : IExternalScript
    {

        public OptimProperty smaDlin = new OptimProperty(500, 1, 1000, 1);
        public OptimProperty smaKor = new OptimProperty(200, 1, 1000, 1);


        public static Color _ColorGreen = new Color(21, 212, 11);
        public static Color _ColorBlack = new Color(0, 0, 0);
        public static Color _ColorRed = new Color(247, 59, 69);






        public void Execute(IContext c, ISecurity s)
        {
            c.ScriptResults["EMAdlin"] = smaDlin;
            c.ScriptResults["EMAkor"] = smaKor;


            IList<double> _smaDlin = Series.EMA(s.ClosePrices, smaDlin);
            IList<double> _smaKor = Series.EMA(s.ClosePrices, smaKor);




            //Графическое отображение
            if (!c.IsOptimization)
            {
                IGraphPane panel1 = c.CreateGraphPane("Pr", "Price");
                IGraphList price = panel1.AddList("Pri", s, CandleStyles.BAR_CANDLE, _ColorGreen, PaneSides.RIGHT);
                price.AlternativeColor = _ColorRed;


                if (true)
                {

                    panel1.AddList("Dlin", _smaDlin, ListStyles.LINE, _ColorGreen, LineStyles.SOLID, PaneSides.RIGHT);
                    panel1.AddList("Kor", _smaKor, ListStyles.LINE, _ColorBlack, LineStyles.SOLID, PaneSides.RIGHT);


                }



            } //Конец Графическое отображение


            int nachBar = smaDlin;




            bool signalBuy = false;
            bool signalSell = false;



            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            for (int bar = nachBar; bar < s.Bars.Count; bar++)
            {
                signalBuy = _smaKor[bar] > _smaDlin[bar];
                signalSell = _smaKor[bar] < _smaDlin[bar];

                if (s.Positions.GetLastPositionActive(bar) == null)
                {





                    if (signalBuy)
                    {
                        s.Positions.BuyAtMarket(bar + 1, 1, "Buy");
                    }
                    if (signalSell)
                    {
                        s.Positions.SellAtMarket(bar + 1, 1, "Short");
                    }

                }

                IPosition posL = s.Positions.GetLastLongPositionActive(bar);
                if (posL != null)
                {
                    if (signalSell)
                    {
                        posL.CloseAtMarket(bar + 1, "Buy");

                        s.Positions.SellAtMarket(bar + 1, 1, "Short");

                    }

                }


                IPosition posS = s.Positions.GetLastShortPositionActive(bar);
                if (posS != null)
                {


                    if (signalBuy)
                    {

                        posS.CloseAtMarket(bar + 1, "Short");

                        s.Positions.BuyAtMarket(bar + 1, 1, "Buy");
                    }

                }

            }

        }
    }
}
 

Вот два кода. Проверяйте сами. Два теста сделал. Уже выложил, но увидел. Что котировке не было данных, поэтому 2 сделки всего было. Но при этом 7 минут и 29 секунд там что то крутилось. Второй тест уже не хочу ждать. В тслабе крутил 30 дней за 22 секунды, в метатрейдере 20 и оценка 20 минут. Бред какой то. Тестер в моих руках не работает.

 

Тслаб

 

Метатрейдер


 
vbymrf #:

Вот два кода. Проверяйте сами. Два теста сделал. Уже выложил, но увидел. Что котировке не было данных, поэтому 2 сделки всего было. Но при этом 7 минут и 29 секунд там что то крутилось. Второй тест уже не хочу ждать. В тслабе крутил 30 дней за 22 секунды, в метатрейдере 20 и оценка 20 минут. Бред какой то. Тестер в моих руках не работает.

На каждом тике копировать весь M1 буфер, который может достигать 100 MB при UNLIMITED bars. Причем два раза. Вместо того, чтобы скопировать только недостоющие с последнего раза бары (как правило - один)

input ENUM_TIMEFRAMES timeframesI = PERIOD_M1;//Временной период таймфрейм
...

void OnTick()
  {
   DataReturn();

...

bool DataReturn()
  {
   barsCount=SeriesInfoInteger(_Symbol,timeframesI,SERIES_BARS_COUNT);
   CopyBuffer(handleLong,0,0,barsCount,listLong);
   CopyBuffer(handleMiddle,0,0,barsCount,listMiddle);

Улыбнуло.

Короче, как обычно: чем меньше понимания, тем больше претензий. 
 
Nikolai Semko #:

На каждом тике копировать весь M1 буфер, который может достигать 100 MB при UNLIMITED bars. Причем два раза. Вместо того, чтобы скопировать только недостоющие с последнего раза бары (как правило - один)

Улыбнуло.

Короче, как обычно: чем меньше понимания, тем больше претензий. 

Да, увидел. Все равно раза от 7 раз тслаб быстрее

 

Расходимся.

Это очередной писатель цикла for на готовых барах:

for (int bar = nachBar; bar < s.Bars.Count; bar++)

Такие системы я в 1999 году писал. Даже в первом MQL в 2001 году было простейшее моделирование тиков, а не чистый цикл по сформировавшимся барам.

Сейчас требования к сложности и точности моделирования на пару порядков выше.

Ознакомьтесь со следующими статьями, которые раскрывают важность потикового моделирования, включая точное мультивалютное и учет проскальзывания при исполнении:


Про тестер много написано тут: https://www.mql5.com/ru/articles/mt5/strategy_tester
Алгоритм генерации тиков в тестере стратегий терминала MetaTrader 5
Алгоритм генерации тиков в тестере стратегий терминала MetaTrader 5
  • www.mql5.com
MetaTrader 5 позволяет во встроенном тестере стратегий моделировать автоматическую торговлю с помощью экспертов на языке MQL5. Такое моделирование называется тестированием экспертов, и может проводиться с использованием многопоточной оптимизации и одновременно по множеству инструментов. Для проведения тщательного тестирования требуется генерировать тики на основе имеющейся минутной истории. В статье дается подробное описание алгоритма, по которому генерируются тики для исторического тестирования в клиентском терминале MetaTrader 5.
 
Renat Fatkhullin #:

Расходимся.

Это очередной писатель цикла for на готовых барах:

Такие системы я в 1999 году писал. Даже в первом MQL в 2001 году было простейшее моделирование тиков, а не чистый цикл по сформировавшимся барам.

Сейчас требования к сложности и точности моделирования на пару порядков выше.

Ознакомьтесь со следующими статьями, которые раскрывают важность потикового моделирования, включая точное мультивалютное и учет проскальзывания при исполнении:


Про тестер много написано тут: https://www.mql5.com/ru/articles/mt5/strategy_tester

И много вам дало моделирование тиков? На рынке итак полно случайностей. Так вы её ещё моделируете!

В проскальзывание я верю только реальное. Тупо запустите сканер стакана и тогда уже моделируйте случайных вход и выход. За несколько дней вы соберете реальное проскальзывание для вашего объема и котировки для любой стратегии. 

 

Корректно сравнивать безындикаторные советники, чтобы избежать случаев плохого кода, включая получение баров.

Идеально - на каждом входе берется только новый тик и больше ничего.


MT5-тестер имеет производительность в несколько миллионов тиков в секунду на одно ядро. Оптимизатор задействует много ядер. Поэтому во время оптимизации молотится по несколько десятков миллионов тиков в секунду. TSLab ни при каких раскладах не сможет обеспечивать (как заявляется в ветке) около миллиарда тиков в секунду. Это технически почти невозможно.