EA Moving Average adalah salah satu alat yang terdapat dalam paket standard terminal MetaTrader 5. Ia merupakan contoh EA yang menggunakan indikator Moving Average untuk melakukan perdagangan.
Fail EA Moving Average.mq5 boleh ditemukan dalam folder "terminal_data_folder\MQL5\Experts\Examples\Moving Average". EA ini memberi contoh penggunaan indikator teknikal, fungsi sejarah perdagangan, dan kelas perdagangan dari Standard Library. Selain itu, EA ini juga dilengkapi dengan sistem pengurusan wang yang berasaskan keputusan perdagangan.
Jom kita lihat struktur Expert Advisor ini dan cara ia berfungsi.
1. Ciri-ciri EA
//+------------------------------------------------------------------+ //| Moving Averages.mq5 | //| Hakcipta 2009-2013, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Hakcipta 2009-2013, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00"
Baris pertama 5 mengandungi ulasan, manakala tiga baris berikutnya menetapkan ciri-ciri program MQL5 (hakcipta, pautan, versi) menggunakan arahan preprocessor #property.
Apabila anda menjalankan Expert Advisor ini, maklumat tersebut akan dipaparkan dalam tab "Common":

Gambar 1. Parameter Umum EA Moving Average
1.2. Fail Terkait
Seterusnya, arahan #include memberitahu pengkompil untuk memasukkan fail "Trade.mqh".
Fail ini adalah sebahagian daripada Standard Library dan mengandungi kelas CTrade untuk akses mudah kepada fungsi perdagangan.
#include <Trade\Trade.mqh>Nama fail yang dimasukkan ditunjukkan dalam tanda kurung "<>;", jadi laluan ditetapkan relatif kepada direktori: "terminal_data_folder\Include".
1.3 Input
Seterusnya adalah jenis, nama, nilai lalai, dan ulasan. Peranan mereka ditunjukkan dalam Gambar 2.
input double MaximumRisk = 0.02; // Risiko Maksimum dalam peratus input double DecreaseFactor = 3; // Faktor pengurangan input int MovingPeriod = 12; // Tempoh Moving Average input int MovingShift = 6; // Shift Moving Average
Parameter MaximumRisk dan DecreaseFactor akan digunakan untuk pengurusan wang, MovingPeriod dan MovingShift menetapkan tempoh dan shift indikator Moving Average yang akan digunakan untuk memeriksa syarat perdagangan.
Text dalam ulasan pada baris parameter input, bersama dengan nilai lalai, akan dipaparkan dalam tab "Options" sebagai ganti nama parameter input:

Gambar 2. Parameter Input EA Moving Average
1.4. Pembolehubah Global
Seterusnya, pembolehubah global ExtHandle dinyatakan. Ia akan digunakan untuk menyimpan pemegang indikator Moving Average.
//--- int ExtHandle=0;
Ia diikuti oleh 6 fungsi. Tujuan setiap fungsi diterangkan dalam ulasan sebelum badan fungsi:
- TradeSizeOptimized() - Mengira saiz lot yang optimum;
- CheckForOpen() - Memeriksa syarat kedudukan terbuka;
- CheckForClose() - Memeriksa syarat untuk menutup kedudukan;
- OnInit() - Fungsi inisialisasi Expert;
- OnTick() - Fungsi tick Expert;
- OnDeinit() - Fungsi deinisialisasi Expert;
Tiga fungsi terakhir adalah fungsi pengendalian acara; tiga fungsi servis pertama dipanggil dalam kod mereka.
2. Fungsi Pengendalian Acara
2.1. Fungsi Inisialisasi OnInit()
Fungsi OnInit() dipanggil sekali semasa permulaan pertama Expert Advisor. Biasanya dalam pengendali acara OnInit(), EA disediakan untuk beroperasi: parameter input diperiksa, indikator dan parameter diinisialisasi, dan lain-lain. Dalam kes ralat kritikal, apabila kerja lebih lanjut tidak bermakna, fungsi akan keluar dengan kod pulangan INIT_FAILED.
//+------------------------------------------------------------------+ //| Fungsi inisialisasi Expert | //+------------------------------------------------------------------+ int OnInit(void) { //--- ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE); if(ExtHandle==INVALID_HANDLE) { printf("Ralat mencipta indikator MA"); return(INIT_FAILED); } //--- return(INIT_SUCCEEDED); }
Oleh kerana perdagangan EA berasaskan indikator Moving Average, dengan memanggil iMA(), indikator Moving Average dicipta dan pemegangnya disimpan dalam pembolehubah global ExtHandle.
Jika berlaku ralat, OnInit() akan keluar dengan kod pulangan INIT_FAILED - ini adalah cara yang betul untuk menyelesaikan operasi EA/indikator dalam kes inisialisasi yang tidak berjaya.
2.2. Fungsi OnTick()
Fungsi OnTick() dipanggil setiap kali kutipan baru diterima untuk simbol yang dipaparkan dalam carta yang digunakan oleh EA.
//+------------------------------------------------------------------+ //| Fungsi tick Expert | //+------------------------------------------------------------------+ void OnTick(void) { //--- if(PositionSelect(_Symbol)) CheckForClose(); else CheckForOpen(); //--- }
Fungsi PositionSelect() digunakan untuk menentukan sama ada terdapat kedudukan terbuka untuk simbol semasa.
Jika terdapat kedudukan terbuka, fungsi CheckForClose() akan dipanggil untuk menganalisis keadaan pasaran semasa dan menutup kedudukan terbuka, sebaliknya fungsi CheckForOpen() akan dipanggil untuk memeriksa syarat kemasukan pasaran dan membuka kedudukan baru jika syarat tersebut berlaku.
2.3. Fungsi OnDeInit()
OnDeInit() dipanggil apabila EA dialih keluar dari carta. Jika program meletakkan objek grafik semasa operasi, ia boleh dialih keluar dari carta.
//+------------------------------------------------------------------+ //| Fungsi deinisialisasi Expert | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+
Dalam kes ini, tiada tindakan yang dilakukan semasa deinisialisasi Expert Advisor.
3. Fungsi Servis
3.1. Fungsi TradeSizeOptimized()
Fungsi ini mengira dan mengembalikan nilai saiz lot yang optimum untuk pembukaan kedudukan dengan tahap risiko tertentu dan keputusan perdagangan.
//+------------------------------------------------------------------+ //| Mengira saiz lot yang optimum | //+------------------------------------------------------------------+ double TradeSizeOptimized(void) { double price=0.0; double margin=0.0; //--- Mengira saiz lot 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); //--- mengira panjang siri dagangan yang kalah berturut-turut if(DecreaseFactor>0) { //--- meminta seluruh sejarah perdagangan HistorySelect(0,TimeCurrent()); //-- int orders=HistoryDealsTotal(); // jumlah urusniaga int losses=0 // bilangan urusniaga yang kalah dalam siri for(int i=orders-1;i>=0;i--) { ulong ticket=HistoryDealGetTicket(i); if(ticket==0) { Print("HistoryDealGetTicket gagal, tiada sejarah perdagangan"); break; } //--- memeriksa simbol urusniaga if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol) continue; //--- memeriksa keuntungan 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); } //--- menormalkan dan memeriksa nilai yang dibenarkan bagi jumlah perdagangan 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; //--- mengembalikan nilai volum perdagangan return(lot); }
Fungsi SymbolInfoDouble() digunakan untuk memeriksa ketersediaan harga untuk simbol semasa, seterusnya fungsi OrderCalcMargin() digunakan untuk meminta margin yang diperlukan untuk meletakkan pesanan (dalam kes ini, pesanan beli). Saiz lot awal ditentukan dari nilai margin yang diperlukan untuk meletakkan pesanan, margin bebas akaun (AccountInfoDouble(ACCOUNT_FREEMARGIN)) dan nilai maksimum risiko yang dibenarkan yang ditentukan dalam parameter input MaximumRisk.
Jika nilai parameter input DecreaseFactor adalah positif, urusniaga dalam sejarah dianalisis dan saiz lot diselaraskan berdasarkan maklumat tentang siri maksimum urusniaga yang kalah: saiz lot awal didarabkan dengan saiz (1-losses/DecreaseFactor).
Seterusnya, volum perdagangan dibundarkan kepada nilai yang merupakan kelipatan daripada langkah volum minimum (stepvol) untuk simbol semasa. Juga, nilai minimum (minvol) dan maksimum (maxvol) volum perdagangan diminta, dan jika nilai lot melepasi had yang dibenarkan, ia diselaraskan. Akhirnya, fungsi mengembalikan nilai volum perdagangan yang dikira.
3.2. Fungsi CheckForOpen()
CheckForOpen() digunakan untuk memeriksa syarat pembukaan kedudukan dan membukanya apabila syarat perdagangan berlaku (dalam kes ini, apabila harga melintasi moving average).
//+------------------------------------------------------------------+ //| Semak syarat untuk membuka kedudukan | //+------------------------------------------------------------------+ void CheckForOpen(void) { MqlRates rt[2]; //--- salin nilai harga if(CopyRates(_Symbol,_Period,0,2,rt)!=2) { Print("CopyRates of ",_Symbol," gagal, tiada sejarah"); return; } //--- Dagangan hanya pada tick pertama bar baru if(rt[1].tick_volume>1) return; //--- Dapatkan nilai semasa indikator Moving Average double ma[1]; if(CopyBuffer(ExtHandle,0,0,1,ma)!=1) { Print("CopyBuffer from iMA gagal, tiada data"); return; } //--- semak isyarat ENUM_ORDER_TYPE signal=WRONG_VALUE; if(rt[0].open>ma[0] && rt[0].close<ma[0]) signal=ORDER_TYPE_SELL // syarat jual else { if(rt[0].open<ma[0] && rt[0].close>ma[0]) signal=ORDER_TYPE_BUY // syarat beli } //--- pemeriksaan tambahan 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); } //--- }
Apabila berdagang menggunakan moving average, anda perlu memeriksa sama ada harga melintasi moving average. Menggunakan fungsi CopyRates(), dua nilai harga semasa disalin dalam array struktur rt[], rt[1] sepadan dengan bar semasa, rt[0] - bar yang telah siap.
Baru bermula dengan memeriksa volum tick bar semasa, jika ia sama dengan 1, maka bar baru telah bermula. Perlu diperhatikan bahawa kaedah untuk mengesan bar baru ini mungkin gagal dalam beberapa kes (apabila kutipan datang dalam kelompok), jadi fakta bermulanya pembentukan bar baru harus dilakukan dengan menyimpan dan membandingkan masa kutipan semasa (lihat IsNewBar).
Nilai semasa indikator Moving Average diminta menggunakan fungsi CopyBuffer() dan disimpan dalam array ma[] yang hanya mengandungi satu nilai. Program kemudian memeriksa sama ada harga telah melintasi moving average dan melakukan pemeriksaan tambahan (jika perdagangan menggunakan EA adalah mungkin dan kehadiran bar dalam sejarah). Jika berjaya, posisi yang sesuai untuk simbol dibuka dengan memanggil PositionOpen() kaedah objek perdagangan (instans CTrade).
Harga pembukaan posisi ditetapkan menggunakan fungsi SymbolInfoDouble() yang mengembalikan harga Bid atau Ask bergantung pada nilai pembolehubah signal. Volum posisi ditentukan dengan memanggil TradeSizeOptimized() yang diterangkan di atas.
3.3. Fungsi CheckForClose()
CheckForClose() memeriksa syarat untuk menutup posisi dan menutupnya jika syarat untuk menutupnya berlaku.
//+------------------------------------------------------------------+ //| Semak syarat menutup kedudukan | //+------------------------------------------------------------------+ void CheckForClose(void) { MqlRates rt[2]; //--- Salin nilai harga if(CopyRates(_Symbol,_Period,0,2,rt)!=2) { Print("CopyRates of ",_Symbol," gagal, tiada sejarah"); return; } //--- Dagangan hanya pada tick pertama bar baru if(rt[1].tick_volume>1) return; //--- dapatkan nilai semasa indikator Moving Average double ma[1]; if(CopyBuffer(ExtHandle,0,0,1,ma)!=1) { Print("CopyBuffer from iMA gagal, tiada data"); return; } //--- dapatkan jenis kedudukan yang dipilih sebelumnya menggunakan PositionSelect() 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; //--- pemeriksaan tambahan if(signal) if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) if(Bars(_Symbol,_Period)>100) { CTrade trade; trade.PositionClose(_Symbol,3); } //--- }
Algoritma fungsi CheckForClose() adalah serupa dengan algoritma CheckForOpen(). Bergantung pada arah posisi terbuka semasa, syarat untuk penutupannya diperiksa (harga melintasi MA ke bawah untuk beli atau ke atas untuk jual). Posisi terbuka ditutup dengan memanggil PositionClose() kaedah objek perdagangan (instans CTrade).
4. Ujian Kembali
Nilai parameter terbaik boleh dijumpai menggunakan Strategy Tester terminal MetaTrader 5.
Contohnya, apabila mengoptimumkan parameter MovingPeriod dalam interval 2012.01.01-2013.08.01, keputusan terbaik diperoleh dengan MovingPeriod=45:

Keputusan Ujian Kembali EA Moving Average
Kesimpulan:
Expert Advisor Moving Average yang disertakan dalam paket standard terminal MetaTrader 5 adalah contoh penggunaan indikator teknikal, fungsi sejarah perdagangan, dan kelas perdagangan dari Standard Library. Selain itu, EA ini juga dilengkapi dengan sistem pengurusan wang yang berasaskan keputusan perdagangan.
Siaran berkaitan
- MQL5 Wizard: Cipta Sistem Trading Berdasarkan Pola Morning/Evening Star dan RSI
- Panduan Lengkap MQL5 Wizard untuk Isyarat Dagangan Berdasarkan Morning/Evening Stars dan Stochastic
- MQL5 Wizard: Isyarat Dagangan Berdasarkan Pola Candlestick Dark Cloud Cover/Piercing Line + RSI
- MQL5 Wizard: Cipta Isyarat Dagangan Berdasarkan Corak Hammer/Hanging Man dan Stochastic
- MQL5 Wizard: Cipta Isyarat Dagangan Berdasarkan Corak 'Dark Cloud Cover' dan 'Piercing Line' dengan CCI