MetaTrader5
Lazy Bot MT5: EA Sederhana untuk Trading Harian di MetaTrader 5
Selamat datang di blog saya! Kali ini kita akan membahas tentang Lazy Bot MT5, sebuah EA atau sistem trading yang dirancang untuk melakukan trading harian di MetaTrader 5. Mari kita lihat lebih dalam mengenai parameter dan cara kerjanya!
1. Parameter Input
EASettings: "---------------------------------------------"
InpMagicNumber: 123456 // Nomor unik untuk EA
InpBotName: "LazyBot_V1" // Nama Bot
Inpuser_lot: 0.01 // Ukuran lot yang digunakan
Inpuser_SL: 5.0 // Stoploss dalam Pips
InpAddPrice_pip: 0 // Jarak dari High/Low ke harga order dalam Pips
Inpuser_SLippage: 3 // Slippage maksimum yang diizinkan
InpMax_spread: 0 // Spread maksimum yang diizinkan (0 = floating)
isTradingTime: true // Mengizinkan waktu trading
InpStartHour: 7 // Jam mulai trading
InpEndHour: 22 // Jam akhir trading
isVolume_Percent: false // Mengizinkan Volume Persentase
InpRisk: 1 // Persentase risiko dari saldo (%)
2. Inisialisasi Variabel Lokal
datetime last;
int totalBars;
int Pips2Points; // slippage 3 pips
double Pips2Double; // Stoploss 15 pips
double slippage;
double acSpread;
string strComment = "";
CPositionInfo m_position; // objek posisi trading
CTrade m_trade; // objek trading
CSymbolInfo m_symbol; // objek informasi simbol
CAccountInfo m_account; // pembungkus informasi akun
COrderInfo m_order; // objek order tertunda
3. Kode Utama
EA ini akan menghapus semua order lama setiap hari dan mencari nilai tertinggi dan terendah dari bar harian sebelumnya. Kemudian, EA akan mengirimkan dua order tertunda, yaitu BUY_STOP dan SELL_STOP tanpa TakeProfit.
a. Fungsi Inisialisasi EA
int OnInit() {
// Deteksi digit 3 atau 5
if(_Digits % 2 == 1) {
Pips2Double = _Point * 10;
Pips2Points = 10;
slippage = 10 * Inpuser_SLippage;
} else {
Pips2Double = _Point;
Pips2Points = 1;
slippage = Inpuser_SLippage;
}
if (!m_symbol.Name(Symbol())) return(INIT_FAILED);
RefreshRates();
m_trade.SetExpertMagicNumber(InpMagicNumber);
m_trade.SetMarginMode();
m_trade.SetTypeFillingBySymbol(m_symbol.Name());
m_trade.SetDeviationInPoints(slippage);
return(INIT_SUCCEEDED);
}
b. Fungsi Tick EA
void OnTick() {
if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) == false) {
Comment("LazyBot\nTrading tidak diizinkan.");
return;
}
MqlDateTime timeLocal;
MqlDateTime timeServer;
TimeLocal(timeLocal);
TimeCurrent(timeServer);
if(timeServer.day_of_week == 0 || timeServer.day_of_week == 6) return;
int hourLocal = timeLocal.hour;
int hourCurrent = timeServer.hour;
acSpread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
strComment = "\nJam Lokal = " + hourLocal;
strComment += "\nJam Saat Ini = " + hourCurrent;
strComment += "\nSpread = " + (string)acSpread;
strComment += "\nTotal Bars = " + (string)totalBars;
Comment(strComment);
TrailingSL();
if(last != iTime(m_symbol.Name(), PERIOD_D1, 0)) {
if(isTradingTime) {
if(hourCurrent >= InpStartHour) {
DeleteOldOrds();
OpenOrder();
last = iTime(m_symbol.Name(), PERIOD_D1, 0);
}
} else {
DeleteOldOrds();
OpenOrder();
last = iTime(m_symbol.Name(), PERIOD_D1, 0);
}
}
}
3.1 Menghitung Sinyal dan Mengirim Order
void OpenOrder() {
double TP_Buy = 0, TP_Sell = 0;
double SL_Buy = 0, SL_Sell = 0;
if(InpMax_spread != 0) {
if(acSpread > InpMax_spread) {
Print(__FUNCTION__, " > Spread saat ini lebih besar dari yang diizinkan!");
return;
}
}
double Bar1High = m_symbol.NormalizePrice(iHigh(m_symbol.Name(), PERIOD_D1, 1));
double Bar1Low = m_symbol.NormalizePrice(iLow(m_symbol.Name(), PERIOD_D1, 1));
double lot1 = CalculateVolume();
double OpenPrice = m_symbol.NormalizePrice(Bar1High + InpAddPrice_pip * Pips2Double);
SL_Buy = m_symbol.NormalizePrice(OpenPrice - Inpuser_SL * Pips2Double);
totalBars = iBars(m_symbol.Name(), PERIOD_D1);
string comment = InpBotName + ";" + m_symbol.Name() + ";" + totalBars;
if(CheckVolumeValue(lot1) && CheckOrderForFREEZE_LEVEL(ORDER_TYPE_BUY_STOP, OpenPrice) && CheckMoneyForTrade(m_symbol.Name(), lot1, ORDER_TYPE_BUY) && CheckStopLoss(OpenPrice, SL_Buy)) {
if(!m_trade.BuyStop(lot1, OpenPrice, m_symbol.Name(), SL_Buy, TP_Buy, ORDER_TIME_GTC, 0, comment)) {
Print(__FUNCTION__, "--> Error Buy");
}
}
OpenPrice = m_symbol.NormalizePrice(Bar1Low - InpAddPrice_pip * Pips2Double);
SL_Sell = m_symbol.NormalizePrice(OpenPrice + Inpuser_SL * Pips2Double);
if(CheckVolumeValue(lot1) && CheckOrderForFREEZE_LEVEL(ORDER_TYPE_SELL_STOP, OpenPrice) && CheckMoneyForTrade(m_symbol.Name(), lot1, ORDER_TYPE_SELL) && CheckStopLoss(OpenPrice, SL_Sell)) {
if(!m_trade.SellStop(lot1, OpenPrice, m_symbol.Name(), SL_Sell, TP_Sell, ORDER_TIME_GTC, 0, comment)) {
Print(__FUNCTION__, "--> Error Sell");
}
}
}
3.2 Menghapus Semua Order Lama
void DeleteOldOrds() {
string sep=";";
ushort u_sep;
string result[];
for(int i = OrdersTotal() - 1; i >= 0; i--) {
if(m_order.SelectByIndex(i)) {
u_sep = StringGetCharacter(sep, 0);
string Ordcomment = m_order.Comment();
int k = StringSplit(Ordcomment, u_sep, result);
if(k > 2) {
string sym = m_symbol.Name();
if((m_order.Magic() == InpMagicNumber) && (sym == result[1])) {
m_trade.OrderDelete(m_order.Ticket());
}
}
}
}
}
3.3 Fungsi Trailing StopLoss
void TrailingSL() {
double SL_in_Pip = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--) {
if(m_position.SelectByIndex(i)) {
if((m_position.Magic() == InpMagicNumber) && (m_position.Symbol() == m_symbol.Name())) {
double order_stoploss1 = m_position.StopLoss();
if(m_position.PositionType() == POSITION_TYPE_BUY) {
SL_in_Pip = NormalizeDouble((Bid - order_stoploss1), _Digits) / Pips2Double;
if(SL_in_Pip > Inpuser_SL) {
order_stoploss1 = NormalizeDouble(Bid - (Inpuser_SL * Pips2Double), _Digits);
m_trade.PositionModify(m_position.Ticket(), order_stoploss1, m_position.TakeProfit());
}
}
if(m_position.PositionType() == POSITION_TYPE_SELL) {
SL_in_Pip = NormalizeDouble((m_position.StopLoss() - Ask), _Digits) / Pips2Double;
if(SL_in_Pip > Inpuser_SL) {
order_stoploss1 = NormalizeDouble(Ask + (Inpuser_SL * Pips2Double), _Digits);
m_trade.PositionModify(m_position.Ticket(), order_stoploss1, m_position.TakeProfit());
}
}
}
}
}
3.4 Memeriksa Nilai Volume
bool CheckVolumeValue(double volume) {
double min_volume = m_symbol.LotsMin();
double max_volume = m_symbol.LotsMax();
double volume_step = m_symbol.LotsStep();
if(volume < min_volume || volume > max_volume) {
return(false);
}
int ratio = (int)MathRound(volume/volume_step);
if(MathAbs(ratio * volume_step - volume) > 0.0000001) {
return(false);
}
return(true);
}
3.5 Memeriksa FreeLevel
bool CheckOrderForFREEZE_LEVEL(ENUM_ORDER_TYPE type, double price) {
int freeze_level = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL);
bool check = false;
switch(type) {
case ORDER_TYPE_BUY_STOP:
check = ((price - Ask) > freeze_level * _Point);
return(check);
case ORDER_TYPE_SELL_STOP:
check = ((Bid - price) > freeze_level * _Point);
return(check);
}
return false;
}
3.6 Memeriksa Uang untuk Trading
bool CheckMoneyForTrade(string symb, double lots, ENUM_ORDER_TYPE type) {
MqlTick mqltick;
SymbolInfoTick(symb,mqltick);
double price = mqltick.ask;
if(type == ORDER_TYPE_SELL) price = mqltick.bid;
double margin, free_margin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
if(!OrderCalcMargin(type,symb,lots,price,margin)) {
Print("Error in ",__FUNCTION__," code=",GetLastError());
return(false);
}
if(margin > free_margin) {
Print("Not enough money for ", EnumToString(type)," ", lots," ", symb," Error code=",GetLastError());
return(false);
}
return(true);
}
3.7 Memeriksa Stoploss
bool CheckStopLoss(double price, double SL) {
int stops_level = (int)SymbolInfoInteger(m_symbol.Name(), SYMBOL_TRADE_STOPS_LEVEL);
if(stops_level != 0) {
PrintFormat("SYMBOL_TRADE_STOPS_LEVEL=%d: StopLoss dan TakeProfit tidak boleh lebih dekat dari %d poin dari harga penutupan", stops_level, stops_level);
}
bool SL_check = false;
return SL_check = MathAbs(price - SL) > (stops_level * m_symbol.Point());
}
Jangan lupa untuk menonton video tutorial MQL4 dan MQL5 berikut untuk memperdalam pemahaman Anda tentang EA ini:
Video MQL4
Video MQL5
2022.12.14