رویـــکــــرد شــــیء‌گرا در MQL

رویـــکــــرد شــــیء‌گرا در MQL

رویـــکــــرد شــــیء‌گرا در MQL [۱]

مقدمه

این مقاله، در ابتدا، برای برنامه‌نویس‌های حرفه‌ای و حتی تازه‌کارها، که در محیط MQL کار می‌کنند، بسیار جذاب خواهد بود. همچنین توصیه می‌شود توسعه‌دهندگان محیط MQL و ایدئولوژیست‌ها نیز این مقاله را بخوانند، چراکه قطعاً پروژه‌های خوبی از دل این مقاله بیرون خواهند آمد. همچنین، تا حد زیادی می‌توانید ایده‌های مشابه را در مقاله‌های Universal Expert Advisor Template و Sending Trading Signals in a Universal Expert Advisor پیدا کنید.

بسیار خب،

یکی از معایب MQL، به‌نظر شخص والای خودم، و از نظر برنامه‌نویسی، این است که رویکرد شیء‌گرایانه در ساخت مدل‌ سیستم معاملاتی، ندارد. توسعه‌دهندگان MQL دو راه پیش روی ما می‌گذارند: استفاده از فراخوانی توابع اکسترنال یا استفاده از پارامتر معامله MAGIC برای شناسایی متعلقات معامله [معامله متعلق به کجاست].

فی‌الواقع اگر فقط یک سیستم [ترید] را روی یک حساب داشته باشیم، نیازی به شناسایی نیست. اما وقتی این امکان در اختیار ما گذاشته شده که بتوانیم روی یک حساب چندین سیستم معاملاتی خودکار را داشته باشیم، بدون MAGIC هیچ نوع خاکی نمی‌شود بر سر ریخت! حتی وقتی توابع اکسترنال را صدا می‌زنیم، باید [وضعیت] آن‌ها را تعیین کنیم. البته شاید حضرتعالی بگویید می‌شود یک آرایه به‌نام OrderTicket ایجاد کرد و مشخص کنیم که این آرایه متعلق به فقط یک سیستم ترید است، اما این را بدانید که در برخی از بروکرهای نسبتاً محترم، تیکت معامله در سوآپ، تغییر می‌کند (در حقیقت، یکی بسته و دیگری باز می‌شود). به همین دلیل است که بدون MAGIC هرگز!

حال که توسعه‌دهنده‌ها سرشان شلوغ است و مشغول توسعه و انعطاف‌پذیری بیشتر زبان MQL هستند، بیایید سعی کنیم همین الان رویکرد شیء‌گرایانه را در ساخت یک مدل معاملاتی پیاده‌سازی کنیم.

این یک سیستم ترید مطابق با مدل شیءگرا من است. البته، جهانی نیست، اما اکنون رویکرد دیگری سراغ ندارم.

رویـــکــــرد شــــیء‌گرا در MQL

پس بیایید این مدل را آنالیز کنیم.

  1. A) سیستم سیگنال (SS)

هدف این ماژول، پردازش و تفسیر خوانش‌های دریافتی است. معمولاً، “Object” این سیستم سیگنال، مجموعه‌ای از اندیکاتورها است، برای مثال، مووینگ اَورج‌ها. نتیجه‌ی پردازش خوانش‌ها و مقادیر اندیکاتور این است که، “این Object” (یا سمافور) سیگنال‌هایی تولید می‌کند تا ورود/خروج، یا اصلاح معامله و غیره را داشته باشیم.

سمافور سیگنال‌اَش را شکل می‌دهد و آن را به یک Object دیگر از ماژول ورود/خروج       (Enter/Exit (EE)) می‌فرستد.

تنظیم سمافور در MQL نسبتاً ساده است.

  1. تعریف یک مشخص‌کننده جهانی[۲] با استفاده از #define

بهتر است شماره‌های متوالی مانند ۱، ۲، ۳، ۴، …. تعیین نشوند، بلکه ۵تا ۵تا یا ۱۰تا ۱۰تا باشد، تا در یک اکسپرت بتوانیم یک سیگنال را برای چندین فرآیند استفاده کنیم (ماژول دوم را ببینید).

//+------------------------------------------------------------------+
//|                                                      Signals.mqh |
//|                                    Copyright © ۲۰۰۷ Сергеев Алексей |
//|                                                los@we.kherson.ua |
//+------------------------------------------------------------------+
#property copyright "Copyright © ۲۰۰۷, Сергеев Алексей "
#property link      "mailto: los@we.kherson.ua"
#property library
 
#define BLACKSYS   10
#define BORCHAN    20
#define ELDER      80
#define ENVELOP    90
  1. سپس در تابع جهانی این ماژول، باید پردازشگر (processor) آن را فعال کنیم.
int CheckSignal(bool bEntry, int SignalID)
{
      switch (SignalID)
      {
                  case BLACKSYS:             return (BlackSys(bEntry)); break;
                  case BORCHAN:              return (BorChan(bEntry)); break;
                  case ELDER:                   return (Elder(bEntry)); break;
                  case ENVELOP:              return (Envelop(bEntry)); break;
                  default:                                     return (-1);
      }
}
  1. و قدم آخر توضیح توابع است.

در اینجا مثالی برای پردازش سیگنال‌‌های یک Object داریم که ویژگی‌های اندیکاتور Envelope را به ارث برده است.

int Envelope(bool bEntry)
{
      int MA=21;
      double Deviation=0.6;
      int Mode=MODE_SMA;//0-sma, 1-ema, 2-smma, 3-lwma
      int Price=PRICE_CLOSE;//0-close, 1-open, 2-high, 3-low, 4-median, 5-typic, 6-wieight
      
      double envH0, envL0, m0;
      double envH1, envL1, m1;
      envH0=iEnvelopes(NULL, 0, MA, Mode, 0, Price, Deviation, MODE_UPPER, 0); 
      envL0=iEnvelopes(NULL, 0, MA, Mode, 0, Price, Deviation, MODE_LOWER, 0); 
      envH1=iEnvelopes(NULL, 0, MA, Mode, 0, Price, Deviation, MODE_UPPER, 1); 
      envL1=iEnvelopes(NULL, 0, MA, Mode, 0, Price, Deviation, MODE_LOWER, 1); 
 
      m0 = (Low[0]+High[0])/2;          m1 = (Low[1]+High[1])/2;
      //----- condition for operation execution
      if (bEntry)   //for opening
      {          
                  if (envH0<m0 && envH1<m1) return (OP_SELL);
                  if (envL0>m0 && envL1>m1) return (OP_BUY);
      }
      else //for closing
      {
                  if (envH0<m0 && envH1<m1) return (OP_BUY);
                  if (envL0>m0 && envL1>m1) return (OP_SELL);
      }
 
   return (-1); //no signal
}

بنابراین، ماژولی بدست می‌آوریم که شامل objects-signals‌های مختلف است.

  1. B) Object‌های بلوک EE حداقل وظایف را دارند:

اول، objectهای آن با objects-signals فعل‌وانفعال دارند – آن‌ها را مشاهده کنید. چرخه‌ی زندگی و تعاملات اینگونه است:

بررسی سمافور »» اگر هرگونه سیگنال مثبتی وجود داشته باشد »» باز کردن/بستن/اصلاح پوزیشن‌ها »» واگذاری کنترل به objectها در ماژول PS.

تمام objectها در ماژول EE، پیشوند Process… دارند،که رفتار آن‌ها را به‌طور خاص تعیین می‌کند.

برای مثال:

ProcessAvgLim         //  -  the object processes signals with opening pending limit-orders and positions averaging
ProcessTurn           //  -  the object processes signals with position turning

هر نمونه از کلاس سیستم ترید باید خصوصیات فردی خودش را داشته باشد (همه این را متوجه می‌شویم و در ماژول‌هایمان استفاده می‌کنیم)، مانند سود، حد ضرر، سیستم مدیریت پول مخصوص به خود، [درست] همانند دیگر پارامترهای اضافی که در حالت‌های مختلف تریلینگ استفاده شده‌اند، و غیره.

هنگام به‌کار بردن این ویژگی‌ها، چندین حالت از رویکرد را امتحان کردم و به‌نظر من مناسب‌ترین ‌آ‌ن‌ها در MQL، ایجاد یک آرایه‌ی دوبُعدی است. در اینجا توضیحات مربوطه را داریم:

double SysPar[nSignal][11];
 
#define _TP        0 // Profit
#define _NullTP    1 // profit level, after which we set into losslessness 
#define _NullTP2   2 // profit level, after which we set into losslessness 
#define _TS        3 // distance of the trailing stop 
#define _NullSL    4 // level, after achieving which the expected profit is transfered into opening point
#define _SL        5 // level, after achieving which the expected profit is transfered into opening point
#define _dSL       6 // the initial step upon the opening level of the next order in the position support
#define _dStep     7 // The step is increased in .. times upon the level of the next opening 
#define _dLot      8 // In how many times (as compared to the last one) we increase the lot on the next one 
#define _nLot      9 // In how many times (as compared to the initial one) we increase the lot on the next one
 
string SysParName[nSignal];

که در اینجا nSignal، مشخص‌کننده‌ی[۳] object-signals است.

برای مثال:

SysPar[ENVELOP][_TS] = 40.0;    // distance of the trailing stop 
SysPar[ENVELOP][_NullSL] = 20.0;// level, after achieving which the expected profit is transfered into opening point
SysPar[ENVELOP][_SL] = 70;      // changing stop-loss

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

بنابراین، بعد از تنظیم پارامترها، تابع پردازش سمافور را فرا می‌خوانیم. ‌به‌عبارت دیگر، با سیستم سیگنال تعامل می‌کنیم. این کار در تابع مورد علاقه‌ی من یعنی start() انجام می‌شود.

void start()
{
      ProcessAvgLim(ENVELOP, ENVELOP, Green, Red);
… …

رویـــکــــرد شــــیء‌گرا در MQL

همانطور که در این طرح می‌‌بینید، در این سیستم ترید، ما ۴ سمافور ثبت‌شده و ۳ ناظر (observer) داریم. هر سمافور بر اساس مدل خودش از تفسیر خوانش، بنا شده‌است.

برای مثال، سمافور ۱ سیگنال‌های آنالیز اندیکاتور MACD را می‌فرستد. Observer 1 در جای خودش بعد از دریافت این سیگنال‌ها معاملات را در یک طرح سادۀ ProcessSimple باز می‌کند.

Observer 2 و ۳، سخت‌تر هستند. هرکدام از آن‌ها سیگنال‌های دو سمافور را کنترل می‌کند. و، نتیجتاً، رویکرد بازشدن معاملات متفاوت است.‌

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

“مسئول” وضعیت معاملات بازشده، objectهای ماژول Position Support (PS) هستند.

  1. C) Block PS، به‌نظر من، جزء جالب‌ترین‌ها است، و اهمیت آن کمتر از سمافورها نیست.

در اینجا، حالت‌های مختلف تریلینگ، به‌کار گرفته شده‌اند، معاملات انتظاری باز شده‌اند،            position support و locking، کنترل سود و ضرر، و موارد دیگر را داریم. چنین PSایی باید روی سیگنال‌های EE، درباره‌ی خروج از بازار در شرایط [وجود] پوزیشن‌های ضرر، با کمترین ضرر [ممکن]، به‌اندازه‌ی کافی واکنش نشان دهد.

یک کتابخانه‌ی جالب از تریلینگ‌ها روی این سایت وجود داردLibrary of Functions and Expert Advisors for trailing / Yury Dzyuban . تمام انواع تریلینگ‌ها به‌سادگی به این سیستم متصل می‌شوند.

برای اینکه درک راحت‌تری داشته باشیم، تمام support objectها از پیشوند Trailing… شروع می‌شوند.

طرح آن بدین گونه است:

رویـــکــــرد شــــیء‌گرا در MQL

فراخوانی، و کنترل تبادل از یک observer به تریلینگ، در همان تابع start() انجام شده‌است

void start()
{
      ProcessSimple(MACD, MACD, Black, Plum); TrailingSimple(MACD, Black, Plum);
      ProcessAvgLim(ENVELOPE, ENVELOPE, Green, Red);  TrailingAvgLim(ENVELOPE, Green, Red);
}

یک نوع مثال از رویکرد شیءگرا در ساخت یک سیستم را دیدیم. می‌توانید از این رویکرد استفاده کنید.

بار دیگر در اینجا می‌خواهم از توسعه‌دهندگان MQL خواهش کنم، امکانات این زبان را گسترش دهند. به‌عنوان مثال در اینجا حالتی از به‌کارگیری کلاس‌های شیء[۴]، نوشته‌شده با زبان C++ را، داریم.

struct SystemParam
{
    double TP;        // profit
    double NullTP;    // profit level, after which we set into losslessness 
    double NullTP2;   // profit level, after which we set into losslessness a set of one-direction orders
    double TS;        // distance of the trailing stop 
    double NullSL;    // loss level, at which we transfer the expected profit into losslessness
    double SL;        // stop-loss
    double dSL;       // a step upon the opening level of the next order for the position support
    double dStep;     // In how many times we increase the step upon the opening level of the next order
    double dLot;      // In how many times we increase the lot on the next order
}
 
 
class MTS 
{
    public:
    string m_NameTS;    // system name (for making comments for the order)
    int m_SignalID;     // identifier of trading signals (for semaphore inquiry)
 
    long int Tickets[1000];    // array of order tickets, selected upon m_SignalID (MAGIC)
 
    SystemParam SysPar;    // Trading system parameters
    color ClrBuy;         // color for indicating BUY order
    color ClrSell;        // color for indicating SELL order
 
    // Initialization
    void MyMTS ();            // standard function that sets initial values of the system
    void MyMTS (int aSignalID, int nProcessMode, int nTrailingMode); // standard function 
                                    // that sets initial values of the system
    
    
    // Implementation
    int CheckSignal();     //function of checking state of market signals
 
    // Processing
    int m_nProcessMode;          // identifier of observation mode
    int m_nTrailingMode;         // identifier of trailing mode
    void Process();         // EE function - processing CheckSignal()
    void Trailing();        // PS function - order trailing
 
    // Special functions
    bool CreatTicketArray(int dir);    // creating an array of tickets, selected upon m_SignalID (MAGIC) 
                    // and desired type dir: buy, sell, buylim, buystop, sellim, sellstop
    bool ArrangeOrderBy(int iSort);  // arranging array Tickets upon the parameter (date, profit, price...)
 
};
 
…
 
MTS MyTS; // our trading system
…
 
int init()  
{   
…
    MyTS.m_SignalID = SIGNAL_MACD; // our system is based on MACD signals
    MyTS.m_NameTS = "MACD";
    MyTS.SysPar.TP = 500;    
    MyTS.SysPar.NullTP = 20;
    MyTS.SysPar.TS = 50;
    MyTS.SysPar.SL = 1000;
 
    MyTS.SetProcess (MODE_AVGLIM);
    MyTS.SetTrailing (MODE_AVGLIM);
…
}
 
void start()
{
…
    MyTS.Process ();        
    MyTS.Trailing ();
…
}
 
…
 
void MTS::Process()
{
…
    int Signal = CheckSignal(true, m_SignalID); //calling the global function of signal processing
    if (Signal == -1) return; // if no signal, do nothing
    
//----- for buying
    if(Signal == OP_BUY)
    {    
    }
 
    if(Signal == OP_SELL)
    {    
    }
…
}
 
…
// global processor of semaphores
 
int CheckSignal(bool bEntry, int SignalID)
{
    switch (SignalID)
    {
        case ELDER:    return (Elder(bEntry)); break;
        case ENVELOP:    return (Envelop(bEntry)); break;
        case LAGUER:    return (Laguer(bEntry)); break;
        case MACD:    return (Macd(bEntry)); break;
        …
    }
}
 
// calling a certain semaphore
int Macd(bool bEntry)
{
    double MACDOpen=3;
    double MACDClose=2;
    double MA=26;
    int MODE_MA    = MODE_EMA; // method of the calculation of averages
    int PRICE_MA   = PRICE_CLOSE; // method of the calculation of averages
    int PERIOD     = PERIOD_H1; // the period to work with
 
    //parameters of averages
    double MacdCur, MacdPre, SignalCur;
    double SignalPre, MaCur, MaPre;
 
    //---- get the value
    MacdCur=iMACD(NULL,0,8,17,9,PRICE_MA,MODE_MAIN,0);   MacdPre=iMACD(NULL,0,8,17,9,PRICE_MA,MODE_MAIN,1);
    SignalCur=iMACD(NULL,0,8,17,9,PRICE_MA,MODE_SIGNAL,0);   SignalPre=iMACD(NULL,0,8,17,9,PRICE_MA,MODE_SIGNAL,1);
    MaCur=iMA(NULL,0,MA,0,MODE_MA,PRICE_MA,0);   MaPre=iMA(NULL,0,MA,0,MODE_MA,PRICE_MA,1);
 
    //----- condition for the operation execution
    if (bEntry)   //for buying bEntry==true
    {     
        if(MacdCur<0 && MacdCur>SignalCur && MacdPre<SignalPre && MathAbs(MacdCur)>(MACDOpen*Point) && MaCur>MaPre) 
         return (OP_BUY);
        if(MacdCur>0 && MacdCur<SignalCur && MacdPre>SignalPre && MacdCur>(MACDOpen*Point) && MaCur<MaPre) 
         return (OP_SELL);
    }
    else //for closing bEntry==false
    {    
        if(MacdCur>0 && MacdCur<SignalCur && MacdPre>SignalPre && MacdCur>(MACDClose*Point)) 
         return (OP_BUY);
        if(MacdCur>0 && MacdCur<SignalCur && MacdPre>SignalPre && MacdCur>(MACDOpen*Point) && MaCur<MaPre) 
         return (OP_BUY);
 
        if(MacdCur<0 && MacdCur>SignalCur && MacdPre<SignalPre && MathAbs(MacdCur)>(MACDClose*Point))  
         return (OP_SELL);
        if(MacdCur<0 && MacdCur>SignalCur && MacdPre<SignalPre && MathAbs(MacdCur)>(MACDOpen*Point) && MaCur>MaPre) 
         return (OP_SELL);
    }
 
    return (-1); //no signal
}

منطق این سیستم در زبان MQL، خیلی متفاوت نخواهد بود. تمام توابع جهانی می‌شوند. و برای متفاوت شدن معاملات یک سیستم ترید، با معاملات یک سیستم دیگر، نیاز است پارامتر SignalID (به‌عبارت دیگر، MAGIC) را در تمام توابعی که با معاملات سروکار دارند، اضافه کنید.

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

  • [۱]) Object Approach in MQL
  • [۲]) Global identifier
  • [۳]) Identifier
  • [۴]) Object classes

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

M23admin

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

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

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

تبدیل کد اندیکاتور به کد اکسپرت. ساختار اندیکاتور

۳۷ مورد نظر

نوشتن نظر شما

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