بهینه‌سازی ربات معاملاتی در ترید واقعی

بهینه‌سازی ربات معاملاتی در ترید واقعی

مقدمه

همه فکر می‌کنند اکسپرتی که ورودی‌هایش مطابق با هیستوری تنظیم شده‌اند، در همان بار اول (و ترجیحاً) در مدت زمان کمی، قرار است به ما سود بدهد و سود بدهد… به‌طور غیرمستقیم تاییده‌هایی درباره‌ی این فرضیه، بعد از آنکه رقابت‌های قهرمانی ترید در سال ۲۰۰۶ را تماشا کردم، به گوش من رسیدند. وقتی این رقابت آغاز شد، اکسپرت‌های سوددده بسیاری نسبت به قبل در رقابت حاضر بودند، اما بعداً مشخص شد برخی از آنها اصلاً به درد رقابت نمی‌خورند. فکر می‌کنم دلیلش این باشد که بیشتر آن اکسپرت‌هایی که به خط پایان نرسیدند، فقط مطابق با هیستوری تنظیم شده بودند.

ایده‌ی بررسی این فرضیه در عمل، در انجمن روسی این وب‌سایت، در بخش سیستم‌های ایده‌آل برای ترید خودکار، متولد شد. ایده‌ی اصلی این است که بهینه‌سازی یک اکسپرت را یک بار در روز، انجام دهیم و سپس نتایج بدست‌آمده از بهینه‌سازی را تحلیل کرده و آن‌ها را در متغیرهای اکسپرت ثبت کنیم.

برای اجرای این ایده، تصمیم گرفتیم از اکسپرت آماده، یعنی MACD Sample، در نرم‌افزار متاتریدر ۴ استفاده کنیم و تابع بهینه‌سازی خودکار خودمان را درون آن وارد کنیم. کمی بعد، کد آن بهینه‌سازِ خودکار، آماده بود، و در همان انجمن در بخش بهینه‌ساز خودکار، آپلود شد. بعد از گذشت مدتی، اولین تاییدها درباره‌‌ی این ایده در همان جا ظاهر شدند. سپس، بهینه‌ساز ما به یک کتابخانه‌ی mqh برای به‌کارگیری بهتر، منتقل شد.

نصب بهینه‌ساز خودکار

برای انجام این کار مراحل زیر را طی کنید:

  • MACD Sample_1.mq4 را در پوشه‌ی “expert” نرم‌افزار متاتریدر ۴ کپی کنید. قطعاً نرم‌افزار باید به اینترنت متصل باشد، و
  • این پوشه، همراه با نرم‌افزار متاتریدر ۴ را در یک جای جدید کپی کنید.

برای راحتی کار، از اینجا به بعد، نرم‌افزار اصلی [متاتریدر] را “نرم‌افزار / Terminal” و کپی آن را “Terminal-Tester” می‌نامیم. با همان اکسپرتی که به‌طور پیش‌فرض در خود نرم‌افزار بود، و ما کمی آن را تغییر دادیم، یعنی MACD Sample_1.mq4، در تایم‌فریم H1، روی EURUSD، یک تست می‌گیریم.

نصب بهینه‌ساز خودکار

Terminal-Tester Setup

یادتان نرود حتماً MACD Sample_1.mq4 را در Terminal-Tester کامپایل کنید. ابتدا نرم‌افزار (Client Terminal) را باز کرده و سپس سراغ استراتژی‌تستر بروید. باید مطابق با تصویر زیر آن را تنظیم کنید.

Terminal-Tester Setup

بهینه‌سازی برای سه روز انجام خواهد شد. سه روز برای بررسی بهینه‌ساز خودکار کاملاً خوب و کافی است. تاربخ بهینه‌سازی (“From”) را مطابق با این فرمول انتخاب می‌کنیم: تاریخ کنونی منهایِ سه روز. حین بهینه‌سازی، هیستوری مورد نیاز برای اَرز انتخاب‌شده (در اینجا EURUSD) باید دانلود شود.

کسانی که بهینه‌سازی را برای اولین بار انجام می‌دهند، می‌توانند توضیحات مربوط به روش انجام کار را در منوی Help نرم‌افزار متاتریدر ۴، بیابند: <Help – Help Topics F1 – Auto Trading – Expert Optimization – Setup>. یا اینکه می‌توانند این مقاله را بخوانند: Testing of Expert Advisors in the MetaTrader 4 Client Terminal: An Outward Glance.

همانطور که در تصویر زیر نشان داده شده‌است، متغیرها را برای بهینه‌سازی انتخاب می‌کنیم.

Terminal-Tester Setup

بهینه‌سازی خودکار محدود به ۴ متغیر است، اما به‌منظور از دست ندادن زمان، داشتن فقط سه متغیر هم کار ما را راه می‌اندازد و کافیست. بعد از اینکه متغیرها انتخاب شدند، بیایید تنظیمات بهینه‌سازی را در فایل تنظیمات به‌نام MACD Sample_1.set، ذخیره کنیم. این فایل باید در پوشه‌ای از Terminal-Tester ذخیره شود که نام آن پوشه “tester” است. سپس پیش-بهینه‌سازی (pre-optimization) را اجرا کرده و زمان شروع را نیز به‌یاد داشته باشید. این کار برای محاسبه‌ی دوره‌ی زمانیِ مورد نیاز برای بهینه‌سازی خودکار با پارامترهای از پیش تعیین‌شده، لازم است. بعد از اینکه بهینه‌سازی تمام شد، زمان انتظار لازم را محاسبه خواهیم کرد. سپس باید این نرم‌افزار را ببندیم، چراکه، درغیر‌این‌‌صورت، قادر نخواهیم بود آن را برنامه‌ریزی‌شده اجرا کنیم.

تنظیمات اکسپرتی که در نرم‌افزار قرار دارد

برای انجام این کار، بیایید اکسپرت آزمایشی MACD Sample_1.mq4 را در متااِدیتور باز کرده و کارهای زیر را انجام دهیم:

– زمان شروع بهینه‌سازی خودکار را تعیین کنید، برای مثال، هر روز ساعت ۰۰:۰۱:

datetime SetHour    = 0;  // Optimization starting hour; 
        datetime SetMinute  = 1;  // Optimization starting minute.

– تعداد روزها برای بهینه‌سازی را تعیین کنید (تعداد روزها باید برابر با تعداد روزهای تعیین‌شده برای         پیش-بهینه‌سازی باشد):

int TestDay = 3;

– زمان بهینه‌سازی و زمان انتظار، که قبلاً محاسبه کرده‌ایم، را در واحد دقیقه تعیین کنید. برای مثال، ۴ دقیقه:

int TimeOut = 4;

– نام اکسپرت را وارد کنید:

string NameMTS = "MACD Sample_1";  // EA's name

– نام فایل تنظیمات، همراه با تنظیمات را وارد کنید:

// Set-file name with the settings
        string NameFileSet = "MACD Sample_1.set";

– مسیر پوشه‌ای که Terminal-Tester نصب‌شده درون آن است را وارد کنید، برای مثال:

// Path to the tester        
        string PuthTester = "D:\Program Files\Forex Best Trade Station";

– اولویت فیلترینگ را مشخص کنید:

// Sorting by Maximal profit
        int Gross_Profit = 1;                      
        // Sorting by Maximal profit factor        
        int Profit_Factor = 2;     
        // Sorting by Maximal expected payoff
        int Expected_Payoff = 3;

– نام متغیرها را جهت بهینه‌سازی بنویسید:

string Per1 = "FastEMA";
        string Per2 = "SlowEMA";
        string Per3 = "SignalSMA";
        string Per4 = "";

– فایل پیوست‌شده‌ی auto_optimization.mqh را در پوشه‌ی “include” کپی کنید؛

– فایل کتابخانه (library file) را در اکسپرت وارد کنید:

//--- Including the auto optimizer's library
#include <auto_optimization.mqh>

– فقط این باقی می‌ماند که کد زیر را در ابتدای تابع start() اکسپرت خودتان کپی کنید.   MACD Sample_1.mq4 این بخش را در خود دارد (نیازی به این کار نیست).

// Not to be launched at testing and optimizing   
  if(!IsTesting() && !IsOptimization())
    {                
      // Compare the current hour with that preset for launching
      if(TimeHour(TimeLocal()) == SetHour)
        {
          // Protection against restarting
          if(!StartTest)
            {
              // Compare the minute range to the minute
              // preset for launching
              if(TimeMinute(TimeLocal()) > SetMinute - 1)
                {     
                  // the range is necessary, in case that for some reasons 
                  // no new tick is available for a long time
                  if(TimeMinute(TimeLocal()) < SetMinute + 1)
                    {  
                      // Flag of tester launching
                      StartTest    = true;
                      TimeStart    = TimeLocal();
                      Tester(TestDay, NameMTS, NameFileSet, PuthTester, 
                             TimeOut, Gross_Profit, Profit_Factor, 
                             Expected_Payoff, Per1, Per2, Per3, Per4);
                    
                    }
                }
            }
        }
    }
    
                        
   FastEMA      = GlobalVariableGet(Per1);
   SlowEMA      = GlobalVariableGet(Per2);
   SignalSMA    = GlobalVariableGet(Per3);
   TrailingStop = GlobalVariableGet(Per4);  
// If the tester launching is flagged  
  if(StartTest)
    {                                        
      // If more time has elapsed the launching than it was set 
      // to be the test waiting time
      if(TimeLocal() - TimeStart > TimeOut*60)
        {            
          // Zeroize the flag
          StartTest = false;                              
        }
    }

کار همین بود. بعد از اینکه بهینه‌ساز خودکار، مجدد کامپایل شد، می‌توانید آن را اجرا کنید. اما شاید فقط بتوانید آن را برای همان اَرز و تایم‌فریمی استفاده کنید که پیش-‌بهینه‌سازی برای آن‌ها انجام شده‌است. در اینجا می‌شود: EURUSD در تایم‌فریم H1. برای بررسی بهینه‌ساز خودکار، می‌توانید کدی که در پایین آورده شده‌است را در تابع int init() وارد کرده، آنگاه بهینه‌ساز خودکار هنگام شروع به‌ کار اکسپرت، [با آن] اجرا خواهد شد.

Tester(TestDay,NameMTS,NameFileSet,PuthTester,TimeOut, Gross_Profit,Profit_Factor, 
       Expected_Payoff, Per1,Per2,Per3,Per4);

بهینه‌ساز خودکار چگونه کار می‌کند؟

بهینه‌ساز خودکار برمبنای استفاده از Terminal-Tester جهت بهینه‌سازی پارامترهای اکسپرتی که روی نمودار Terminal اجرا شده‌است، کار می‌کند. برای انجام این کار، برنامه، فایلی را به Terminal-Tester می‌فرستد که شامل پارامترهای بهینه‌سازی می‌شود (optimise.ini) و Terminal-Tester را در حالت بهینه اجرا می‌کند. سپس، نتایج بدست‌آمده از “FileReport……..htm” را در Terminal کپی می‌کند و بهترین مقادیر نتایج بدست‌آمده را فیلتر می‌کند.

بهینه‌ساز خودکار چگونه کار می‌کند

جزئیات بیشتر درباره‌ی چگونگی عملکرد بهینه‌ساز خودکار

در زمان از پیش تعیین‌شده، برای مثال، ۰۰:۰۱، بهینه‌ساز خودکار باید اجرا شود. متغیرها نیز باید با مقادیر پُر شوند.

// Path to the terminal 
string PuthTerminal = TerminalPath() + "\experts\files";
// Name of the ini file for the tester
string FileOptim    = "optimise.ini";
string FileOptim1   = "\optimise.ini";                                  
// Calculation of the starting date
datetime DayStart   = TimeLocal()-86400*TestDay;
// Optimization starting date
string DateStart    = TimeToStr(DayStart,TIME_DATE);
// Optimization ending date
string DateStop     = TimeToStr(TimeLocal(),TIME_DATE);
// Tester report file name
string FileReport   = "FileReport_" + Symbol() + "_" + DateStop + ".htm";
string FileReport1  = "\FileReport_" + Symbol() + "_" + DateStop + ".htm";
// Limitation for the minimum amount of trades per day
double MinTr        = TestDay - 2;
// Limitation for maximal amount of trades per day
double MaxTr        = (60 / Period()*TestDay) + 2;
// The amount of attempts to copy the report file
int    KvoPptk      = 10;
// The amount of lines for sorting
int    StepRes      = 12;

آنگاه پارامترهای فایل ini در آرایه رشته‌ای نوشته می‌شوند:

// Prepare the ini file for optimization
ArrayOpttim[0] = ";optimise strategy tester";             
// Enable/Disable Expert Advisors
ArrayOpttim[1] = "ExpertsEnable = false";
// Name of the EA file
ArrayOpttim[2] = "TestExpert=" + NameMTS;
// Name of the file containing parameters
ArrayOpttim[3] = "TestExpertParameters=" + NameFileSet;
// Symbol
ArrayOpttim[4] = "TestSymbol=" + Symbol();
// Timeframe
ArrayOpttim[5] = "TestPeriod=" + Period();
// Modeling mode
ArrayOpttim[6] = "TestModel=" + 0;
// Recalculate
ArrayOpttim[7] = "TestRecalculate=false";
// Optimization
ArrayOpttim[8] = "TestOptimization=true";
// Use date
ArrayOpttim[9] = "TestDateEnable=true";
// From
ArrayOpttim[10] = "TestFromDate=" + DateStart;
// To
ArrayOpttim[11] = "TestToDate=" + DateStop;
// Report file name
ArrayOpttim[12] = "TestReport=" + FileReport;
// Rewrite the report file
ArrayOpttim[13] = "TestReplaceReport=true";
// Shut down the terminal upon completion
ArrayOpttim[14] = "TestShutdownTerminal=true";

پارامترهای بهینه‌سازی از آرایه (array) درون فایل ini ثبت می‌شوند. می‌توانید در بخش Help نرم‌افزار متاتریدر ۴، درباره‌ی اینکه چگونه فایل‌های ini ایجاد می‌شوند، مطالعه داشته باشید. <Help – Help Topics F1 – Tools – Configuration at Startup>.

// Write data into the ini file                
// Find out about the array size
OptimArraySize = ArraySize(ArrayOpttim);
// Open a file to write
opttim = FileOpen(FileOptim, FILE_CSV|FILE_WRITE, 0x7F);
if(opttim > 0)
  {
    for(int i = 0; i < OptimArraySize; i++)
      {
        // from the array into the variable
        ini = ArrayOpttim[i];                                     
        // from the variable into the file
        FileWrite(opttim, ini);
      } 
    // close the file
    FileClose(opttim);
  }
else
  {
    Print("Failed writing data into the ini file. Error No ", 
          GetLastError());
    return(0);
  }

بعد از اینکه پارامترها در فایل ini ذخیره شدند، shell32.dll موجود در standard Windows delivery، متصل شده و تابع ShellExecuteA اجرا می‌شود.

#import  "shell32.dll"               //Connect a dll (provided with Windows)       
  int ShellExecuteA(int hwnd,string Operation,string 
                    File,string Parameters,string Directory,int ShowCmd); 
#import

فایلی که حاوی پارامترها است، به پوشه‌ی Terminal Tester فرستاده خواهد شد.

// copy the ini file into the tester folder 
copyini = ShellExecuteA(0,"Open","xcopy", "\"" + PuthTerminal + 
                        FileOptim1 + "\" \"" + PuthTester + "\" /y", 
                        "", ۳);
// wait until the file is copied
Sleep(1200);                                                    
if(copyini < 0)
  {
    Print("Failed copying ini file");
    return(0);
  }

آنگاه تستر اجرا شده و شروع به بهینه‌سازی متغیرهای از پیش تعریف‌شده، می‌کند. اکسپرت حین بهینه‌سازی، در وضعیت ساکن (توقف) قرار دارد.

// Start Tester 
start = ShellExecuteA(0, "Open", "terminal.exe", FileOptim,
                      PuthTester, 3);
if(start < 0)
  {
    Print("Failed starting Tester");
    return(0);
  }
Comment("Wait until optimization is complete");
// wait until optimization is complete
Sleep(60000*TimeOut);

بعد از اینکه بهینه‌سازی کامل شد، تستر به‌طور خودکار نتایج را در فایل گزارش ثبت می‌کند. این فایل به پوشه‌ای کپی می‌شود که نرم‌افزار درون آن است.

for(Pptk = 0; Pptk < KvoPptk; Pptk++)
  {                    
    //Start a cycle attempting to compy the resport file
    Comment("Attempt # " + Pptk + " to copy the report file");
    ShellExecuteA(0, "Open", "xcopy", "\"" + PuthTester + FileReport1 + 
                  "\" \"" + PuthTerminal + "\" /y", "", 3);
    // wait until the file is copied
    Sleep(1200);
    // Try to open the report file
    file = FileOpen(FileReport, FILE_READ, 0x7F);
    if(file < 0)
      {
        // if it fails to open, wait some more and try again
        Sleep(60000);
      }                    
    else 
        break;             
  }
if(file < 0)
  {
    Print("Failed copying the report file");
    return(0);
  }

آنگاه داده‌های فایل گزارش، در آرایه رشته‌ای جهت پردازش‌های بیشتر، جای می‌گیرند.

// Read from file into the array
// Cycle, until the file ends
while(FileIsEnding(file) == false)
  {                 
    // Read a string from the report file
    FileLine = FileReadString(file);
    // Find the necessary string and set the reference point there
    index = StringFind(FileLine, "title", 20);
    if(index > 0)
      {
        // Increase the array in size
        ArrayResize(ArrayStrg, NumStr + 1);
        // Record the strings from the file in the array
        ArrayStrg[NumStr] = FileLine;
        NumStr++;
      }
  }
// Close the file
FileClose(file);
// Delete the file in order not to produce too many copies
FileDelete(FileReport);
// Set the array size by the amount of data read from the file
ArrayResize(ArrayData, NumStr);

آنگاه مقادیر مورد نیاز در آرایه، انتخاب می‌شوند:

for(text = 0; text < NumStr; text++)
     {
      select = ArrayStrg[text]; 
    //-------------------------------------------------------------------------
    //   Reporting text processing (These are apples and oranges)              | 
    //-------------------------------------------------------------------------
    // Position Pass 
    ClStep=StringFind(select, "; \">",20)+4;
    // Find the end of position
    ClStepRazm = StringFind(select, "td>", ClStep);
    // Read the value
    CycleStep = StringSubstr(select, ClStep, ClStepRazm - ClStep);
    // Position Profit 
    // Find the beginning of the position
    GrProf = StringFind(select, "", ClStepRazm);
    // Find the end of position
    GrProfRazm = StringFind(select, "td>", GrProf);
    // Read value
    GrossProfit = StringSubstr(select, GrProf+4, GrProfRazm - (GrProf + 4));
    // Position Total Trades
    // Find the beginning of position
    TotTrad = StringFind(select, "", GrProfRazm);
    // Find the end of position
    TotTradRazm = StringFind(select, "td>", TotTrad);
    // Read the value
    TotalTrades = StringSubstr(select, TotTrad+4, TotTradRazm - 
                               (TotTrad + 4));
    // Position Profitability
    // Find the beginning of position
    ProfFact = StringFind(select, "", TotTradRazm);
    // Find the end of position
    ProfFactRazm = StringFind(select, "td>", ProfFact);
    // Read the value
    ProfitFactor = StringSubstr(select, ProfFact + 4, ProfFactRazm - 
                                (ProfFact + 4));
    // Position Expected Payoff 
    // Find the beginning of position
    ExpPay = StringFind(select, "", ProfFactRazm);
    // Find the dn of position
    ExpPayRazm=StringFind(select, "td>", ExpPay);
    // Read the value
    ExpectedPayoff = StringSubstr(select, ExpPay+4, ExpPayRazm - 
                                  (ExpPay + 4));
    // Variables' positions starting with the second one
    // Find the beginning of position
    P1 = StringFind(select, Per1, 20);
    // Find the end of position
    P1k = StringFind(select, ";", P1);
    // Read the Variable
    Perem1 = StringSubstr(select, P1 + StringLen(Per1) + 1, P1k - 
                          (P1 + 1 + StringLen(Per1)));
    // Find the beginning of position
    P2 = StringFind(select, Per2, 20);
    // Find the end of position
    P2k = StringFind(select, ";", P2); 
    // Read the Variable
    Perem2 = StringSubstr(select, P2 + StringLen(Per2) + 1, P2k - 
                          (P2 + 1 + StringLen(Per2)));
    // Find the beginning of position
    P3 = StringFind(select, Per3, 20);
    // Find the end of position
    P3k = StringFind(select, ";", P3);
    // Read the Variable
    Perem3 = StringSubstr(select, P3 + StringLen(Per3) + 1, P3k - 
                          (P3 + 1 + StringLen(Per3)));
    // Find the beginning of position
    P4 = StringFind(select, Per4, 20);
    // Find the end of position
    P4k = StringFind(select, ";", P4);
    // Read the Variable 
    Perem4 = StringSubstr(select, P4 + StringLen(Per4) + 1, P4k - 
                          (P4 + 1 + StringLen(Per4)));
    Comment("The obtained results are being analyzed");

بعد از آن، نتایح بدست‌آمده، قبل از اینکه به‌شکل عددی در بیایند، فیلتر می‌شوند، و حداقل و حداکثر مقدار معاملات مشخص می‌شوند. صفر در مقدار Profit_Factor، جای خودش را به‌خاطر مرتب‌سازی صحیح و پس از آن غربالگری، به ۱۰۰۰ می‌دهد.

// Transform into number format
TotalTradesTransit = StrToDouble(TotalTrades);
GrossProfitTransit = StrToDouble(GrossProfit);
ExpectedPayoffTran = StrToDouble(ExpectedPayoff);
nodubl = true;
if(MinTr < TotalTradesTransit && MaxTr > TotalTradesTransit)
  {                    
    // Filter by the amount of trades
    PrFactDouble = StrToDouble(ProfitFactor);
    // Replace 0 in the Profit_Factor for proper analysis
    if(PrFactDouble == 0)
      {
        PrFactDouble = 1000;
      }

 

سپس مقادیر بررسی می‌شوند تا تکراری در میان آن‌ها نباشد و آنگاه فیلتر می‌شوند.

// Filter data having identical values
for(Dubl = 0; Dubl <= ResizeArayNew; Dubl++)
  {                    
    // Start the loop searching for identical values
    if(GrossProfitTransit == ArrayData[Dubl][1])
      {          
        // check whether the results for maximal profit coincide
        if(TotalTradesTransit == ArrayData[Dubl][2])
          {       
            // check whether the results for the amount of trades coincide
            if(PrFactDouble == ArrayData[Dubl][3])
              {          
                // check whether the results for Profit Factor coincide
                if(ExpectedPayoffTran == ArrayData[Dubl][4])
                  { 
                    // check whether the results for expected payoff coincide
                    nodubl=false;                              
                    // If everything coincides, flag it as coincided
                  }
              }
          }
      }
  }

بعد از آن، مقادیری که برای مرتب‌سازی آماده شده‌اند، در آرایه نوشته می‌شوند.

// Write the filtered data in the array
if(nodubl)
  {
    ArrayData[text][1] = GrossProfitTransit;                                
    ArrayData[text][2] = TotalTradesTransit;
    ArrayData[text][3] = PrFactDouble;
    ArrayData[text][4] = ExpectedPayoffTran;
    ArrayData[text][5] = StrToDouble(Perem1);
    ArrayData[text][6] = StrToDouble(Perem2);
    ArrayData[text][7] = StrToDouble(Perem3);
    ArrayData[text][8] = StrToDouble(Perem4);
    ResizeArayNew++; 
  }

آنگاه داد‌ه‌ها را به ترتیب اولویتی که از پیش تعیین شده‌است، آنالیز می‌کنند. آنالیز به این شکل انجام می‌شود:

  • حلقه اجرا می‌شود، و در گام اول (first pass)، مقادیر بر اساس اولین پارامتر مرتب می‌شوند، برای مثال، بر اساس حداکثر سود؛ چند تا از بهترین مقادیر انتخاب شده‌اند (۱۲، به‌طور پیش‌فرض)، و بقیه حذف می‌شوند؛
  • در گام دوم، مقادیر بر اساس پارامتر دوم، مرتب می‌شوند، برای مثال، بر اساس Profit Factor؛ برخی از بهترین مقادیر انتخاب می‌شوند، نیمی از آنها بعد از اولین مرتب‌سازی، و بقیه حذف می‌شوند.
  • و در گام سوم، مرتب‌سازی آخر بر اساس پارامتر سوم انجام می‌شود، برای مثال، بر اساس بازپرداخت مورد انتظار؛ نیمی از مقادیر بعد از مرتب‌سازی دوم اخذ می‌شوند و بقیه حذف می‌گردند.
// Analyzer
// Analyzing principle is the sequential checking of maximal 
// values according to the predefined filtering priority   
ArrayResize(ArrayTrans, ResizeArayNew - 1);
for(int PrioStep = 1; PrioStep < 4; PrioStep++)
  {
    for(PrCycle = 0; PrCycle < ResizeArayNew; PrCycle++)
      {
        Sort     = ArrayData[PrCycle][0];
        Prior1   = ArrayData[PrCycle][1];             
        transit  = ArrayData[PrCycle][2];
        Prior2   = ArrayData[PrCycle][3];             
        Prior3   = ArrayData[PrCycle][4];             
        transit1 = ArrayData[PrCycle][5];
        transit2 = ArrayData[PrCycle][6];
        transit3 = ArrayData[PrCycle][7];
        transit4 = ArrayData[PrCycle][8]; 
           
        if(PrioStep == 1)
          {
            //Prepare for the 1st sorting
            if(Gross_Profit ==1)
              {
                SortTrans = Prior1;
              }
            if(Profit_Factor == 1)
              {
                SortTrans = Prior2;
              }
            if(Expected_Payoff == 1)
              {
                SortTrans = Prior3;
              }
          }
        if(PrioStep == 2)
          {
            // Restore
            if(Gross_Profit ==1)
              {
                Prior1 = Sort;
              }
            if(Profit_Factor == 1)
              {
                Prior2 = Sort;
              }
            if(Expected_Payoff == 1)
              {
                Prior3 = Sort;
              } 
            //Prepare for the 2nd sorting
            if(Gross_Profit == 2)
              {
                SortTrans = Prior1;
              }
            if(Profit_Factor == 2)
              {
                SortTrans = Prior2;
              }
            if(Expected_Payoff == 2)
              {
                SortTrans = Prior3;
              }
          }
        if(PrioStep == 3)
          {
            // Restore
            if(Gross_Profit == 2)
              {
                Prior1 = Sort;
              }
            if(Profit_Factor == 2)
              {
                Prior2 = Sort;
              }
            if(Expected_Payoff == 2)
              {
                Prior3 = Sort;
              } 
            //Prepare for the 3rd sorting
            if(Gross_Profit ==3)
              {
                SortTrans = Prior1;
              }
            if(Profit_Factor == 3)
              {
                SortTrans = Prior2;
              }
            if(Expected_Payoff == 3)
              {
                SortTrans = Prior3;
              }
          }          
        ArrayTrans[PrCycle][0] = SortTrans;
        ArrayTrans[PrCycle][1] = Prior1;
        ArrayTrans[PrCycle][2] = transit;
        ArrayTrans[PrCycle][3] = Prior2;
        ArrayTrans[PrCycle][4] = Prior3;
        ArrayTrans[PrCycle][5] = transit1;
        ArrayTrans[PrCycle][6] = transit2;
        ArrayTrans[PrCycle][7] = transit3;
        ArrayTrans[PrCycle][8] = transit4;
      }
    ArraySort(ArrayTrans,StepRes, 0, MODE_DESCEND); // Sort the array
    ArrayResize(ArrayTrans, StepRes);               // Cut off the unnecessary things
    for(int CopyAr = 0; CopyAr < StepRes; CopyAr++)
      {
        ArrayData[CopyAr][0] = ArrayTrans[CopyAr][0];
        ArrayData[CopyAr][1] = ArrayTrans[CopyAr][1];
        ArrayData[CopyAr][2] = ArrayTrans[CopyAr][2];
        ArrayData[CopyAr][3] = ArrayTrans[CopyAr][3];
        ArrayData[CopyAr][4] = ArrayTrans[CopyAr][4];             
        // Per1    Variable 1
        ArrayData[CopyAr][5] = ArrayTrans[CopyAr][5];              
        // Per2    Variable 2
        ArrayData[CopyAr][6] = ArrayTrans[CopyAr][6];
        // Per3    Variable 3
        ArrayData[CopyAr][7] = ArrayTrans[CopyAr][7];
        // Per4    Variable 4
        ArrayData[CopyAr][8] = ArrayTrans[CopyAr][8];
      }
   StepRes = StepRes / 2;
  }

مقادیری که به این سبک فیلتر شده‌اند، در متغیرهای جهانی نوشته می‌شوند. مقادیر متغیرهای جهانی در اکسپرت ما جایگزین می‌گردند.

// Write the obtained results in variables
   double Peremen1 = ArrayTrans[0][5];                         
   double Peremen2 = ArrayTrans[0][6];
   double Peremen3 = ArrayTrans[0][7];
   double Peremen4 = ArrayTrans[0][8];
   // If the variable name is specified, write the result in 
   // global variables
   if(Per1 != "")
     {
       GlobalVariableSet(Per1, Peremen1);
     }             
   if(Per2 != "")
     {
       GlobalVariableSet(Per2,Peremen2);
     }
   if(Per3 != "")
     {
       GlobalVariableSet(Per3,Peremen3);
     }
   if(Per4 != "")
     {
       GlobalVariableSet(Per4,Peremen4);
     }
   Comment(Per1, " ", Peremen1, "  | ", Per2, " ", Peremen2, "  | ", Per3, 
           " ", Peremen3, "  | ", Per4, " ", Peremen4);
   Print(Per1, " ", Peremen1, "  | ", Per2, " ", Peremen2, "  | ", Per3, 
         " ", Peremen3,"  | ",Per4," ",Peremen4);
  }  // Function ends. That's all, automated optimization is complete.

نتایج عملکرد بهینه‌ساز خودکار

نتایج عملکرد بهینه‌ساز خودکار را می‌توانید با استفاده از پیام‌هایی که در گوشه‌ی سمت چپ، بالای نمودار، ظاهر می‌شوند، مشاهده کنید. تصویر زیر مثالی از این موضوع است:

نتایج عملکرد بهینه‌ساز خودکار

زمان مرجع تکمیل بهینه‌سازی[۱].

نتایج عملکرد بهینه‌ساز خودکار

تحلیل مقادیر بدست‌آمده بعد از بهینه‌سازی.

تحلیل مقادیر بدست‌آمده بعد از بهینه‌سازی.

مقادیر نتیجه‌یِ متغیرها[۲].

اگر نتایج بهینه‌سازی در پیام ظاهر شد، بدان معناست که بهینه‌سازی تمام شده‌است و داده‌ها دریافت شده‌اند.

برای اینکه بتوانیم به‌صورت جداگانه، کار بهینه‌ساز خودکار را ارزیابی کنیم، ممکن است بگویید تمام فایل‌هایی را که حاوی داده‌های متوسط هستند و حین فرآیند کاری ذخیره‌ شده‌اند را، باید بررسی کنیم. تستر، داده‌ها را در فایلی با نام “FileReport_EURUSD_2007.03. 12.htm” ذخیره می‌کند، که در آن نماد (symbol) و داده‌ها در نام فایل، مطابق با نماد انتخاب‌شده و تاریخ کنونی بهینه‌سازی، جایگزین می‌شوند. این فایل را می‌توانید در پوشه‌ی Terminal-Tester پیدا کنید. این فایل‌ها همراه با گزارش‌ها به‌طور خودکار پاک نمی‌شوند، بنابراین فرد می‌تواند از آن‌ها برای بررسی تغییرات پارامترها استفاده کند.

مقادیر نتیجه‌یِ متغیرها

فایل بعدی، FileTest1.csv، بعد از اینکه مقادیر فیلتر شدند و مقدار معاملات مشخص شد، و کپی‌ها حذف شدند، ذخیره می‌شود. مسیر ذخیره‌ی این فایل: D:\Program Files\terminal_folder_name\experts\files

مقادیر نتیجه‌یِ متغیرها

سپس مقادیری که پس از هر مرحله غربالگری بدست می‌آید، درون FileTest2.csv ذخیره می‌شوند. این فایل هم در همان پوشه‌ی قبلی ذخیره می‌شود.

مقادیر نتیجه‌یِ متغیرها

جدول بالا نشان می‌دهد که چگونه مقادیر بدست‌آمده فیلتر شده‌اند. ترتیب فیلترینگ به‌طور پیش‌فرض اینگونه تعیین شده‌است: ۱- Gross_Profit، ۲- Profit_Factor، ۳- Expected_Payoff.

کد بهینه‌ساز خودکار حاوی کامنت‌هایی با جزئیات است، و در صورت نیاز می‌توانید بهترین پارامترهای متغیر را انتخاب کنید. برای مثال، قصد دارید اکسپرت خود را برای یک بازه‌ی زمانی غیر از روز‌های اخیر بهینه‌سازی کنید، یا می‌خواهید مقدار معاملات را در دوره‌ی بهینه‌سازی، کاهش/افزایش دهید. برای انجام این کار می‌بایستی مستقیماً متغیرهای مربوطه را در auto_optimization.mqh تغییر دهید.

// Limitation of minimal amount of trades per day
double MinTr   = TestDay - 2; 
// Limitation on maximal amount of trades per day
double MaxTr   = (60 / Period()*TestDay) + 2;
// The amount of attempts to copy the report file
int    KvoPptk = 10;
// The amount of strings to be sorted
int    StepRes = 12;

نتیجه‌گیری

این مقاله قصد نداشت به تازه‌کارها اِلمان‌های بهینه‌سازی را آموزش دهد. بنابراین، پیشنهاد می‌شود قبل از اینکه سراغ بهینه‌سازی خودکار بروید، حتماً بهینه‌سازی معمولی را یاد بگیرید. بهتر این است، از بهینه‌ساز خودکار زمانی استفاده کنید که، متغیرهای پایه، که روی اکسپرت شما در زمان‌های مختلف، تاثیرات مختلفی می‌گذارند را، انتخاب کرده باشید. به‌عبارت دیگر، بهتر است از این بهینه‌ساز خودکار برای مطابقت دادن پارامترهای متغیرها، با تغییراتی که روی عملکرد اکسپرت شما، بسته به نوسانات بازار، بیش از دیگر پارامترها در متغیرهای دیگر، تاثیر می‌گذارند، استفاده کنید.

علاوه بر این‌ها، بهتر این است که دوره‌ی بهینه‌سازی را خیلی طولانی درنظر نگیرید. فرض کنید اکسپرت، ۶ الی ۱۲ ساعت هر روز، بهینه‌سازی شود، آنگاه این سوال پیش می‌آید: پس کی ترید کنیم؟ به‌عبارت دیگر، بهینه‌سازی به خودی خود، نیاز نیست. پیشنهاد می‌شود تناوب بهینه‌‌سازی (منظور، تناوب اجرای بهینه‌ساز است) را با درنظر گرفتن تایم‌فریمی که روی آن اکسپرت قرار است ترید کند، تعیین کنید. این یعنی اینکه ضروری است درنظر داشته باشیم که داده‌های هیستوری هنگامیکه Tester-Terminal شروع به کار می‌کند، به‌نوعی پمپاژ می‌شوند و ممکن است بروکر داده‌های هیستوری مورد نیاز برای یک بازه‌ی زمانی خاص را در اختیار نداشته باشد. برای تایید فرضیه‌ای که در ابتدای این مقاله به آن اشاره شد، نیاز دارید ۲۴ ساعت اتصال اینترنت قوی، پایدار و بدون قطعی داشته باشید.

برنامه‌های بهینه‌سازی خودکاری که توسعه‌ داده شدند، در فایل‌های پیوست‌شده موجود هستتند: auto_optimization.mqh – خود کتابخانه، MACD Sample_1.mq4 – که نسخه‌ی کمی تغییرداده‌شده‌ی اکسپرتی است که در نرم‌افزار متاتریدر ۴ موجود است.

این مقاله دارای فایل پیوست است.

[۱]) Optimization Completeness Reference Time

[۲]) Resulting Values of Variables


مقالات پیشنهادی :

M23admin

→ خواندن مطلب قبلی

یک‌بار دیگر زیگزاگ‌ها

خواندن مطلب بعدی ←

تبدیل کد اندیکاتور به کد اکسپرت. طرح‌های کلی ساختاری یک اکسپرت و توابع اندیکاتور

۲۲ مورد نظر

نوشتن نظر شما

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *