- Input parameters
//Import External class #include <TradePositionInfo.mqh> #include <TradeTrade.mqh> #include <TradeSymbolInfo.mqh> #include <TradeAccountInfo.mqh> #include <TradeOrderInfo.mqh> //--- introduce predefined variables for code readability #define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK) #define Bid SymbolInfoDouble(_Symbol, SYMBOL_BID) //--- input parameters input string EASettings = "---------------------------------------------"; //-------- <EA Settings> -------- input int InpMagicNumber = 123456; //Magic Number input string InpBotName = "LazyBot_V1"; //Bot Name input string TradingSettings = "---------------------------------------------"; //-------- <Trading Settings> -------- input double Inpuser_lot = 0.01; //Lots input double Inpuser_SL = 5.0; //Stoploss (in Pips) input double InpAddPrice_pip = 0; //Dist from [H], [L] to OP_Price (in Pips) input int Inpuser_SLippage = 3; // Maximum slippage allow_Pips. input double InpMax_spread = 0; //Maximum allowed spread (in Pips) (0 = floating) input string TimeSettings = "---------------------------------------------"; //-------- <Trading Time Settings> -------- input bool isTradingTime = true; //Allow trading time input int InpStartHour = 7; //Start Hour input int InpEndHour = 22; //End Hour input string MoneyManagementSettings = "---------------------------------------------"; //-------- <Money Settings> -------- input bool isVolume_Percent = false; //Allow Volume Percent input double InpRisk = 1; //Risk Percentage of Balance (%)
2. local variables initialization
//Local parameters datetime last; int totalBars; int Pips2Points; // slippage 3 pips 3=points 30=points double Pips2Double; // Stoploss 15 pips 0.015 0.0150 double slippage; double acSpread; string strComment = ""; CPositionInfo m_position; // trade position object CTrade m_trade; // trading object CSymbolInfo m_symbol; // symbol info object CAccountInfo m_account; // account info wrapper COrderInfo m_order; // pending orders object
3. Main Code
Explaining the Strategy, Everyday Bot will delete All the old Orders and find Highest and Lowest value of the previous daily Bar and Send to two Pending orders “BUY_STOP“, “SELL_STOP“. (No TakeProfit).
a/ Expert initialization function
int OnInit() { //--- //3 or 5 digits detection //Pip and point 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())) // sets symbol name 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/ Expert tick function
void OnTick() { if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) == false) { Comment("LazyBotnTrade not allowed."); return; } //Get trading time, // Opening section // London 14h - 23h GMT VietNam // Newyork 19h - 04h GMT VietNam MqlDateTime timeLocal; MqlDateTime timeServer; TimeLocal(timeLocal); TimeCurrent(timeServer); // do not work on holidays. if(timeServer.day_of_week == 0 || timeServer.day_of_week == 6) return; int hourLocal = timeLocal.hour;//TimeHour(TimeLocal()); int hourCurrent = timeServer.hour;//TimeHour(TimeCurrent()); acSpread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); strComment = "nLocal Hour is = " + hourLocal; strComment += "nCurrent Hour is = " + hourCurrent; strComment += "nSpread is = " + (string)acSpread; strComment += "nTotal Bars is = " + (string)totalBars; Comment(strComment); //Check Trailing TrailingSL(); //--- if(last != iTime(m_symbol.Name(), PERIOD_D1, 0))// && hourCurrent > InpStartHour) { //Check Trading time if(isTradingTime) { if(hourCurrent >= InpStartHour) // && hourCurrent < InpEndHour){ { DeleteOldOrds(); //Send Order BUY_STOP va SELL_STOP OpenOrder(); last = iTime(m_symbol.Name(), PERIOD_D1, 0); } } else { DeleteOldOrds(); //Send Order BUY_STOP va SELL_STOP OpenOrder(); last = iTime(m_symbol.Name(), PERIOD_D1, 0); } } }
3.1 Calculate signal and send orders
//+------------------------------------------------------------------+ //| CALCULATE SIGNAL AND SEND ORDER | //+------------------------------------------------------------------+ void OpenOrder() { double TP_Buy = 0, TP_Sell = 0; double SL_Buy = 0, SL_Sell = 0; //Check Maximum Spread if(InpMax_spread != 0){ if(acSpread > InpMax_spread){ Print(__FUNCTION__," > current Spread is greater than user Spread!..."); 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)); //Calculate Lots double lot1 = CalculateVolume(); double OpenPrice = m_symbol.NormalizePrice(Bar1High + InpAddPrice_pip * Pips2Double);// + NormalizeDouble((acSpread/Pips2Points) * Pips2Double, Digits); //For BUY_STOP -------------------------------- TP_Buy = 0;//Bar1High + NormalizeDouble(min_sl* Pips2Double, Digits); 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))// use "ORDER_TIME_GTC" when expiration date = 0 Print(__FUNCTION__, "--> Buy Error"); } //For SELL_STOP -------------------------------- OpenPrice = m_symbol.NormalizePrice(Bar1Low - InpAddPrice_pip * Pips2Double);// - NormalizeDouble((acSpread/Pips2Points) * Pips2Double, Digits); TP_Sell = 0;//Bar1Low - NormalizeDouble(min_sl* Pips2Double, Digits); 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__, "--> Sell Error"); } }
3.2 New day, delete all old orders
//+------------------------------------------------------------------+ //| Delele Old Orders | //+------------------------------------------------------------------+ void DeleteOldOrds() { string sep=";"; // A separator as a character ushort u_sep; // The code of the separator character string result[]; // An array to get strings for(int i = OrdersTotal() - 1; i >= 0; i--) // returns the number of current orders { if(m_order.SelectByIndex(i)) // selects the pending order by index for further access to its properties { //--- Get the separator code u_sep = StringGetCharacter(sep, 0); string Ordcomment = m_order.Comment(); //Split OrderComment (EAName;Symbol;totalBar) to get Ordersymbol 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 EA has function “trailing StopLoss”, SL will change every time price change and make profit increase
//+------------------------------------------------------------------+ //| TRAILING STOPLOSS | //+------------------------------------------------------------------+ void TrailingSL() { double SL_in_Pip = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { if(m_position.SelectByIndex(i)) // selects the orders by index for further access to its properties { if((m_position.Magic() == InpMagicNumber) && (m_position.Symbol() == m_symbol.Name())) //m_symbol.Name() { double order_stoploss1 = m_position.StopLoss(); // For Buy oder if(m_position.PositionType() == POSITION_TYPE_BUY) { //--Calculate SL when price changed SL_in_Pip = NormalizeDouble((Bid - order_stoploss1), _Digits) / Pips2Double; //Print(__FUNCTION__, "Modify Order Buy " + (string)SL_in_Pip); 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()); } } //For Sell Order if(m_position.PositionType() == POSITION_TYPE_SELL) { //--Calculate SL when price changed 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 Check Volume value
//+------------------------------------------------------------------+ //| Check the correctness of the order volume | //+------------------------------------------------------------------+ bool CheckVolumeValue(double volume) { //--- minimal allowed volume for trade operations double min_volume = m_symbol.LotsMin(); //--- maximal allowed volume of trade operations double max_volume = m_symbol.LotsMax(); //--- get minimal step of volume changing 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 Check FreeLevel
//+------------------------------------------------------------------+ //| CHECK FREEZE LEVEL | //+------------------------------------------------------------------+ bool CheckOrderForFREEZE_LEVEL(ENUM_ORDER_TYPE type, double price)//change name of this function { int freeze_level = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL); bool check = false; //--- check only two order types switch(type) { //--- Buy operation case ORDER_TYPE_BUY_STOP: { //--- check the distance from the opening price to the activation price check = ((price-Ask) > freeze_level*_Point); //--- return the result of checking return(check); } //--- Sell operation case ORDER_TYPE_SELL_STOP: { //--- check the distance from the opening price to the activation price check = ((Bid-price)>freeze_level*_Point); //--- return the result of checking return(check); } break; } //--- a slightly different function is required for pending orders return false; }
3.6 Check Money for trade
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CheckMoneyForTrade(string symb,double lots,ENUM_ORDER_TYPE type) { //--- Getting the opening price MqlTick mqltick; SymbolInfoTick(symb,mqltick); double price=mqltick.ask; if(type==ORDER_TYPE_SELL) price=mqltick.bid; //--- values of the required and free margin double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE); //--- call of the checking function if(!OrderCalcMargin(type,symb,lots,price,margin)) { //--- something went wrong, report and return false Print("Error in ",__FUNCTION__," code=",GetLastError()); return(false); } //--- if there are insufficient funds to perform the operation if(margin>free_margin) { //--- report the error and return false Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError()); return(false); } //--- checking successful return(true); }
3.7 Check Stoploss
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CheckStopLoss(double price, double SL) { //--- get the SYMBOL_TRADE_STOPS_LEVEL level int stops_level = (int)SymbolInfoInteger(m_symbol.Name(), SYMBOL_TRADE_STOPS_LEVEL); if(stops_level != 0) { PrintFormat("SYMBOL_TRADE_STOPS_LEVEL=%d: StopLoss and TakeProfit must"+ " not be nearer than %d points from the closing price", stops_level, stops_level); } //--- bool SL_check=false; //--- check the StopLoss return SL_check = MathAbs(price - SL) > (stops_level * m_symbol.Point()); }
Video MQL4:
Video MQL5: