سفارشیسازی سبک نمایش در مدل محدودیت روند شمعی | بهبود تحلیل تکنیکال با MQL5
سبکهای رسم سفارشی میتوانند جذابیت بصری نمودارها را افزایش دهند و آنها را خواناتر و جالبتر کنند. یک نمودار طراحیشده بهخوبی میتواند تجربه کاربری را بهبود بخشد و خستگی چشم را در طول جلسات معاملاتی طولانی کاهش دهد. با سفارشیسازی سبکهای رسم به نیازهای خاص، معاملهگران میتوانند چیدمانهای معاملاتی مؤثرتر و کارآمدتری ایجاد کنند. بهعنوان مثال، استفاده از هیستوگرامها برای نمایش دادههای حجم یا خطوط برای میانگینهای متحرک میتواند تفسیر این شاخصها را در یک نگاه آسانتر کند. سبکهای رسم مانند پیکانها یا نمادها میتوانند برای علامتگذاری رویدادها یا سیگنالهای خاص در نمودار استفاده شوند، مانند نقاط خرید/فروش که شناسایی فرصتهای معاملاتی را آسانتر میکند.
MQL5 مجموعهای از سبکهای رسم مختلف را برای شاخصها در MetaTrader 5 ارائه میدهد. این عناصر بصری به معاملهگران مزیت تحلیلی میدهند و به آنها کمک میکنند تا به سرعت به احساسات بازار پاسخ دهند. گنجاندن این سبکهای مختلف رسم نه تنها جذابیت زیباییشناختی نمودارها را افزایش میدهد، بلکه به معاملهگران این امکان را میدهد که بر اساس تجزیه و تحلیل جامع دینامیکهای بازار تصمیمات آگاهانهتری اتخاذ کنند. معاملهگران میتوانند حرکات قیمت را بهطور مؤثر تفسیر کرده و روندها و معکوسهای بالقوه را با دقت بیشتری شناسایی کنند. MQL5 شامل ۱۸ نوع مختلف از نمودارهای گرافیکی است. در این مقاله، میخواهیم عمیقتر بپردازیم و بررسی کنیم که چگونه میتوان یکی از این سبکهای نمایش را به مدل خود اضافه کرد.
بهجای اینکه فقط یک پیکان برای هشدار خود رسم کنیم، میخواهیم یک نمایش پیشرفتهتر بر روی نمودار ایجاد کنیم تا آن را حتی سادهتر کنیم. به یاد داشته باشید که هدف ما در این سری مقالات این است که مدل محدودیت روند خود را بهگونهای اصلاح کنیم که با احساس شکل شمعی 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 را پیدا کنید.
پس از کامپایل برنامه با استفاده از این تنظیمات ورودی، میتوانید سند منبع را در زیر نتیجهگیری این مقاله پیدا کنید. در ادامه، آخرین کد برای 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"
نکته: بخش فوق به عنوان یک فضای نگهدارنده برای اطلاعات اضافی عمل میکند. جزئیات بیشتر در کد اصلی زیر موجود است. طرح بافر انعطافپذیر است و میتوان تغییراتی در مقادیر آن ایجاد کرد، به شرطی که هدف اصلی به طور مداوم حفظ شود.
///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
برنامه نوآورانه ما اکنون قابلیتهای پیشرفتهای را به نمایش میگذارد که شامل تغییر رنگ یک خط بههنگام تعیین یک روند جدید است. این ویژگی، نمودار را سادهتر کرده و با افزودن رنگ، سیستم سیگنالدهی را به همراه دیگر اعلانهای بصری و صوتی بهبود میبخشد. تصاویر زیر نمایشی بصری از تأثیر این ویژگی جدید را ارائه میدهند.
شکل ۳: مدل محدودیت روند نسخه ۱.۰۴ بر روی شاخص 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.
پس از اتمام کامپایل کد، میتوانید اسکریپت را پیدا کرده و مطابق با دستورالعملهای ارائهشده در تصویر اجرا کنید. این اسکریپت یک پیام را نمایش میدهد که وضعیت شمع روز جاری را نشان میدهد.
شکل ۴: اجرای اسکریپت My_D1_candlestatus.mq5
دانلود فایل های مربوطه در این مقاله
سایر گزینهها برای سبکهای رسم MQL5
پلتفرم MetaTrader 5 با مجموعهای گسترده از ابزارهای ترسیمی برای ارزیابی بازار، از جمله خطوط، کانالها و اشکال، ارائه میشود که همه این امکانات بهراحتی در دسترس است. با درک عمیق زبان برنامهنویسی شیءگرا MQL5 و ارتباط آن با Python و C++، معاملهگران قادرند ابزارها و توسعههای شخصیسازیشده ایجاد کنند. این ابزارها به معاملهگران کمک میکنند تا تواناییهای تحلیل تکنیکی خود را بهبود بخشند و تصمیمات تجاری آگاهانهتری بگیرند. با انعطافپذیری و گزینههای سفارشیسازی موجود در MetaTrader 5، معاملهگران میتوانند تجربه معاملاتی خود را مطابق با ترجیحات و استراتژیهای خود تنظیم کنند.
نتیجهگیری
ما با موفقیت یک ویژگی جدید را به برنامهمان اضافه کردیم که نتایج مثبتی به همراه داشته و پتانسیل تأثیرگذاری بر نسخههای آینده را دارد. ما در مقالات بعدی از یک اندیکاتور به یک EA (مشاور متخصص) پیشرفت خواهیم کرد. سبکهای رسم در MQL5 مزایای قابل توجهی برای معاملهگران فراهم میکند و وضوح، دقت و سفارشیسازی بصری دادهها را افزایش میدهد. این سبکها قابلیتهای تحلیل تکنیکی را تقویت کرده و تکنیکهای پیشرفته ترسیم را تسهیل میکند و به روزرسانیهای تعاملی و آنی را پشتیبانی میکند. علاوه بر این، انعطافپذیری و خلاقیتی که توسط سبکهای رسم MQL5 فراهم میشود، به معاملهگران این امکان را میدهد که شاخصها و ابزارهای تحلیلی منحصربهفردی بسازند و رویکردهای معاملاتی و درک کلی از بازار را غنیسازی کنند.
مدل ما در حال تکامل است و با دقت بهینهشده، بینشهای بصری آنی را با یک کلیک ارائه میدهد. این اسکریپت بهسرعت وضعیت شمع D1 را منتقل میکند، در حالی که ویژگی DRAW_LINE روندها را در یک بازه زمانی پایینتر بهطور قابل فهمی نشان میدهد. من فایلهای منبع برای تمام ویژگیهای بحثشده در اینجا را شامل کردهام. امیدوارم شما نیز از پیشرفتهای این پروژه بهرهبرداری کنید و از شما دعوت میکنم نظرات خود را به اشتراک بگذارید و در بحثها شرکت کنید.
نظرات کاربران