سفارشی‌سازی سبک نمایش در مدل محدودیت روند شمعی | بهبود تحلیل تکنیکال با MQL5
بازدید 75

سفارشی‌سازی سبک نمایش در مدل محدودیت روند شمعی | بهبود تحلیل تکنیکال با MQL5

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

 

MQL5 مجموعه‌ای از سبک‌های رسم مختلف را برای شاخص‌ها در MetaTrader 5 ارائه می‌دهد. این عناصر بصری به معامله‌گران مزیت تحلیلی می‌دهند و به آن‌ها کمک می‌کنند تا به سرعت به احساسات بازار پاسخ دهند. گنجاندن این سبک‌های مختلف رسم نه تنها جذابیت زیبایی‌شناختی نمودارها را افزایش می‌دهد، بلکه به معامله‌گران این امکان را می‌دهد که بر اساس تجزیه و تحلیل جامع دینامیک‌های بازار تصمیمات آگاهانه‌تری اتخاذ کنند. معامله‌گران می‌توانند حرکات قیمت را به‌طور مؤثر تفسیر کرده و روندها و معکوس‌های بالقوه را با دقت بیشتری شناسایی کنند. MQL5 شامل ۱۸ نوع مختلف از نمودارهای گرافیکی است. در این مقاله، می‌خواهیم عمیق‌تر بپردازیم و بررسی کنیم که چگونه می‌توان یکی از این سبک‌های نمایش را به مدل خود اضافه کرد.

 

برای مشاوره و  طراحی اکسپرت، اندیکاتور یا ربات های معامله گر می توانید با کارشناسان ما تماس بگیرید ، ما همواره پاسخگو شما خواهیم بود.شماره تماس پشتیبانی سایت هوش فعال : 09364549266

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

 

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

 

خلاصه

در مقالات قبلی این سری (قسمت ۱، قسمت ۲ و قسمت ۳) هدف این بود که هر سیگنال را به احساس شمع D1 محدود کنیم. مفهوم این است که اگر شمع D1 صعودی باشد، معمولاً روند کلی روز در تایم‌فریم‌های پایین‌تر صعودی خواهد بود. با استفاده از روش‌های تحلیلی پیشرفته در تایم‌فریم‌های پایین‌تر، می‌توانیم نقاط ورود را شناسایی کرده و سیگنال‌هایی تولید کنیم که با روند فعلی هم‌راستا باشند. با هر مرحله، ما کد منبع خود را بهبود بخشیدیم و ویژگی‌های جدیدی را به مدل خود اضافه کردیم. در سری مقالات، ما از پیکان‌ها به‌عنوان یک عنصر طراحی برای هر مرحله از نشانگر خود استفاده کردیم و به بررسی استفاده از فونت Wingdings برای عناصر نمایشی اختیاری پرداختیم.

 

ما میانگین‌های متحرک ۲۰۰ و ۱۰۰ را به دارایی در نمودار MQL5 اضافه کردیم تا استراتژی‌سازی کنیم. با تجزیه و تحلیل رفتار این شاخص‌های داخلی، رویداد تقاطع دوره‌ای مهمی را شناسایی کردیم. سپس، یک نشانگر تقاطع شخصی‌سازی‌شده با سیستم هشدار ایجاد کردیم تا ما را از چنین وقایعی مطلع کند و نشان‌دهنده یک معکوس بالقوه روند باشد. تنظیم مقادیر MA به سطوح بالاتر می‌تواند به فیلتر کردن سیگنال‌ها در هنگام نوسانات بازار کمک کند. در قسمت ۳، من روش را با معرفی ورودی دوره MA قابل تنظیم بهبود بخشیدم تا مقادیر دوره مختلف را بررسی کرده و تنظیم بهینه برای معکوس‌های روند را تعیین کنم.

input int Slow_MA_period = 200;
input int Fast_MA_period = 100;

نرم‌افزار این امکان را فراهم می‌کند که به‌صورت فوری تنظیمات ورودی نمایش داده‌شده در نمای بصری را تغییر دهید. برای ویرایش ویژگی‌های آن، می‌توانید از ترکیب کلید Ctrl + I در حین مشاهده نمودار متاتریدر ۵ استفاده کنید یا با کلیک راست روی ماوس، منوی اندیکاتور را باز کرده و گزینه Trend Constraint V1.03 را پیدا کنید.

سفارشی‌سازی سبک نمایش در مدل محدودیت روند شمعی | بهبود تحلیل تکنیکال با MQL5

پس از کامپایل برنامه با استفاده از این تنظیمات ورودی، می‌توانید سند منبع را در زیر نتیجه‌گیری این مقاله پیدا کنید. در ادامه، آخرین کد برای Trend Constraint V1.03 ارائه شده است:

/// Program after adding Moving Average optimization feature for reversals
///Indicator Name: Trend Constraint
#property copyright "Clemence Benjamin"
#property link      "https://mql5.com"
#property version   "1.03"
#property description "A model that seek to produce sell signal when D1 candle is Bearish only and  buy signal when it is Bullish"


//--- indicator settings
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots 4

#property indicator_type1 DRAW_ARROW
#property indicator_width1 5
#property indicator_color1 0xFF3C00
#property indicator_label1 "Buy"

#property indicator_type2 DRAW_ARROW
#property indicator_width2 5
#property indicator_color2 0x0000FF
#property indicator_label2 "Sell"

#property indicator_type3 DRAW_ARROW
#property indicator_width3 1
#property indicator_color3 0x04CC04
#property indicator_label3 "Buy Reversal"

#property indicator_type4 DRAW_ARROW
#property indicator_width4 1
#property indicator_color4 0xE81AC6
#property indicator_label4 "Sell Reversal"

#define PLOT_MAXIMUM_BARS_BACK 5000
#define OMIT_OLDEST_BARS 50

//--- indicator buffers
double Buffer1[];
double Buffer2[];
double Buffer3[];
double Buffer4[];

input double Oversold = 30;
input double Overbought = 70;
input int Slow_MA_period = 200;
input int Fast_MA_period = 100;
datetime time_alert; //used when sending alert
input bool Audible_Alerts = true;
input bool Push_Notifications = true;
double myPoint; //initialized in OnInit
int RSI_handle;
double RSI[];
double Open[];
double Close[];
int MA_handle;
double MA[];
int MA_handle2;
double MA2[];
int MA_handle3;
double MA3[];
int MA_handle4;
double MA4[];
double Low[];
double High[];

void myAlert(string type, string message)
  {
   if(type == "print")
      Print(message);
   else if(type == "error")
     {
      Print(type+" | Trend Constraint V1.03 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
     }
   else if(type == "order")
     {
     }
   else if(type == "modify")
     {
     }
   else if(type == "indicator")
     {
      if(Audible_Alerts) Alert(type+" | Trend Constraint V1.03 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
      if(Push_Notifications) SendNotification(type+" | Trend Constraint V1.03 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
     }
  }

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {   
   SetIndexBuffer(0, Buffer1);
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(0, PLOT_ARROW, 241);
   SetIndexBuffer(1, Buffer2);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(1, PLOT_ARROW, 242);
   SetIndexBuffer(2, Buffer3);
   PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(2, PLOT_ARROW, 236);
   SetIndexBuffer(3, Buffer4);
   PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(3, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(3, PLOT_ARROW, 238);
   //initialize myPoint
   myPoint = Point();
   if(Digits() == 5 || Digits() == 3)
     {
      myPoint *= 10;
     }
   RSI_handle = iRSI(NULL, PERIOD_CURRENT, 14, PRICE_CLOSE);
   if(RSI_handle < 0)
     {
      Print("The creation of iRSI has failed: RSI_handle=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_SMMA, PRICE_CLOSE);
   if(MA_handle < 0)
     {
      Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle2 = iMA(NULL, PERIOD_CURRENT, 400, 0, MODE_SMA, PRICE_CLOSE);
   if(MA_handle2 < 0)
     {
      Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle3 = iMA(NULL, PERIOD_CURRENT, Fast_MA_period, 0, MODE_EMA, PRICE_CLOSE);
   if(MA_handle3 < 0)
     {
      Print("The creation of iMA has failed: MA_handle3=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle4 = iMA(NULL, PERIOD_CURRENT, Slow_MA_period, 0, MODE_SMA, PRICE_CLOSE);
   if(MA_handle4 < 0)
     {
      Print("The creation of iMA has failed: MA_handle4=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
   int limit = rates_total - prev_calculated;
   //--- counting from 0 to rates_total
   ArraySetAsSeries(Buffer1, true);
   ArraySetAsSeries(Buffer2, true);
   ArraySetAsSeries(Buffer3, true);
   ArraySetAsSeries(Buffer4, true);
   //--- initial zero
   if(prev_calculated < 1)
     {
      ArrayInitialize(Buffer1, EMPTY_VALUE);
      ArrayInitialize(Buffer2, EMPTY_VALUE);
      ArrayInitialize(Buffer3, EMPTY_VALUE);
      ArrayInitialize(Buffer4, EMPTY_VALUE);
     }
   else
      limit++;
   datetime Time[];
   
   datetime TimeShift[];
   if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total);
   ArraySetAsSeries(TimeShift, true);
   int barshift_M1[];
   ArrayResize(barshift_M1, rates_total);
   int barshift_D1[];
   ArrayResize(barshift_D1, rates_total);
   for(int i = 0; i < rates_total; i++)
     {
      barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]);
      barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]);
   }
   if(BarsCalculated(RSI_handle) <= 0) 
      return(0);
   if(CopyBuffer(RSI_handle, 0, 0, rates_total, RSI) <= 0) return(rates_total);
   ArraySetAsSeries(RSI, true);
   if(CopyOpen(Symbol(), PERIOD_M1, 0, rates_total, Open) <= 0) return(rates_total);
   ArraySetAsSeries(Open, true);
   if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close) <= 0) return(rates_total);
   ArraySetAsSeries(Close, true);
   if(BarsCalculated(MA_handle) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total);
   ArraySetAsSeries(MA, true);
   if(BarsCalculated(MA_handle2) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total);
   ArraySetAsSeries(MA2, true);
   if(BarsCalculated(MA_handle3) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle3, 0, 0, rates_total, MA3) <= 0) return(rates_total);
   ArraySetAsSeries(MA3, true);
   if(BarsCalculated(MA_handle4) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle4, 0, 0, rates_total, MA4) <= 0) return(rates_total);
   ArraySetAsSeries(MA4, true);
   if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total);
   ArraySetAsSeries(Low, true);
   if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total);
   ArraySetAsSeries(High, true);
   if(CopyTime(Symbol(), Period(), 0, rates_total, Time) <= 0) return(rates_total);
   ArraySetAsSeries(Time, true);
   //--- main loop
   for(int i = limit-1; i >= 0; i--)
     {
      if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation   
      
      if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue;
      if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue;
      
      //Indicator Buffer 1
      if(RSI[i] < Oversold
      && RSI[i+1] > Oversold //Relative Strength Index crosses below fixed value
      && Open[barshift_M1[i]] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close
      && MA[i] > MA2[i] //Moving Average > Moving Average
      && MA3[i] > MA4[i] //Moving Average > Moving Average
      )
        {
         Buffer1[i] = Low[1+i]; //Set indicator value at Candlestick Low
         if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy"); //Alert on next bar open
         time_alert = Time[1];
        }
      else
        {
         Buffer1[i] = EMPTY_VALUE;
        }
      //Indicator Buffer 2
      if(RSI[i] > Overbought
      && RSI[i+1] < Overbought //Relative Strength Index crosses above fixed value
      && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close
      && MA[i] < MA2[i] //Moving Average < Moving Average
      && MA3[i] < MA4[i] //Moving Average < Moving Average
      )
        {
         Buffer2[i] = High[1+i]; //Set indicator value at Candlestick High
         if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell"); //Alert on next bar open
         time_alert = Time[1];
        }
      else
        {
         Buffer2[i] = EMPTY_VALUE;
        }
      //Indicator Buffer 3
      if(MA3[i] > MA4[i]
      && MA3[i+1] < MA4[i+1] //Moving Average crosses above Moving Average
      )
        {
         Buffer3[i] = Low[i]; //Set indicator value at Candlestick Low
         if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy Reversal"); //Alert on next bar open
         time_alert = Time[1];
        }
      else
        {
         Buffer3[i] = EMPTY_VALUE;
        }
      //Indicator Buffer 4
      if(MA3[i] < MA4[i]
      && MA3[i+1] > MA4[i+1] //Moving Average crosses below Moving Average
      )
        {
         Buffer4[i] = High[i]; //Set indicator value at Candlestick High
         if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell Reversal"); //Alert on next bar open
         time_alert = Time[1];
        }
      else
        {
         Buffer4[i] = EMPTY_VALUE;
        }
     }
   return(rates_total);
  }
//Thank you, friend. You have reached this stage and you can do more+

سبک‌های نمایش MQL5

MQL5 مجموعه گسترده‌ای از سبک‌های ترسیم برای اندیکاتورها را ارائه می‌دهد. هنگام توسعه اندیکاتورها، هدف اصلی معمولاً طراحی سیستم‌هایی است که بتوانند از طریق صدا و نشانه‌های بصری کاربران را مطلع کنند. این امر به ساده‌سازی عملیات معاملاتی کمک می‌کند و نیاز به نظارت مداوم بر چارت‌ها را کاهش می‌دهد، زیرا کامپیوتر این مسئولیت را بر عهده می‌گیرد. در ادامه، مروری مختصر بر برخی از سبک‌های ترسیم قابل استفاده در MQL5 ارائه می‌شود، از جمله DRAW_ARROW، DRAW_LINE، DRAW_HISTOGRAM، DRAW_FILLING و DRAW_NONE. برای اطلاعات دقیق‌تر در مورد سبک‌های ترسیم، به جدول زیر و همچنین مرجع MQL5 مراجعه کنید.

سبک ترسیم توضیحات
DRAW_ARROW برای ترسیم فلش‌ها در نقاط مشخص، معمولاً برای نمایش سیگنال‌های خرید/فروش و رویدادهای مهم استفاده می‌شود.
DRAW_LINE برای ترسیم خطی که نقاط داده را به هم وصل می‌کند. ایده‌آل برای میانگین‌های متحرک و خطوط روند.
DRAW_HISTOGRAM داده‌ها را به صورت میله‌ای یا هیستوگرام نمایش می‌دهد. مناسب برای حجم، هیستوگرام MACD و سایر اندیکاتورهای میله‌ای.
DRAW_FILLING برای پر کردن ناحیه بین دو خط در چارت، ارائه راهی بصری و شهودی برای نمایش دامنه‌های داده یا تفاوت‌ها.
DRAW_NONE برای تعریف اندیکاتوری که هیچ نمایشی روی چارت ندارد.

پیاده‌سازی سبک DRAW_LINE در سیستم ما

بیایید از تابع DRAW_LINE برای نمایش روندها به‌صورت متمایز در چارت متاتریدر 5 استفاده کنیم. در گذشته، توانستیم اندیکاتور خود را به‌طور مؤثر برای شناسایی معکوس‌های روند از طریق تقاطع‌های میانگین متحرک با دوره‌های بالاتر راه‌اندازی کنیم. هدف ما اکنون بهبود نحوه ارائه اطلاعات به‌صورت بصری است بدون اینکه چارت را با عناصر زیاد شلوغ کنیم. این افزودنی جدید به ما این امکان را می‌دهد که یک خط واحد ترسیم کنیم که روندها را نمایش دهد و با هر تغییر جهت، رنگ آن به‌طور خودکار تغییر کند.

برای نسخه 1.04، با چهار بافر فعلی، قصد داریم قابلیت‌های خود را با معرفی بافر 5 و بافر 6 گسترش دهیم.

بافر 5: برای ترسیم یک خط آبی هنگامی که MA 100 بالای MA 200 باشد.

///properties
#property indicator_type5 DRAW_LINE
#property indicator_style5 STYLE_SOLID
#property indicator_width5 2
#property indicator_color5 0xFFAA00
#property indicator_label5 "Buy Trend"

بافر 6: برای ترسیم یک خط قرمز هنگامی که MA 100 پایین‌تر از MA 200 باشد.

#property indicator_type6 DRAW_LINE
#property indicator_style6 STYLE_SOLID
#property indicator_width6 2
#property indicator_color6 0x0000FF
#property indicator_label6 "Sell Trend"

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

کد اصلی برای Trend Constraint v1.04

///Indicator Name: Trend Constraint
#property copyright "Clemence Benjamin"
#property link      "https://mql5.com"
#property version   "1.04"
#property description "A model that seek to produce sell signal when D1 candle is Bearish only and  buy signal when it is Bullish"
//--- indicator settings
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots 6

#property indicator_type1 DRAW_ARROW
#property indicator_width1 5
#property indicator_color1 0xFF3C00
#property indicator_label1 "Buy"

#property indicator_type2 DRAW_ARROW
#property indicator_width2 5
#property indicator_color2 0x0000FF
#property indicator_label2 "Sell"

#property indicator_type3 DRAW_ARROW
#property indicator_width3 2
#property indicator_color3 0xE8351A
#property indicator_label3 "Buy Reversal"

#property indicator_type4 DRAW_ARROW
#property indicator_width4 2
#property indicator_color4 0x1A1AE8
#property indicator_label4 "Sell Reversal"

#property indicator_type5 DRAW_LINE
#property indicator_style5 STYLE_SOLID
#property indicator_width5 2
#property indicator_color5 0xFFAA00
#property indicator_label5 "Buy Trend"

#property indicator_type6 DRAW_LINE
#property indicator_style6 STYLE_SOLID
#property indicator_width6 2
#property indicator_color6 0x0000FF
#property indicator_label6 "Sell Trend"

#define PLOT_MAXIMUM_BARS_BACK 5000
#define OMIT_OLDEST_BARS 50

//--- indicator buffers
double Buffer1[];
double Buffer2[];
double Buffer3[];
double Buffer4[];
double Buffer5[];
double Buffer6[];

input double Oversold = 30;
input double Overbought = 70;
input int Slow_MA_period = 200;
input int Fast_MA_period = 100;
datetime time_alert; //used when sending alert
input bool Audible_Alerts = true;
input bool Push_Notifications = true;
double myPoint; //initialized in OnInit
int RSI_handle;
double RSI[];
double Open[];
double Close[];
int MA_handle;
double MA[];
int MA_handle2;
double MA2[];
int MA_handle3;
double MA3[];
int MA_handle4;
double MA4[];
double Low[];
double High[];
int MA_handle5;
double MA5[];
int MA_handle6;
double MA6[];

void myAlert(string type, string message)
  {
   if(type == "print")
      Print(message);
   else if(type == "error")
     {
      Print(type+" | Trend Constraint V1.04 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
     }
   else if(type == "order")
     {
     }
   else if(type == "modify")
     {
     }
   else if(type == "indicator")
     {
      if(Audible_Alerts) Alert(type+" | Trend Constraint V1.04 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
      if(Push_Notifications) SendNotification(type+" | Trend Constraint V1.04 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
     }
  }

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {   
   SetIndexBuffer(0, Buffer1);
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(0, PLOT_ARROW, 241);
   SetIndexBuffer(1, Buffer2);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(1, PLOT_ARROW, 242);
   SetIndexBuffer(2, Buffer3);
   PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(2, PLOT_ARROW, 236);
   SetIndexBuffer(3, Buffer4);
   PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(3, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(3, PLOT_ARROW, 238);
   SetIndexBuffer(4, Buffer5);
   PlotIndexSetDouble(4, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(4, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   SetIndexBuffer(5, Buffer6);
   PlotIndexSetDouble(5, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(5, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   //initialize myPoint
   myPoint = Point();
   if(Digits() == 5 || Digits() == 3)
     {
      myPoint *= 10;
     }
   RSI_handle = iRSI(NULL, PERIOD_CURRENT, 14, PRICE_CLOSE);
   if(RSI_handle < 0)
     {
      Print("The creation of iRSI has failed: RSI_handle=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_SMMA, PRICE_CLOSE);
   if(MA_handle < 0)
     {
      Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle2 = iMA(NULL, PERIOD_CURRENT, 400, 0, MODE_SMA, PRICE_CLOSE);
   if(MA_handle2 < 0)
     {
      Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle3 = iMA(NULL, PERIOD_CURRENT, 100, 0, MODE_EMA, PRICE_CLOSE);
   if(MA_handle3 < 0)
     {
      Print("The creation of iMA has failed: MA_handle3=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle4 = iMA(NULL, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE);
   if(MA_handle4 < 0)
     {
      Print("The creation of iMA has failed: MA_handle4=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle5 = iMA(NULL, PERIOD_CURRENT, Fast_MA_period, 0, MODE_SMA, PRICE_CLOSE);
   if(MA_handle5 < 0)
     {
      Print("The creation of iMA has failed: MA_handle5=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle6 = iMA(NULL, PERIOD_CURRENT, Slow_MA_period, 0, MODE_SMA, PRICE_CLOSE);
   if(MA_handle6 < 0)
     {
      Print("The creation of iMA has failed: MA_handle6=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
   int limit = rates_total - prev_calculated;
   //--- counting from 0 to rates_total
   ArraySetAsSeries(Buffer1, true);
   ArraySetAsSeries(Buffer2, true);
   ArraySetAsSeries(Buffer3, true);
   ArraySetAsSeries(Buffer4, true);
   ArraySetAsSeries(Buffer5, true);
   ArraySetAsSeries(Buffer6, true);
   //--- initial zero
   if(prev_calculated < 1)
     {
      ArrayInitialize(Buffer1, EMPTY_VALUE);
      ArrayInitialize(Buffer2, EMPTY_VALUE);
      ArrayInitialize(Buffer3, EMPTY_VALUE);
      ArrayInitialize(Buffer4, EMPTY_VALUE);
      ArrayInitialize(Buffer5, EMPTY_VALUE);
      ArrayInitialize(Buffer6, EMPTY_VALUE);
     }
   else
      limit++;
   datetime Time[];
   
   datetime TimeShift[];
   if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total);
   ArraySetAsSeries(TimeShift, true);
   int barshift_M1[];
   ArrayResize(barshift_M1, rates_total);
   int barshift_D1[];
   ArrayResize(barshift_D1, rates_total);
   for(int i = 0; i < rates_total; i++)
     {
      barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]);
      barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]);
   }
   if(BarsCalculated(RSI_handle) <= 0) 
      return(0);
   if(CopyBuffer(RSI_handle, 0, 0, rates_total, RSI) <= 0) return(rates_total);
   ArraySetAsSeries(RSI, true);
   if(CopyOpen(Symbol(), PERIOD_M1, 0, rates_total, Open) <= 0) return(rates_total);
   ArraySetAsSeries(Open, true);
   if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close) <= 0) return(rates_total);
   ArraySetAsSeries(Close, true);
   if(BarsCalculated(MA_handle) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total);
   ArraySetAsSeries(MA, true);
   if(BarsCalculated(MA_handle2) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total);
   ArraySetAsSeries(MA2, true);
   if(BarsCalculated(MA_handle3) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle3, 0, 0, rates_total, MA3) <= 0) return(rates_total);
   ArraySetAsSeries(MA3, true);
   if(BarsCalculated(MA_handle4) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle4, 0, 0, rates_total, MA4) <= 0) return(rates_total);
   ArraySetAsSeries(MA4, true);
   if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total);
   ArraySetAsSeries(Low, true);
   if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total);
   ArraySetAsSeries(High, true);
   if(BarsCalculated(MA_handle5) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle5, 0, 0, rates_total, MA5) <= 0) return(rates_total);
   ArraySetAsSeries(MA5, true);
   if(BarsCalculated(MA_handle6) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle6, 0, 0, rates_total, MA6) <= 0) return(rates_total);
   ArraySetAsSeries(MA6, true);
   if(CopyTime(Symbol(), Period(), 0, rates_total, Time) <= 0) return(rates_total);
   ArraySetAsSeries(Time, true);
   //--- main loop
   for(int i = limit-1; i >= 0; i--)
     {
      if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation   
      
      if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue;
      if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue;
      
      //Indicator Buffer 1
      if(RSI[i] < Oversold
      && RSI[i+1] > Oversold //Relative Strength Index crosses below fixed value
      && Open[barshift_M1[i]] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close
      && MA[i] > MA2[i] //Moving Average > Moving Average
      && MA3[i] > MA4[i] //Moving Average > Moving Average
      )
        {
         Buffer1[i] = Low[1+i]; //Set indicator value at Candlestick Low
         if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy"); //Alert on next bar open
         time_alert = Time[1];
        }
      else
        {
         Buffer1[i] = EMPTY_VALUE;
        }
      //Indicator Buffer 2
      if(RSI[i] > Overbought
      && RSI[i+1] < Overbought //Relative Strength Index crosses above fixed value
      && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close
      && MA[i] < MA2[i] //Moving Average < Moving Average
      && MA3[i] < MA4[i] //Moving Average < Moving Average
      )
        {
         Buffer2[i] = High[1+i]; //Set indicator value at Candlestick High
         if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell"); //Alert on next bar open
         time_alert = Time[1];
        }
      else
        {
         Buffer2[i] = EMPTY_VALUE;
        }
      //Indicator Buffer 3
      if(MA5[i] > MA6[i]
      && MA5[i+1] < MA6[i+1] //Moving Average crosses above Moving Average
      )
        {
         Buffer3[i] = Low[i]; //Set indicator value at Candlestick Low
         if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy Reversal"); //Alert on next bar open
         time_alert = Time[1];
        }
      else
        {
         Buffer3[i] = EMPTY_VALUE;
        }
      //Indicator Buffer 4
      if(MA5[i] < MA6[i]
      && MA5[i+1] > MA6[i+1] //Moving Average crosses below Moving Average
      )
        {
         Buffer4[i] = High[i]; //Set indicator value at Candlestick High
         if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell Reversal"); //Alert on next bar open
         time_alert = Time[1];
        }
      else
        {
         Buffer4[i] = EMPTY_VALUE;
        }
      //Indicator Buffer 5
      if(MA5[i] > MA6[i] //Moving Average > Moving Average
      )
        {
         Buffer5[i] = MA6[i]; //Set indicator value at Moving Average
         if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy Trend"); //Alert on next bar open
         time_alert = Time[1];
        }
      else
        {
         Buffer5[i] = EMPTY_VALUE;
        }
      //Indicator Buffer 6
      if(MA5[i] < MA6[i] //Moving Average < Moving Average
      )
        {
         Buffer6[i] = MA6[i]; //Set indicator value at Moving Average
         if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell Trend"); //Alert on next bar open
         time_alert = Time[1];
        }
      else
        {
         Buffer6[i] = EMPTY_VALUE;
        }
     }
   return(rates_total);
  }
//You are the best coder

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

سفارشی‌سازی سبک نمایش در مدل محدودیت روند شمعی | بهبود تحلیل تکنیکال با MQL5

شکل ۲: مدل محدودیت روند نسخه ۱.۰۴ بر روی USDJPY

سفارشی‌سازی سبک نمایش در مدل محدودیت روند شمعی | بهبود تحلیل تکنیکال با MQL5

شکل ۳: مدل محدودیت روند نسخه ۱.۰۴ بر روی شاخص Boom 500

وضعیت شمع D1 من

برای اضافه کردن یک ویژگی جدید به مدل خود، می‌خواهیم به محض اینکه به متاتریدر ۵ منتقل می‌شویم و از مدل‌مان استفاده می‌کنیم، وضعیت شمع D1 را سریعاً بررسی کنیم. تصمیم گرفتم از یک اسکریپت استفاده کنم که وضعیت شمع D1 را روی چارت نمایش دهد، حتی اگر چارت در تایم‌فریم‌های غیر از D1 باشد. این بهبود به شناسایی سریع وضعیت شمع کمک می‌کند، به ویژه زمانی که روی تایم‌فریم M1 کار می‌کنیم و جداکننده‌های دوره D1 ممکن است در برخی از زوم‌ها قابل مشاهده نباشند. حال بیایید کد اسکریپت MQL5 را که در زیر ارائه شده بررسی کنیم:

<//My_D1_candlestatus.mql5
//Author: Clemence Benjamin
//Link: https://www.mql5.com/en/users/billionaire2024/seller
#property copyright "Copyright 2024, Clemence Benjamin"
#property link      "https://www.mql5.com/en/users/billionaire2024/seller"
#property version   "1.00"
#property script_show_inputs
#property strict

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   //--- Get the opening and closing prices of the current D1 candle
   double openPrice = iOpen(NULL, PERIOD_D1, 0);
   double closePrice = iClose(NULL, PERIOD_D1, 0);
   
   //--- Determine if the candle is bullish or bearish
   string candleStatus;
   if(closePrice > openPrice)
     {
      candleStatus = " D1 candle is bullish.";
     }
   else if(closePrice < openPrice)
     {
      candleStatus = " D1 candle is bearish.";
     }
   else
     {
      candleStatus = " D1 candle is neutral.";// when open price is equal to close price
     
     }
   
   //--- Print the status on the chart
   Comment(candleStatus);
   
   //--- Also print the status in the Experts tab for logging
   Print(candleStatus);
  }
//+------------------------------------------------------------------+

درک توابع و متغیرهای اسکریپت My_D1_Candlestatus.mq5

Functions and Variable	Descriprition
OnStart()	This is the main function of the script that executes when the script is run. It retrieves the opening and closing prices of the current D1 candle, determines if the candle is bullish, bearish, or neutral, and then displays this information on the chart using Comment().
iOpen() and iClose()	These functions retrieve the opening and closing prices of the current D1 candle.

candleStatus	A string variable to store the status message of the current D1 candle.
Comment()	This function displays the status message on the chart.
Print()	This function logs the status message to the "Experts" tab for additional logging.

پس از اتمام کامپایل کد، می‌توانید اسکریپت را پیدا کرده و مطابق با دستورالعمل‌های ارائه‌شده در تصویر اجرا کنید. این اسکریپت یک پیام را نمایش می‌دهد که وضعیت شمع روز جاری را نشان می‌دهد.

سفارشی‌سازی سبک نمایش در مدل محدودیت روند شمعی | بهبود تحلیل تکنیکال با MQL5

شکل ۴: اجرای اسکریپت My_D1_candlestatus.mq5


دانلود فایل های مربوطه در این مقاله


سایر گزینه‌ها برای سبک‌های رسم MQL5

پلتفرم MetaTrader 5 با مجموعه‌ای گسترده از ابزارهای ترسیمی برای ارزیابی بازار، از جمله خطوط، کانال‌ها و اشکال، ارائه می‌شود که همه این امکانات به‌راحتی در دسترس است. با درک عمیق زبان برنامه‌نویسی شیءگرا MQL5 و ارتباط آن با Python و C++، معامله‌گران قادرند ابزارها و توسعه‌های شخصی‌سازی‌شده ایجاد کنند. این ابزارها به معامله‌گران کمک می‌کنند تا توانایی‌های تحلیل تکنیکی خود را بهبود بخشند و تصمیمات تجاری آگاهانه‌تری بگیرند. با انعطاف‌پذیری و گزینه‌های سفارشی‌سازی موجود در MetaTrader 5، معامله‌گران می‌توانند تجربه معاملاتی خود را مطابق با ترجیحات و استراتژی‌های خود تنظیم کنند.

نتیجه‌گیری

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

مدل ما در حال تکامل است و با دقت بهینه‌شده، بینش‌های بصری آنی را با یک کلیک ارائه می‌دهد. این اسکریپت به‌سرعت وضعیت شمع D1 را منتقل می‌کند، در حالی که ویژگی DRAW_LINE روندها را در یک بازه زمانی پایین‌تر به‌طور قابل فهمی نشان می‌دهد. من فایل‌های منبع برای تمام ویژگی‌های بحث‌شده در اینجا را شامل کرده‌ام. امیدوارم شما نیز از پیشرفت‌های این پروژه بهره‌برداری کنید و از شما دعوت می‌کنم نظرات خود را به اشتراک بگذارید و در بحث‌ها شرکت کنید.

نظرات کاربران

دیدگاهتان را بنویسید

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