ایجاد نمادهای دلخواه در Meta Trader 5 ( پارت سوم ) | ربات معامله گر تجاری بر اساس برخورد دو MA

ربات معامله گر تجاری

از یکی از ساده ترین استراتژیه های تجارت که برخورد دو میانگین متحرک می باشد، استفاده می کنیم. تصویر صفحه نمایش قبلی این ایده را ارائه می دهد. وقتی MA سریع (قرمز) از MA کند (آبی) به سمت بالا یا پایین عبور می کند، به ترتیب، خرید و فروش را باز می کند. این یک سیستم برگشتی است.خیلی سخت می بود که ربات معامله گر را ار اسکراچ بسازیم اما MetaTrader 5 یک برنامه کمکی MQL فراهم می آورد که می تواند ربات های معامله گر را بر اساس کتابخانه کلاس های استاندارد (با پشتیبانی ترمینال) تولید کند. این امر برای کارگزارانی که با برنامه نویسی آشنا نیستند خیلی مرسوم است. ساختار کدی حاصل برای تعداد زیادی از ربات ها معمول است و بنابراین استفاده از آن برای موارد اصلی- برای تطبیق ربات ها برای معامله نمادهای دلخواه- ایده خوبی است. ربات های معامله گری که بدون کتابخانه استاندارد ساخته شده اند، نیز می توانند بر طبق همین روش تطبیق یابند اما از آنجاییکه تولید آنها می تواند تفاوت زیادی داشته باشد، برنامه نویس باید اصلاحات متناسب را در صورت لزوم انجام دهد (به طور کلی، برنامه نویسان باتجربه می تواند هر ربات معامله گر تجاری را با استفاده از مثال ما می توانند تطبیق دهند).

ربات معامله گر تجاری بر اساس برخورد دو MA

به طرز کاملا عجیبی، کتابخانه استاندارد هیچ سیگنالی از برخورد دو میانگین متحرک ندارد، اگر چه یکی از محبوب ترین استانداردها می باشد (حداقل هنگام آموزش معاملات الگوریتمی محبوب ترین است). و بنابراین، نیاز به نوشتن ماژول سیگنالی متناسب هستیم. آن را Signal2MACross.mgh می نامییم. در زیر کد آن که مطابق با قوانین لازم برای قابل استفاده شدن سیگنال با برنامه کمکی MQL می باشد، وجود دارد.

این کد با یک header- کامنت های مخصوص با توصیف سیگنالی در یک فرمت متناسب- شروع می شود که آن را برای MetaEditor  قابل دسترس می نماید.

  //--- wizard description start
  //+------------------------------------------------------------------+
  //| Description of the class                                         |
  //| Title=Signals of 2 MAs crosses                                   |
  //| Type=SignalAdvanced                                              |
  //| Name=2MA Cross                                                   |
  //| ShortName=2MACross                                               |
  //| Class=Signal2MACross                                             |
  //| Page=signal_2mac                                                 |
  //| Parameter=SlowPeriod,int,11,Slow MA period                       |
  //| Parameter=FastPeriod,int,7,Fast Ma period                        |
  //| Parameter=MAMethod,ENUM_MA_METHOD,MODE_LWMA,Method of averaging  |
  //| Parameter=MAPrice,ENUM_APPLIED_PRICE,PRICE_OPEN,Price type       |
  //| Parameter=Shift,int,0,Shift                                      |
  //+------------------------------------------------------------------+
  //--- wizard description end

کد چهاردهم

نام کلاس (کلاس خطی) باید مطابق با نام یک کلاس واقعی در کدهای MQL بعدی باشد. سیگنال 5 پارامتر معمول برای دو میانگین متحرک دارد: دو دوره (سریع و آرام)، روش میانگین گیری، نوع قیمت و شیفت.

کلاس از CExpertSignal نتیجه شد. شامل دو مثال از اشیا شاخص CiMA، متغیرهای پارامترهای فعال، روش های تنظیم کننده پارامتر (نام روشها باید با نام های در هدر مطابق باشند) است. همچنین، کلاس روش های مجازی را بازنگری کرده است که در طول شروع شاخص ها فراخوانده می شوند، همان طور که هنگام بررسی تنظیمات و تعیین سیگنال های خرید و فروش اتفاق می افتد.

class Signal2MACross : public CExpertSignal
  {
    protected:
      CiMA              m_maSlow;         // object-indicator
      CiMA              m_maFast;         // object-indicator
      
      // adjustable parameters
      int               m_slow;
      int               m_fast;
      ENUM_MA_METHOD    m_method;
      ENUM_APPLIED_PRICE m_type;
      int               m_shift;
      
      // "weights" of market models (0-100)
      int               m_pattern_0;      // model 0 "fast MA crosses slow MA"
  
    public:
                        Signal2MACross(void);
                       ~Signal2MACross(void);
                       
      // parameters setters
      void              SlowPeriod(int value) { m_slow = value; }
      void              FastPeriod(int value) { m_fast = value; }
      void              MAMethod(ENUM_MA_METHOD value) { m_method = value; }
      void              MAPrice(ENUM_APPLIED_PRICE value) { m_type = value; }
      void              Shift(int value) { m_shift = value; }
      
      // adjusting "weights" of market models
      void              Pattern_0(int value) { m_pattern_0 = value; }
      
      // verification of settings
      virtual bool      ValidationSettings(void);
      
      // creating the indicator and timeseries
      virtual bool      InitIndicators(CIndicators *indicators);
      
      // checking if the market models are formed
      virtual int       LongCondition(void);
      virtual int       ShortCondition(void);
  
    protected:
      // initialization of the indicators
      bool              InitMAs(CIndicators *indicators);
      
      // getting data
      double            FastMA(int ind) { return(m_maFast.Main(ind)); }
      double            SlowMA(int ind) { return(m_maSlow.Main(ind)); }

کد پانزدهم

کلاس فقط استراتژی (الگو یا مدل) را توضیح می دهد: وقتی MA سریع از MA آرامد می گذرد، یک خرید (برای برخورد رو به بالا) یا فروش (برای برخورد رو به پایین) شروع می شود. وزن مدل به صورت پیش فرض برابر با 100 می باشد.

Signal2MACross::Signal2MACross(void) : m_slow(11), m_fast(7), m_method(MODE_LWMA), m_type(PRICE_OPEN), m_shift(0), m_pattern_0(100)
  {
  }

کد شانزدهم

وضعیت شرایط گشایش در دو روش زیر معین می شوند (به صراحت، کدها برخورد را بررسی نمیکنند اما وضعیت قرارگیری یک MA نسبت به دیگری را رصد می کند، در حالی که تاثیر آن مشابه با سیستمی است که همواره در بازار می باشد، گرچه این کد ساده تر است):

int Signal2MACross::LongCondition(void)
  {
    const int idx = StartIndex();
    
    if(FastMA(idx) > SlowMA(idx))
    {
      return m_pattern_0;
    }
    return 0;
  }
  
  int Signal2MACross::ShortCondition(void)
  {
    const int idx = StartIndex();
  
    if(FastMA(idx) < SlowMA(idx))
    {
      return m_pattern_0;
    }
    return 0;

کد هفدهم

تابع StarIndex در کلاس مادر تعیین می شود. همان طور که می توانید از کد ببینید، نمایشگر تعداد میله های هر سیگنال تحلیل شده می باشد. اگر هر اجرای مبتنی بر تیک در تنظیمات ربات معامله گر تجاری انتخاب شود (Expert_EveryTick = true، بعدا ببینید)، بنابراین نمایه آغازگر برابر با صفر است؛ وگرنه (مثلا با میله های بسته اجرا شود) نمایه 1 می باشد.

فایل Signal2MACross.mgh را در پوشه MQL5/Include/Expert/Signal/MySignals ذخیره کنید، سپس MetaEditor را (اگر در حال اجراست) دوباره راه اندازی نمایید تا ماژول جدید را در برنامه MQL بردارد.

اکنون می توانیم یک ربات معامله گر تجاری بر اساس سیگنال ما بسازیم. گزینه File-New را در منو انتخاب و صفحه دیالوگ برنامه را باز کنید. سپس مراحل زیر را دنبال نمایید.

  • ربات معامله گر (تولید) را انتخاب کنید.
  • EA را نامگذاری کنید، مثلا Experts/Examples/MA2Cross.
  • سیگنال Signals of 2 Mas را اضافه کنید.
  • از Trailing stop not used استفاده کنید.
  • از Trading with fixed volume استفاده کنید.

در نتیجه، کد زیر ربات معامله گر تجاری را دریافت خواهید کرد:

 #include <Expert\Expert.mqh>
  #include <Expert\Signal\MySignals\Signal2MACross.mqh>
  #include <Expert\Trailing\TrailingNone.mqh>
  #include <Expert\Money\MoneyFixedLot.mqh>
  
  //+------------------------------------------------------------------+
  //| Inputs                                                           |
  //+------------------------------------------------------------------+
  // inputs for expert
  input string             Expert_Title              = "MA2Cross";  // Document name
  ulong                    Expert_MagicNumber        = 7623;
  bool                     Expert_EveryTick          = false;
  // inputs for main signal
  input int                Signal_ThresholdOpen      = 10;          // Signal threshold value to open [0...100]
  input int                Signal_ThresholdClose     = 10;          // Signal threshold value to close [0...100]
  input double             Signal_PriceLevel         = 0.0;         // Price level to execute a deal
  input double             Signal_StopLevel          = 0.0;         // Stop Loss level (in points)
  input double             Signal_TakeLevel          = 0.0;         // Take Profit level (in points)
  input int                Signal_Expiration         = 0;           // Expiration of pending orders (in bars)
  input int                Signal_2MACross_SlowPeriod = 11;         // 2MA Cross(11,7,MODE_LWMA,...) Slow MA period
  input int                Signal_2MACross_FastPeriod = 7;          // 2MA Cross(11,7,MODE_LWMA,...) Fast Ma period
  input ENUM_MA_METHOD     Signal_2MACross_MAMethod  = MODE_LWMA;   // 2MA Cross(11,7,MODE_LWMA,...) Method of averaging
  input ENUM_APPLIED_PRICE Signal_2MACross_MAPrice   = PRICE_OPEN;  // 2MA Cross(11,7,MODE_LWMA,...) Price type
  input int                Signal_2MACross_Shift     = 0;           // 2MA Cross(11,7,MODE_LWMA,...) Shift
  input double             Signal_2MACross_Weight    = 1.0;         // 2MA Cross(11,7,MODE_LWMA,...) Weight [0...1.0]
  // inputs for money
  input double             Money_FixLot_Percent      = 10.0;        // Percent
  input double             Money_FixLot_Lots         = 0.1;         // Fixed volume
  
  //+------------------------------------------------------------------+
  //| Global expert object                                             |
  //+------------------------------------------------------------------+
  CExpert ExtExpert;
  
  //+------------------------------------------------------------------+
  //| Initialization function of the expert                            |
  //+------------------------------------------------------------------+
  int OnInit()
  {
    // Initializing expert
    if(!ExtExpert.Init(Symbol(), Period(), Expert_EveryTick, Expert_MagicNumber))
    {
      printf(__FUNCTION__ + ": error initializing expert");
      ExtExpert.Deinit();
      return(INIT_FAILED);
    }
    // Creating signal
    CExpertSignal *signal = new CExpertSignal;
    if(signal == NULL)
    {
      printf(__FUNCTION__ + ": error creating signal");
      ExtExpert.Deinit();
      return(INIT_FAILED);
    }
    
    ExtExpert.InitSignal(signal);
    signal.ThresholdOpen(Signal_ThresholdOpen);
    signal.ThresholdClose(Signal_ThresholdClose);
    signal.PriceLevel(Signal_PriceLevel);
    signal.StopLevel(Signal_StopLevel);
    signal.TakeLevel(Signal_TakeLevel);
    signal.Expiration(Signal_Expiration);
    
    // Creating filter Signal2MACross
    Signal2MACross *filter0 = new Signal2MACross;
    if(filter0 == NULL)
    {
      printf(__FUNCTION__ + ": error creating filter0");
      ExtExpert.Deinit();
      return(INIT_FAILED);
    }
    signal.AddFilter(filter0);
    
    // Set filter parameters
    filter0.SlowPeriod(Signal_2MACross_SlowPeriod);
    filter0.FastPeriod(Signal_2MACross_FastPeriod);
    filter0.MAMethod(Signal_2MACross_MAMethod);
    filter0.MAPrice(Signal_2MACross_MAPrice);
    filter0.Shift(Signal_2MACross_Shift);
    filter0.Weight(Signal_2MACross_Weight);
  
    ...
    
    // Check all trading objects parameters
    if(!ExtExpert.ValidationSettings())
    {
      ExtExpert.Deinit();
      return(INIT_FAILED);
    }
    
    // Tuning of all necessary indicators
    if(!ExtExpert.InitIndicators())
    {
      printf(__FUNCTION__ + ": error initializing indicators");
      ExtExpert.Deinit();
      return(INIT_FAILED);
    }
  
    return(INIT_SUCCEEDED);
  }

کد هجدهم

کد کامل MA2Cross.mq5 ضمیمه این مقاله می باشد. همه چیز آماده کامپایل، آزمایش آزمون استراتژی و حتی بهینه سازی هر نمادی، شامل نماد رنکو دلخواهمان، می باشد. از آنجاییکه دقیقا علاقه مند به رنکو هستیم، نیاز به توضیح چند چیز می باشیم.

هر بلوک رنکو، در شکل مستطیلی خود، وجود نخواهد داشت تا زمانی که کاملا با تغییرات قیمت شکل بگیرد. وقتی بلوک بعدی ظاهر می شود، نه تنها قیمت پایانی اش بلکه قیمت آغازینش را هم نمی دانیم زیرا دو جهت متضاد ممکن وجود دارد: بالا و پایین. وقتی بلوک نهایتا بسته می شود قیمت پایانی قطعی و استوار است. به همین دلیل مقدار پیش فرض پارامتر Signal_2MACross_MAPrice در ربات معامله گر به PRICE_CLOSE تغییر می کند- تغییر دادن آن پیشنهاد نمی شود. می توانید با دیگر انواع قیمت تجربه کنید ولی ایده رنکو نه تنها به نرمی مستقل از زمان می شود بلکه نوسانات کوچک قیمت را حذف می کند که این امر با عدد سازی بر طبق اندازه بلوک به دست می آید.

توجه داشته باشید که میله رنکو صفرم همواره ناقص است (در اکثر موارد یک کندل استیک بدون بدنه، نه مستطیلی، می باشد) که به همین دلیل از سیگنال میله اول استفاده می کنیم. به این منظور، مقدار پارامتر Expert_ EveryTick را برابر با False تنظیم می نماییم.

رنکو دلخواه مبتنی بر EURUSD را اندازه بلوک 100 نقطه تولید کنید. در نتیجه، نماد EURUSD_T_r100 را به دست می آوریم. آن را در آزمایشگر انتخاب کنید. مطمئن شوید که بازه زمانی M1 را تنظیم کرده باشید.

حال ببینیم چگونه ربات معامله گر تجاری با این نماد برای بازه 2019-2020 (نیمه اول)، به عنوان مثال، با دوره پیش فرض 7 و 11 رفتار می کند (بقیه ترکیبات می تواند به طور مستقل با بهینه سازی بررسی شود).

The result of the MA2CrossCustom strategy on 100-point renko chart derived from EURUSD

نتیجه استراتژی MA2CrossCustom بر روی نمودار رنکو 100 نقطه ای منتج از EURUSD

برای مقایسه نماد دلخواه با نماد واقعی، در اینجا گزارشی از MA2CrossCustom ربات معامله گر تهیه نموده ام که مشابه MA2Cross با یک پارامتر WorkSymbol خالی می باشد. در بخش بعدی چگونگی به دست آوردن MA2CrossCustom را از MA2Cross در نظر می گیریم.

همانطور که از جدول معامله می توان دید، معاملات در قیمت هایی چند برابر با اندازه بلوک صورت می گیرند: قیمت های فروش کاملا مطابق و قیمت های خرید متفاوت از اندازه گسترش می باشند (ژنراتور رنکو ما در هر میله مقدار ماکزیمم گسترش ثبت شده در طول تشکیلش را ذخیره می کند، اگر می خواهید شما می توانید این رفتار را در کد مرجع تغییر دهید). رنکو توسط نوع قیمت استفاده شده در نمودار مرجع ساخته می شود. در مورد ما نوع قیمت مزایده می باشد. آخرین قیمت برای ابزار تبادل ارز به کار می رود.

Deals table when trading EURUSD-based custom renko symbol

جدول معاملات هنگام معامله نماد رنکو دلخواه مبتنی بر EURUSD

اکنون به نظر می رسد که نتیجه کار به خوبی صحیح می باشد. در واقع، نکات ظریف مخفی بسیاری وجود دارد.

نماد رنکو در حال معامله در آزمایشگر بر روی دقت نتایج در هر حالتی تاثیر می گذارد: توسط قیمت اولیه، بازه M1 در OHLC و تیک ها.

قیمت اولیه میله یک رنکو استاندارد همواره به زمانی که میله با آن نشانگذاری شده است، نمی رسد بلکه در اکثر موارد بعدا می رسد (زیرا قیمت برای مدتی درون اندازه رنکو بالا و پایین می رود و شاید نهایتا جهت را، با تشکیل میله بازگشتی، تغییر دهد). زمان نشانگر میله زمان تکمیل میله قبلی است.

قیمت پایانی مرتبط با زمان پایان نمی باشد زیرا میله رنکو میله M1 می باشد، یعنی مدت زمان ثابت یک دقیقه دارد.

ممکن است یک رنکو غیراستاندارد تولید شود که در آن میله ها با زمان تکمیل، نه زمان آغاز، نشانگذاری شوند. بنابراین قیمت پایانی مرتبط با زمان پایان خواهد بود. با این وجود زمان آغاز یک دقیقه زودتر از زمان پایان خواهد بود و بنابراین مرتبط با زمان آغاز واقعی نخواهد بود (برابر با قیمت پایان بعلاوه/منهای اندازه رنکو خواهد بود).

قرار بر این است که تحلیل رنکو توسط میله های تشکیل یافته انجام شود، اما قیمت مشخصه آنها قیمت پایانی است، جز اینکه در طول عملیات میله به میله، آزمایشگر فقط قیمت آغاز را برای میله کنونی (آخرین) فراهم می آورد (هیچ حالتی با قیمت های پایان ندارد). در اینجا، قیمت های آغاز میله از ابتدا پیش بینی کننده هستند. اگر از سیگنال های میله های بسته شده (معمولا از اولین) استفاده کنیم، معاملات به هر حال در قیمت کنونی میله صفرم اجرا می شود. حتی اگر از حالات تیک استفاده کنیم، آزمونگر تیک ها را برای رنکو مطابق با قوانین معمول، با استفاده از نقاط مبتنی بر هر تشکیل میله، تولید می کند. آزمونگر ساختار خاص و رفتار شاخص های رنکو را در نظر نمی گیرد (که در تلاشیم به صورت بصری میله های M1 را تکرار کنیم). اگر فرضا یک تشکیل یکباره کل میله را تصور کنیم، هنوز هم دارای یک بدنه خواهد بود- و برای چنین میله هایی آزمونگر تیک های آغاز شونده از قیمت آغاز را تولید می کند. اگر حجم تیک میله را برابر با یک تنظیم کنیم، میله پیکر بندی را از دست می دهد(تبدیل به برچسب قیمت برابر با OHLC می گردد).

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

به عبارت دیگر، به دلیل خود ساختار رنکو بر روی نمادهای رنکو اهداف آزمونگر داریم برای اینکه در آینده در مرحله ای برابر با اندازه میله رنکو ظاهر می شود.

به همین خاطر لازم است تا سیستم معاملات  بر روی میله رنکو مجزا آزمایش نشود بلکه با اجرای سفارشات معامله روی نماد واقعی ترکیب شود.

رنکو تجزیه و تحلیل و زمان بندی زمان ورود به بازار را فراهم می آورد.

تا بحال فقط قابلیت ربات معامله گر را در معامله نماد دلخواه آزمایش نموده ایم. این امر محدودیت هایی بر روی برنامه ربات معامله گر فقط در آزمونگر تنظیم می کند. برای جهانی نمودن ربات معامله گر، یعنی قادر به معامله آنلاین نماد اصلی در هنگام اجرا نمودار رنکو، لازم است که چند چیز اضافه کنیم. این امر همچنین در هنگام حل مسئله با نتایج خیلی خوشبینانه کمک می کند.

بیشتر بخوانید

تطبیق ربات معامله گر تجاری برای معامله بر روی نمودارهای نماد دلخواه

یک نماد دلخواه فقط برای ترمینال تقاضا کننده شناخته می شود و در سرور معامله وجود ندارد. به وضوح رربات معامله گر تجاری بررسی کننده یک نمودار نماد دلخواه باید تمام سفارشات معامله برای نماد اصلی ( که در آن نماد دلخواه مبنا است) را تولید کند. به عنوان ساده ترین راه حل این مسئله، ربات معامله گر می تواند بر روی نمودار نماد اصلی اجرا شود اما سیگنال ها (مثلا، شاخص ها) را از نماد دلخواه دریافت کند. با این وجود، بسیاری از معامله گران ترجیح می دهند تا تمام تصویر را ببینند. به علاوه، بهینه سازی های کد منتخب می تواند خطاهایی را تولید کند. مطلوب است که تغییرات بر روی کد مرجع حداقل با شد.

متاسفانه، نام نماد اصلی و رنکو تولید شده بر مبنای آن نمی توانند توسط خود پلاتفرم متصل شوند. راه حل مرسوم داشتن فیلد رشته ای origin و parent در خصوصیات نماد دلخواه می باشد که در آن بتوانیم نام نماد واقعی را بنویسیم. به صورت پیش فرض خالی خواهد بود اما وقتی پر شود، پلاتفرم به صورت خودکار نماد را در تمام سفارش معاملات و درخواست های تاریخچه جایگزین می نماید. از آنجاییکه این مکانیزم در پلاتفرم وجود ندارد، مجبور خواهیم بود تا آن را خودمان اعمال کنیم. اسامی نماد مرجع و دلخواه با استفاده از پارامترها تنظیم می شود. خصوصیات نماد دلخواه فیلدی با معنی مناسب- SYMBOL_BASIS- دارد. اما از آنجاییکه نمی توانیم تضمین کنیم که مولد های قراردادی نمادهای دلخواه (هر برنامه MQL) به درستی پارامترها را پر می کند یا از آن دقیقا برای این هدف استفاده خواهیم کرد، نیاز به تهیه راه حل دیگری داریم.

بدین منظور، کلاس CustomOrder را ارائه داده ام ( مراجعه شود به CustomOrder.mqh در ضمیمه). این کلاس حاوی روشهای پوششی برای تمام توابع رابط کاربری MQL مربوط به ارسال سفارشات معامله و درخواست های تاریخچه می باشد که حاوی پارامترهای رشته ای با نام نمادی وسیله می باشند. این روش ها یک نماد دلخواه را با نماد فعال حاضر، یا برعکس، جایگزین می کنند. تمام توابع رابط کاربری دیگر نیاز به hook ندارند. کد در زیر نشان داده می شود:

class CustomOrder
  {
    private:
      static string workSymbol;
      
      static void replaceRequest(MqlTradeRequest &request)
      {
        if(request.symbol == _Symbol && workSymbol != NULL)
        {
          request.symbol = workSymbol;
          if(request.type == ORDER_TYPE_BUY
          || request.type == ORDER_TYPE_SELL)
          {
            if(request.price == SymbolInfoDouble(_Symbol, SYMBOL_ASK)) request.price = SymbolInfoDouble(workSymbol, SYMBOL_ASK);
            if(request.price == SymbolInfoDouble(_Symbol, SYMBOL_BID)) request.price = SymbolInfoDouble(workSymbol, SYMBOL_BID);
          }
        }
      }
      
    public:
      static void setReplacementSymbol(const string replacementSymbol)
      {
        workSymbol = replacementSymbol;
      }
      
      static bool OrderSend(MqlTradeRequest &request, MqlTradeResult &result)
      {
        replaceRequest(request);
        return ::OrderSend(request, result);
      }
      
      static bool OrderCalcProfit(ENUM_ORDER_TYPE action, string symbol, double volume, double price_open, double price_close, double &profit)
      {
        if(symbol == _Symbol && workSymbol != NULL)
        {
          symbol = workSymbol;
        }
        return ::OrderCalcProfit(action, symbol, volume, price_open, price_close, profit);
      }
      
      static string PositionGetString(ENUM_POSITION_PROPERTY_STRING property_id)
      {
        const string result = ::PositionGetString(property_id);
        if(property_id == POSITION_SYMBOL && result == workSymbol) return _Symbol;
        return result;
      }
      
      static string OrderGetString(ENUM_ORDER_PROPERTY_STRING property_id)
      {
        const string result = ::OrderGetString(property_id);
        if(property_id == ORDER_SYMBOL && result == workSymbol) return _Symbol;
        return result;
      }
      
      static string HistoryOrderGetString(ulong ticket_number, ENUM_ORDER_PROPERTY_STRING property_id)
      {
        const string result = ::HistoryOrderGetString(ticket_number, property_id);
        if(property_id == ORDER_SYMBOL && result == workSymbol) return _Symbol;
        return result;
      }
      
      static string HistoryDealGetString(ulong ticket_number, ENUM_DEAL_PROPERTY_STRING property_id)
      {
        const string result = ::HistoryDealGetString(ticket_number, property_id);
        if(property_id == DEAL_SYMBOL && result == workSymbol) return _Symbol;
        return result;
      }
      
      static bool PositionSelect(string symbol)
      {
        if(symbol == _Symbol && workSymbol != NULL) return ::PositionSelect(workSymbol);
        return ::PositionSelect(symbol);
      }
      
      static string PositionGetSymbol(int index)
      {
        const string result = ::PositionGetSymbol(index);
        if(result == workSymbol) return _Symbol;
        return result;
      }
      ...
  };
  
  static string CustomOrder::workSymbol = NULL;

کد نوزدهم

برای به حداقل رساندن تغییرات در کد مرجع، ماکرو های زیر (برای تمام روش ها) استفاده می شوند:

bool CustomOrderSend(const MqlTradeRequest &request, MqlTradeResult &result)
  {
    return CustomOrder::OrderSend((MqlTradeRequest)request, result);
  }
  
  #define OrderSend CustomOrderSend

کد بیستم

آنها جهت دهی مجدد خودکار تمام توابع رابط کاربری استاندارد را برای فراخواندن روش های کلاس CustomOrder فعال می سازد. به این منظور، CustomOrder.mqh را در ربات معامله گر لحاظ کرده و نماد فعال را تنظیم نمایید:

 #include <CustomOrder.mqh>
  #include <Expert\Expert.mqh>
  ...
  input string WorkSymbol = "";
  
  int OnInit()
  {
    if(WorkSymbol != "")
    {
      CustomOrder::setReplacementSymbol(WorkSymbol);
      
      // force a chart for the work symbol to open (in visual mode only)
      MqlRates rates[1];
      CopyRates(WorkSymbol, PERIOD_H1, 0, 1, rates);
    }
    ...
  }

کد بیست و یکم

مهم است که دایرکتوری #include <CustomOrder.mqh> اول وقبل از بقیه بیاید. بنابراین، بر روی تمام کدهای مرجع، شامل کتابخانه های استاندارد متصل، تاثیر می گذارد. اگر کاراکتر عام مشخص نشود، CustomOrder.mqh متصل تاثیری بر روی ربات معامله گر نخواهد داشت و کنترل را به توابع رابط کاربری استاندارد منتقل می کند.

تاابع MA2Cross بهینه ربات معامله گر به MA2CrossCustom.mq5 تغییر نام داده است.

حال می توانیم WorkSymbol را بر روی EURUSD تنظیم کنیم، در حالیکه بقیه تنظیمات را نگهداریم و آزمایش را شروع کنیم. اکنون ربات معامله گر عملا EURUSD معامله می کند اگرچه بر روی نمودار نماد رنکو اجرا می شود.

The result of the MA2CrossCustom strategy on 100-point renko chart when trading the real EURUSD symbol

نتیجه استراتژی MA2CrossCustom بر روی نمودار رنکو 100 نقطه ای هنگام معامله با نماد EURUSD واقعی

این بار نتیجه نزدیکتر به واقعیت می باشد.

در معاملات EURUSD، قیمت ها به طور مشهودی متفاوت از قیمت های پایانی میله رنکو می باشد. این امر به دلیل آن است که میله های رنکو همواره با شروع یک دقیقه ای نشانگذاری می شوند (این امر محدودیت بازه زمانی M1 در پلاتفرم است) ولی قیمت از مرز میله در لحظات قراردادی درون دقیقه عبور می کند. از آنجایی که ربات معامله گر بر روی نمودار در حالت میله به میله اجرا می شود (نباید با حالت آزمونگر اشتباه شود)، ظهور سیگنال به گشایش میله دقیقه ای EURUSD، هنگامی که قیمت معمولا متفاوت است، منتقل می شود. به طور متوسط، خطا احتمال ریاضیاتی محدوده میله های دقیقه ای برای هر معامله می باشد.

EURUSD trades performed by the Expert Advisor from a Renko chart derived from EURUSD

معاملات EURUSD انجام شده توسط ربات معامله گر روی نمودار رنکو منتج شده از EURUSD

برای حذف تناقض، ربات معامله گر می بایست تمام تیک ها را پردازش کند اما قبلا دریافتیم که منطق تولید تیک در آزمونگر متفاوت از تشکیل تیک رنکو می باشد: مخصوصا، قیمت آغازی میله های بازگشتی همواره فاصله ای برابر با یک بلوک رنکو مربوط به پایان میله قبلی دارد.این مسئله در معامله آنلاین وجود ندارد.

حال عملکرد CustomOrder را با استفاده از ربات معامله گر دیگر بررسی کنیم که بدون استفاده از کتابخانه استاندارد نوشته شده است. برای این کار از ExprBot ربات معامله گر مقاله درباره محاسبه اصطلاحات ریاضی استفاده خواهیم کرد- همچنین استراتژی برخورد دو MA را استخراج می کند و عملیات معامله را با استفاده از کتابخانه MT4Orders انجام می دهد.

ربات معامله گر بهینه ExprBotCustom.mq5، در فایل های هدر لازم (در پوشه ExpresSParserS)، در زیر ضمیمه شده است.در زیر نتایج بازه 2019 تا 2020 (نیمه اول سال) با همان تنظیمات (دوره 7/11، متوسط گیری نوع LWMA، قیمت های پایانی روی اولین میله) آمده است.

The result of the ExprBotCustom strategy on 100-point renko chart derived from EURUSD

نتیجه استراتژی ExprBotCustom روی نمودار رنکو 100 نقطه ای منتج از EURUSD

The result of the ExprBotCustom strategy on 100-point renko chart when trading the real EURUSD symbol

نتیجه استراتژی ExprBotCustom روی نمودار رنکو 100 نقطه ای هنگام معامله با نماد واقعی EURUSD

این نتایج خیلی مشابه با نتایج به دست آمده با MA2CrossCustom ربات معامله گر می باشند. می توانیم نتیجه بگیریم که رویکرد موردنظر مسئله را حل می کند. با این وجود، اجرای CustomOrder کنونی فقط حداقل مبانی می باشد. شاید بهبودهایی بر اساس استراتژی معامله و خصوصیات نماد فعال نیاز باشد.

نتیجه گیری

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

البته، نمادهای دلخواه امکانات خیلی بیشتری را فراهم می آورد. کاربرد های بالقوه این تکنولوژی خیلی وسیع تر است. به عنوان مثال، می توانیم از نمادهای مصنوعی، دلتای حجم و منابع داده شخص ثالث استفاده کنیم. انتقال برنامه مذکور، استفاده از این امکانات نمودارهای MetaTrader 5 استاندارد را، در آزمونگر استراتژی و حالت آنلاین، فعال می کند.

پارت اول این مقاله:

ایجاد نماد های دلخواه در متاتریدر 5

این مقاله ترجمه شده توسط تیم آکادمی ایران ام کیو ال می باشد. 

صفحه اصلی مقاله

سایر مقالات مرتبط

متا تریدر چیست؟
متاتریدر

متا تریدر چیست؟

متا تریدر چیست؟ اولین سوالی که هر فرد وقتی می خواهد آموزش های متاتریدر مانند آموزش صفر تا صد mql5،

کامل ترین و بهترین آموزش متاتریدر 4
mql4

کامل ترین آموزش متاتریدر 4

بهترین آموزش متاتریدر 4 متاتریدر4 یک پلتفرم معاملاتی محسوب می‌ شود که دارای رابط کاربری ساده است و همین یادگیری

پاسخ‌ها

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