मूविंग एवरेज EA, MetaTrader 5 क्लाइंट टर्मिनल के स्टैंडर्ड पैक में शामिल है और यह एक उदाहरण है कि कैसे मूविंग एवरेज इंडिकेटर का उपयोग करके ट्रेड किया जाता है।
EA फ़ाइल Moving Average.mq5 "terminal_data_folder\MQL5\Experts\Examples\Moving Average\" फ़ोल्डर में स्थित है। यह EA तकनीकी संकेतकों, ट्रेड इतिहास फंक्शंस और स्टैंडर्ड लाइब्रेरी के ट्रेडिंग क्लासेस के उपयोग का एक उदाहरण है। इसके अलावा, EA में एक मनी मैनेजमेंट सिस्टम भी शामिल है जो ट्रेड परिणामों पर आधारित है।
आइए हम इस एक्सपर्ट एडवाइजर की संरचना और इसके काम करने के तरीके पर गौर करें।
1. EA के गुण
//+------------------------------------------------------------------+ //| Moving Averages.mq5 | //| Copyright 2009-2013, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2009-2013, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00"
पहली 5 पंक्तियों में एक टिप्पणी है, उसके बाद तीन पंक्तियाँ MQL5-प्रोग्राम के गुण सेट करती हैं (कॉपीराइट, लिंक, संस्करण) #property प्रीप्रोसेसर निर्देशों का उपयोग करके।
जब आप एक्सपर्ट एडवाइजर को चलाते हैं, तो ये "कॉमन" टैब में प्रदर्शित होते हैं:

चित्र 1. मूविंग एवरेज EA के सामान्य पैरामीटर
1.2. शामिल फ़ाइलें
अगला, #include निर्देश कंपाइलर को "Trade.mqh" फ़ाइल शामिल करने के लिए कहता है।
यह फ़ाइल स्टैंडर्ड लाइब्रेरी का हिस्सा है, इसमें ट्रेडिंग फ़ंक्शंस तक आसान पहुँच के लिए CTrade क्लास शामिल है।
#include <Trade\Trade.mqh>शामिल फ़ाइल का नाम ब्रैकेट "<>;" में दिखाया गया है, इसलिए पथ को "terminal_data_folder\Include\" निर्देशिका के सापेक्ष सेट किया गया है।
1.3 इनपुट
फिर प्रकार, नाम, डिफ़ॉल्ट मान और एक टिप्पणी आती है। इनके कार्य को चित्र 2 में दिखाया गया है।
input double MaximumRisk = 0.02; // अधिकतम जोखिम प्रतिशत में input double DecreaseFactor = 3; // कमी कारक input int MovingPeriod = 12; // मूविंग एवरेज अवधि input int MovingShift = 6; // मूविंग एवरेज शिफ्ट
MaximumRisk और DecreaseFactor पैरामीटर का उपयोग मनी मैनेजमेंट के लिए किया जाएगा, MovingPeriod और MovingShift मूविंग एवरेज तकनीकी संकेतक की अवधि और शिफ्ट सेट करते हैं जो ट्रेड की स्थितियों की जांच के लिए उपयोग किया जाएगा।
इनपुट पैरामीटर पंक्ति में टिप्पणी में पाठ और डिफ़ॉल्ट मान "ऑप्शंस" टैब में प्रदर्शित होते हैं:

चित्र 2. मूविंग एवरेज EA के इनपुट पैरामीटर
1.4. वैश्विक चर
इसके बाद वैश्विक चर ExtHandle की घोषणा की जाती है। इसका उपयोग मूविंग एवरेज संकेतक के हैंडल को स्टोर करने के लिए किया जाएगा।
//--- int ExtHandle=0;
इसके बाद 6 फ़ंक्शन हैं। उनके प्रत्येक का उद्देश्य फ़ंक्शन के शरीर से पहले की टिप्पणी में वर्णित है:
- TradeSizeOptimized() - अनुकूलित लॉट आकार की गणना करें;
- CheckForOpen() - खुले पदों की स्थितियों की जांच करें;
- CheckForClose() - बंद स्थिति की स्थितियों की जांच करें;
- OnInit() - एक्सपर्ट इनिशियलाइजेशन फ़ंक्शन;
- OnTick() - एक्सपर्ट टिक फ़ंक्शन;
- OnDeinit() - एक्सपर्ट डीनिशियलाइजेशन फ़ंक्शन;
अंतिम तीन फ़ंक्शन इवेंट हैंडलिंग फ़ंक्शन हैं; पहले तीन सेवा फ़ंक्शन उनके कोड में कॉल होते हैं।
2. इवेंट हैंडलिंग फ़ंक्शन
2.1. OnInit() इनिशियलाइजेशन फ़ंक्शन
OnInit() फ़ंक्शन को एक्सपर्ट एडवाइजर के पहले स्टार्ट के दौरान एक बार कॉल किया जाता है। आमतौर पर OnInit() इवेंट हैंडलर में EA को संचालन के लिए तैयार किया जाता है: इनपुट पैरामीटर की जांच की जाती है, संकेतकों और पैरामीटर को इनिशियलाइज किया जाता है, आदि। गंभीर त्रुटियों के मामले में, जब आगे का काम अर्थहीन होता है, तो फ़ंक्शन INIT_FAILED रिटर्न कोड के साथ बाहर निकलता है।
//+------------------------------------------------------------------+ //| एक्सपर्ट इनिशियलाइजेशन फ़ंक्शन | //+------------------------------------------------------------------+ int OnInit(void) { //--- ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE); if(ExtHandle==INVALID_HANDLE) { printf("MA संकेतक बनाने में त्रुटि"); return(INIT_FAILED); } //--- return(INIT_SUCCEEDED); }
चूंकि EA ट्रेडिंग मूविंग एवरेज संकेतक पर आधारित होती है, iMA() को कॉल करके मूविंग एवरेज संकेतक बनाया जाता है और इसका हैंडल वैश्विक चर ExtHandle में सहेजा जाता है।
यदि कोई त्रुटि होती है, तो OnInit() एक रिटर्न कोड INIT_FAILED के साथ बाहर निकलता है - यह असफल इनिशियलाइजेशन के मामले में EA/इंडिकेटर संचालन को समाप्त करने का सही तरीका है।
2.2. OnTick() फ़ंक्शन
OnTick() फ़ंक्शन को हर बार उस प्रतीक के लिए नए उद्धरण प्राप्त होने पर कॉल किया जाता है, जिस पर EA चल रहा है।
//+------------------------------------------------------------------+ //| एक्सपर्ट टिक फ़ंक्शन | //+------------------------------------------------------------------+ void OnTick(void) { //--- if(PositionSelect(_Symbol)) CheckForClose(); else CheckForOpen(); //--- }
PositionSelect() फ़ंक्शन का उपयोग वर्तमान प्रतीक के लिए एक खुली स्थिति का निर्धारण करने के लिए किया जाता है।
यदि कोई खुली स्थिति है, तो CheckForClose() फ़ंक्शन को कॉल किया जाता है, जो बाजार की वर्तमान स्थिति का विश्लेषण करता है और खुली स्थिति को बंद करता है, अन्यथा CheckForOpen() को कॉल किया जाता है, जो बाजार में प्रवेश की स्थितियों की जांच करता है और यदि ऐसी स्थितियां बनती हैं तो एक नई स्थिति खोलता है।
2.3. OnDeInit() डीनिशियलाइजेशन फ़ंक्शन
OnDeInit() फ़ंक्शन तब कॉल किया जाता है जब EA को चार्ट से हटा दिया जाता है। यदि कोई प्रोग्राम संचालन के दौरान ग्राफिकल ऑब्जेक्ट्स रखता है, तो उन्हें चार्ट से हटा दिया जा सकता है।
//+------------------------------------------------------------------+ //| एक्सपर्ट डीनिशियलाइजेशन फ़ंक्शन | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+
इस मामले में एक्सपर्ट एडवाइजर डीनिशियलाइजेशन के दौरान कोई क्रियाएँ नहीं की जाती हैं।
3. सेवा फ़ंक्शन
3.1. TradeSizeOptimized() फ़ंक्शन
यह फ़ंक्शन निर्दिष्ट जोखिम स्तर और व्यापार परिणामों के साथ स्थिति खोलने के लिए अनुकूलित लॉट आकार की गणना करता है और इसे रिटर्न करता है।
//+------------------------------------------------------------------+ //| अनुकूलित लॉट आकार की गणना करें | //+------------------------------------------------------------------+ double TradeSizeOptimized(void) { double price=0.0; double margin=0.0; //--- लॉट आकार की गणना करें if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price)) return(0.0); if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin)) return(0.0); if(margin<=0.0) return(0.0); double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)*MaximumRisk/margin,2); //--- लगातार हारे हुए ट्रेडों की श्रृंखला की लंबाई की गणना करें if(DecreaseFactor>0) { //--- पूरी ट्रेडिंग हिस्ट्री का अनुरोध करें HistorySelect(0,TimeCurrent()); //-- int orders=HistoryDealsTotal(); // कुल सौदों की संख्या int losses=0 // श्रृंखला में हारे हुए सौदों की संख्या for(int i=orders-1;i>=0;i--) { ulong ticket=HistoryDealGetTicket(i); if(ticket==0) { Print("HistoryDealGetTicket विफल, कोई ट्रेड इतिहास नहीं"); break; } //--- सौदे के प्रतीक की जांच करें if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol) continue; //--- लाभ की जांच करें double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT); if(profit>0.0) break; if(profit<0.0) losses++; } //--- if(losses>1) lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1); } //--- ट्रेड वॉल्यूम के अनुमत मूल्यों की सामान्यीकरण और जाँच करें double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); lot=stepvol*NormalizeDouble(lot/stepvol,0); double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); if(lot<minvol) lot=minvol; double maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX); if(lot>maxvol) lot=maxvol; //--- ट्रेड वॉल्यूम का मान लौटाएँ return(lot); }
SymbolInfoDouble() फ़ंक्शन का उपयोग वर्तमान प्रतीक के लिए कीमतों की उपलब्धता की जांच करने के लिए किया जाता है, इसके बाद OrderCalcMargin() फ़ंक्शन का उपयोग आदेश लगाने के लिए आवश्यक मार्जिन का अनुरोध करने के लिए किया जाता है (इस मामले में एक खरीद आदेश)। प्रारंभिक लॉट आकार उस मार्जिन के मूल्य से निर्धारित किया जाता है जो एक आदेश लगाने के लिए आवश्यक होता है, खाते के फ्री मार्जिन (AccountInfoDouble(ACCOUNT_FREEMARGIN)) और इनपुट पैरामीटर MaximumRisk में निर्दिष्ट अधिकतम अनुमत मान।
यदि इनपुट पैरामीटर DecreaseFactor का मान सकारात्मक है, तो इतिहास में सौदों का विश्लेषण किया जाता है और लॉट के आकार को लगातार हारे हुए ट्रेडों की अधिकतम श्रृंखला के बारे में जानकारी के अनुसार समायोजित किया जाता है: प्रारंभिक लॉट आकार को (1-losses/DecreaseFactor) से गुणा किया जाता है।
फिर ट्रेड वॉल्यूम को मौजूदा प्रतीक के लिए न्यूनतम अनुमत वॉल्यूम के चरण (stepvol) के मूल्य के लिए कई गुना "गोल" किया जाता है। साथ ही ट्रेड वॉल्यूम के न्यूनतम (minvol) और अधिकतम संभावित मान (maxvol) का अनुरोध किया जाता है, और यदि लॉट वैल्यू अनुमत सीमाओं से बाहर होती है, तो इसे समायोजित किया जाता है। परिणामस्वरूप, फ़ंक्शन ट्रेडिंग वॉल्यूम का गणना किया हुआ मान लौटाता है।
3.2. CheckForOpen() फ़ंक्शन
CheckForOpen() स्थिति खोलने की स्थितियों की जांच करने के लिए उपयोग किया जाता है और व्यापार स्थितियों के बनने पर इसे खोलता है (इस मामले में जब मूल्य मूविंग एवरेज को पार करता है)।
//+------------------------------------------------------------------+ //| स्थिति खोलने की स्थितियों की जांच करें | //+------------------------------------------------------------------+ void CheckForOpen(void) { MqlRates rt[2]; //--- मूल्य मानों की कॉपी करें if(CopyRates(_Symbol,_Period,0,2,rt)!=2) { Print("CopyRates of ",_Symbol," विफल, कोई इतिहास नहीं"); return; } //--- नए बार के पहले टिक पर व्यापार करें if(rt[1].tick_volume>1) return; //--- मूविंग एवरेज संकेतक का वर्तमान मान प्राप्त करें double ma[1]; if(CopyBuffer(ExtHandle,0,0,1,ma)!=1) { Print("CopyBuffer from iMA विफल, कोई डेटा नहीं"); return; } //--- सिग्नल की जांच करें ENUM_ORDER_TYPE signal=WRONG_VALUE; if(rt[0].open>ma[0] && rt[0].close<ma[0]) signal=ORDER_TYPE_SELL // बिक्री की स्थिति else { if(rt[0].open<ma[0] && rt[0].close>ma[0]) signal=ORDER_TYPE_BUY // खरीद की स्थिति } //--- अतिरिक्त जांच if(signal!=WRONG_VALUE) if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) if(Bars(_Symbol,_Period)>100) { CTrade trade; trade.PositionOpen(_Symbol,signal,TradeSizeOptimized(), SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK), 0,0); } //--- }
जब मूविंग का उपयोग करके ट्रेड किया जा रहा होता है, तो आपको जांच करनी होती है कि मूल्य मूविंग एवरेज को पार करता है या नहीं। CopyRates() फ़ंक्शन का उपयोग करके वर्तमान कीमतों के दो मानों को संरचना rt[] में कॉपी किया जाता है, rt[1] वर्तमान बार के लिए है, rt[0] - पूर्ण बार के लिए।
एक नया बार शुरू होने की पहचान करने के लिए वर्तमान बार की टिक मात्रा की जांच की जाती है यदि यह 1 के बराबर है, तो एक नया बार शुरू हो गया है। यह नोट करना चाहिए कि बार की पहचान करने का यह तरीका कुछ मामलों में विफल हो सकता है (जब उद्धरण पैक में आते हैं), इसलिए नए बार के गठन की पहचान करने के लिए वर्तमान उद्धरण के समय को सहेजने और उसकी तुलना करनी चाहिए (देखें IsNewBar).
मूविंग एवरेज संकेतक का वर्तमान मान CopyBuffer() फ़ंक्शन का उपयोग करके अनुरोध किया जाता है और ma[] ऐरे में सहेजा जाता है जिसमें केवल एक मान होता है। इसके बाद प्रोग्राम यह जांचता है कि क्या मूल्य मूविंग एवरेज को पार कर गया है और अतिरिक्त जांच करता है (क्या EA का उपयोग करना संभव है और इतिहास में बार की उपस्थिति)। यदि सफल होती है, तो प्रतीक के लिए एक उपयुक्त स्थिति खोलने के लिए PositionOpen() विधि को कॉल किया जाता है (जो CTrade का एक उदाहरण है)।
स्थिति खोलने की कीमत का सेट करना SymbolInfoDouble() फ़ंक्शन का उपयोग करके किया जाता है जो Bid या Ask मूल्य लौटाता है, जो signal चर के मान पर निर्भर करता है। स्थिति का वॉल्यूम TradeSizeOptimized() फ़ंक्शन द्वारा निर्धारित किया जाता है जिसे ऊपर वर्णित किया गया है।
3.3. CheckForClose() फ़ंक्शन
CheckForClose() स्थिति बंद करने की स्थितियों की जांच करता है और यदि बंद करने के लिए स्थितियाँ बनती हैं तो इसे बंद कर देता है।
//+------------------------------------------------------------------+ //| बंद स्थिति की स्थितियों की जांच करें | //+------------------------------------------------------------------+ void CheckForClose(void) { MqlRates rt[2]; //--- मूल्य मानों की कॉपी करें if(CopyRates(_Symbol,_Period,0,2,rt)!=2) { Print("CopyRates of ",_Symbol," विफल, कोई इतिहास नहीं"); return; } //--- नए बार के पहले टिक पर व्यापार करें if(rt[1].tick_volume>1) return; //--- मूविंग एवरेज संकेतक का वर्तमान मान प्राप्त करें double ma[1]; if(CopyBuffer(ExtHandle,0,0,1,ma)!=1) { Print("CopyBuffer from iMA विफल, कोई डेटा नहीं"); return; } //--- पहले चुनी गई स्थिति के प्रकार को प्राप्त करें bool signal=false; long type=PositionGetInteger(POSITION_TYPE); if(type==(long)POSITION_TYPE_BUY && rt[0].open>ma[0] && rt[0].close<ma[0]) signal=true; if(type==(long)POSITION_TYPE_SELL && rt[0].open<ma[0] && rt[0].close>ma[0]) signal=true; //--- अतिरिक्त जांच if(signal) if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) if(Bars(_Symbol,_Period)>100) { CTrade trade; trade.PositionClose(_Symbol,3); } //--- }
CheckForClose() फ़ंक्शन का एल्गोरिदम CheckForOpen() फ़ंक्शन के एल्गोरिदम के समान है। वर्तमान खुली स्थिति की दिशा के आधार पर, इसके बंद होने की स्थितियों की जांच की जाती है (मूविंग एवरेज को ऊपर से नीचे पार करना खरीदने के लिए या नीचे से ऊपर से बेचना)। एक खुली स्थिति को बंद करने के लिए ट्रेड ऑब्जेक्ट (CTrade का उदाहरण) के PositionClose() विधि को कॉल किया जाता है।
4. बैकटेस्टिंग
सर्वश्रेष्ठ पैरामीटर के मान स्ट्रेटेजी टेस्टर का उपयोग करके प्राप्त किए जा सकते हैं।
उदाहरण के लिए, जब 2012.01.01-2013.08.01 के अंतराल में MovingPeriod पैरामीटर का ऑप्टिमाइजेशन किया जाता है, तो सर्वश्रेष्ठ परिणाम MovingPeriod=45 के साथ प्राप्त होते हैं:

बैकटेस्टिंग परिणाम मूविंग एवरेज एक्सपर्ट एडवाइजर
निष्कर्ष:
मूविंग एवरेज एक्सपर्ट एडवाइजर जो MetaTrader 5 टर्मिनल के स्टैंडर्ड पैक में शामिल है, यह तकनीकी संकेतकों, ट्रेडिंग इतिहास फ़ंक्शंस और ट्रेड क्लासेस के उपयोग का एक उदाहरण है। इसके अलावा, EA में एक मनी मैनेजमेंट सिस्टम शामिल है जो ट्रेड परिणामों पर आधारित है।
संबंधित पोस्ट
- MetaTrader 4 के लिए विज़ुअल ऑर्डर प्रोसेसिंग - आपके ट्रेडिंग साथी
- MQL5 विजार्ड: मॉर्निंग/ईवनिंग स्टार पैटर्न और स्टोकास्टिक पर आधारित ट्रेड सिग्नल
- MQL5 विजार्ड: मॉर्निंग/इविनिंग स्टार और RSI पर आधारित ट्रेड सिग्नल
- MQL5 विजार्ड: दो EMA के क्रॉसओवर पर आधारित ट्रेड सिग्नल और इंट्राडे टाइम फ़िल्टर
- MQL5 विज़ार्ड - हैमर/हैंगिंग मैन और स्टोकास्टिक पर आधारित ट्रेड सिग्नल