extern int TypeOfSignal1 = 8; // Entry signal extern int TypeOfSignal2 = 19; // Confirmation/trend signal extern int TypeOfSignal3 = 21; // Confirmation/trend signal extern int TypeOfSignal4 = 24; // Confirmation/trend signal // TypeOfSignal: // 0 - do NOT use any signal // 8 - RSI crosses 50 // 14 - Confirmation by TrendLord on higher timeframe // 17 - entry via Parabolic SAR(on first dot) // 18 - entry via Fractal // 19 - EMA9 crosses SMA20 // 20 - EMA9, SMA20, SMA100 are aligned on M5, M15, M30, H1, H4 charts // 21 - EMA9 crosses SMA20 or full candle above EMA9 // 22 - entry via Parabolic SAR(on second dot) // 23 - EMA5, EMA9, SMA20 are aligned // 24 - EMA5, EMA9, SMA20 are aligned on M15, H30, H1, H4 charts // Allowed values for TypeOfSignal1 (entry signal): 8,17,18,19,21,22. // Allowed values for TypeOfSignal2 - TypeOfSignal4: 0,14,17,18,19,20,21,22,23,24. extern int OppositeDirection = 0; extern double Lots = 1.0; // Timeframe (in minutes) for second signal (confirmation by TrendLord). // See available values here: http://docs.mql4.com/ru/constants/timeframes extern int TimeFrame2 = 240; extern int StopLoss = 120; extern int TakeProfit = 30; extern int StartHour = 0; extern int EndHour = 24; extern double ParabolicStep = 0.02; extern double ParabolicMaximum = 0.2; // The main problem with cached ticket is: // How to detect, that position was closed by stop-loss? // The answer is: check OrderCloseTime. For closed order it is == 0 int currentOrderTicket; bool usePrevBarTime = false; datetime prevBarTime; bool setTakeProfit; bool setTakeProfitWhenAvailable = true; int sleepTimeAtError = 3000; int StartTrailingStop; int lastOrderTime; int init() { if (StartHour >= EndHour) { Print("StartHour=", StartHour, " >= EndHour=", EndHour, ", expert will not work"); return(-1); } currentOrderTicket = -1; lastOrderTime = -1; StartTrailingStop = TakeProfit; prevBarTime = -1; setTakeProfit = false; if (setTakeProfitWhenAvailable && (StartTrailingStop >= 100)) { setTakeProfit = true; } findLostOrder(); } int getHigherTimeframe(int period) { if (period == PERIOD_M1) { return(PERIOD_M5); } if (period == PERIOD_M5) { return(PERIOD_M15); } if (period == PERIOD_M15) { return(PERIOD_M30); } if (period == PERIOD_M30) { return(PERIOD_H1); } if (period == PERIOD_H1) { return(PERIOD_H4); } if (period == PERIOD_H4) { return(PERIOD_D1); } if (period == PERIOD_D1) { return(PERIOD_W1); } if (period == PERIOD_W1) { return(PERIOD_MN1); } if (period == PERIOD_MN1) { Print("WARNING: no higher period available for monthly timeframe"); return(-2); } Print("WARNING: unknown timeframe: ", period); return(-1); } int getIntTime(datetime time) { string timeStr = TimeToStr(time, TIME_MINUTES); return(StrToInteger(StringSubstr(timeStr, 0, 2)) * 60 + StrToInteger(StringSubstr(timeStr, 3, 2))); } void findLostOrder() { int total = OrdersTotal(); // Check for existing (already opened) order for(int cnt=0; cnt < total; cnt++) { OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES); if(OrderSymbol() != Symbol()) { continue; } // Order already opened currentOrderTicket = OrderTicket(); string type = "buy"; if (OrderType() == OP_SELL) { type = "sell"; } Print("Found open ", type, " position for ", OrderSymbol(), " at init: ticket ", OrderTicket(), ", opened at ", OrderOpenTime(), ", open price ", OrderOpenPrice(), ", ", OrderLots(), " lots, stop-loss at ", OrderStopLoss()); OrderPrint(); // TODO: align date by timeframe lastOrderTime = getIntTime(OrderOpenTime()); break; } } double getClosePrice() { if (OrderType() == OP_BUY) { return(Bid); } if (OrderType() == OP_SELL) { return(Ask); } Print("ERROR: No order is opened now"); return(-1); } int haveEnoughMoney() { if(AccountFreeMargin() < (1000 * Lots)) { Print("We have no money for ", Lots, " lots. Free Margin = ", AccountFreeMargin()); return(0); } return(1); } bool allowToSetStopLoss(double basePrice) { double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point; double delta = MathAbs(basePrice - getClosePrice()); return(delta > stopLevel); } int closePosition(int orderType, string reason) { // Set current available price (Bid or Ask) for close position double priceType; if (OP_BUY == orderType) { priceType = Bid; } else { if (OP_SELL == orderType) { priceType = Ask; } else { return(0); } } // Keep current selected order int prevOrderTicket = OrderTicket(); int total = OrdersTotal(); // Check for existing short(sell) order and close it for(int cnt=0; cnt < total; cnt++) { OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES); // Close all Buy or all Sell orders for current symbol if((OrderType() == orderType) && // check for opened position (OrderSymbol() == Symbol())) // check for symbol { Print("Close position because of ", reason); OrderPrint(); if (!OrderClose(OrderTicket(), OrderLots(), priceType, 1, Green)) { Print("Unable to close order, error ", GetLastError()); } } } OrderSelect(prevOrderTicket, SELECT_BY_TICKET, MODE_TRADES); return(0); } // OrderSend does not allow to specify stop limit and take profit, // so use special method to set them bool setStopLossAndTakeProfit(int ticket, double newStopLoss, double newTakeProfit) { bool set = false; double currentStopLoss = OrderStopLoss(); if (NormalizeDouble(currentStopLoss - newStopLoss, Digits) != 0) { if (allowToSetStopLoss(newStopLoss)) { set = true; currentStopLoss = newStopLoss; } } double currentTakeProfit = OrderTakeProfit(); if (NormalizeDouble(currentTakeProfit - newTakeProfit, Digits) != 0) { if (allowToSetStopLoss(newTakeProfit)) { set = true; currentTakeProfit = newTakeProfit; } } if (! set) { return(false); } Print("OrderModify for ticket ", ticket, " set stopLoss: ", currentStopLoss, ", set takeProfit: ", newTakeProfit); if (OrderModify(ticket, OrderOpenPrice(), currentStopLoss, currentTakeProfit, 0, Green)) { return(true); } Print("Unable to set stopLoss and takeProfit: ", GetLastError()); return(false); } int directionByRsiCrossCenter() { double rsi_1 = iRSI(NULL, 0, 14, PRICE_CLOSE, 1); double rsi_2 = iRSI(NULL, 0, 14, PRICE_CLOSE, 2); if ((rsi_1 > 50) && (rsi_2 < 50)) { return(OP_BUY); } if ((rsi_1 < 50) && (rsi_2 > 50)) { return(OP_SELL); } return(-1); } // Return direction for open order, or -1 int directionByParabolic(int bar) { double parabolic_1 = iSAR(NULL, 0, ParabolicStep, ParabolicMaximum, bar); double parabolic_2 = iSAR(NULL, 0, ParabolicStep, ParabolicMaximum, bar + 1); double median_1 = (Low[bar] + High[bar]) / 2.0; double median_2 = (Low[bar + 1] + High[bar + 1]) / 2.0; if ((parabolic_1 < median_1) && (parabolic_2 > median_2)) { return(OP_BUY); } if ((parabolic_1 > median_1) && (parabolic_2 < median_2)) { return(OP_SELL); } return(-1); } // Return direction for open order, or -1 int directionBySma10() { double ema9_0 = iMA(NULL, 0, 9, 0, MODE_EMA, PRICE_CLOSE, 0); double ema9_1 = iMA(NULL, 0, 9, 0, MODE_EMA, PRICE_CLOSE, 1); double ema20_0 = iMA(NULL, 0, 20, 0, MODE_EMA, PRICE_CLOSE, 0); double ema20_1 = iMA(NULL, 0, 20, 0, MODE_EMA, PRICE_CLOSE, 1); if ((ema9_0 > ema20_0) && (ema9_1 < ema20_1)) { return(OP_BUY); } if ((ema9_0 < ema20_0) && (ema9_1 > ema20_1)) { return(OP_SELL); } return(-1); } bool compareMA(int timeFrame, int mode, int period1, int period2) { double ema1 = iMA(NULL, timeFrame, period1, 0, mode, PRICE_CLOSE, 0); double ema2 = iMA(NULL, timeFrame, period2, 0, mode, PRICE_CLOSE, 0); return(ema1 < ema2); } // Return direction for open order, or -1 int directionBySma10OrFullCandle() { int direction = directionBySma10(); if (direction >= 0) { return(direction); } double ema9_1 = iMA(NULL, 0, 9, 0, MODE_EMA, PRICE_CLOSE, 1); double ema9_2 = iMA(NULL, 0, 9, 0, MODE_EMA, PRICE_CLOSE, 2); if ((Low[1] > ema9_1) && (Low[2] < ema9_2)) { return(OP_BUY); } if ((High[1] < ema9_1) && (High[2] > ema9_2)) { return(OP_SELL); } return(-1); } int confirmBySmaAlignedOnTimeframe(int period, int mode, int period1, int period2, int period3) { if (compareMA(period, mode, period2, period1) && compareMA(period, mode, period3, period2)) { return(OP_BUY); } if (compareMA(period, mode, period1, period2) && compareMA(period, mode, period2, period3)) { return(OP_SELL); } return(-1); } int confirmBySmaAlignedOn3TFs() { if (compareMA(15, MODE_EMA, 20, 9) && compareMA(15, MODE_EMA, 40, 20) && compareMA(30, MODE_EMA, 20, 9) && compareMA(30, MODE_EMA, 40, 20) && compareMA(60, MODE_EMA, 20, 9) && compareMA(60, MODE_EMA, 40, 20)) { return(OP_BUY); } if (compareMA(15, MODE_EMA, 9, 20) && compareMA(15, MODE_EMA, 20, 40) && compareMA(30, MODE_EMA, 9, 20) && compareMA(30, MODE_EMA, 20, 40) && compareMA(60, MODE_EMA, 9, 20) && compareMA(60, MODE_EMA, 20, 40)) { return(OP_SELL); } return(-1); } // Return direction for open order, or -1 int confirmByParabolic() { int direction; for (int i = 1; i < 50; i++) { direction = directionByParabolic(i); if (direction >= 0) { return(direction); } } return(-1); } int directionByFractal(int bar) { double fractal = iFractals(NULL, 0, MODE_UPPER, bar); if (fractal != 0) { return(OP_SELL); } fractal = iFractals(NULL, 0, MODE_LOWER, bar); if (fractal != 0) { return(OP_BUY); } return(-1); } // Return direction for open order, or -1 int confirmByFractal() { int direction; for (int i = 1; i < 50; i++) { direction = directionByFractal(i); if (direction >= 0) { return(direction); } } return(-1); } int directionByTypeOfSignal(int type, int baseDirection) { if (type <= 0) { return(-1); } if (type == 14) { if(iCustom(NULL, TimeFrame2, "TrendLord", 1, 1) > 1000000000) { // Downtrend is set in N1 indicator, uptrend is set in N2 indicator. return(OP_SELL); } return(OP_BUY); } if (type == 17) { return(confirmByParabolic()); } if (type == 18) { return(confirmByFractal()); } if (type == 20) { return(confirmBySmaAlignedOn3TFs()); } if (type == 23) { return(confirmBySmaAlignedOnTimeframe(Period(), MODE_EMA, 5,9,20)); } if (type == 24) { return(confirmBySmaAlignedOnTimeframe(getHigherTimeframe(Period()), MODE_EMA, 5,9,20)); } return(-1); } // Return direction for open order, or -1 int directionByEntryLineIndicator(bool ignoreAllowedDirections) { if (Time[0] <= prevBarTime) { return(-1); } int signalDirection = -1; if (TypeOfSignal1 == 8) { signalDirection = directionByRsiCrossCenter(); } if (TypeOfSignal1 == 17) { signalDirection = directionByParabolic(0); } if (TypeOfSignal1 == 18) { signalDirection = directionByFractal(1); } if (TypeOfSignal1 == 19) { signalDirection = directionBySma10(); } if (TypeOfSignal1 == 21) { signalDirection = directionBySma10OrFullCandle(); } if (TypeOfSignal1 == 22) { signalDirection = directionByParabolic(2); } if (signalDirection < 0) { return(signalDirection); } if (TypeOfSignal2 > 0) { if (directionByTypeOfSignal(TypeOfSignal2, signalDirection) != signalDirection) { return(-1); } } if (TypeOfSignal3 > 0) { if (directionByTypeOfSignal(TypeOfSignal3, signalDirection) != signalDirection) { return(-1); } } if (TypeOfSignal4 > 0) { if (directionByTypeOfSignal(TypeOfSignal4, signalDirection) != signalDirection) { return(-1); } } int direction = signalDirection; if (OppositeDirection > 0) { direction = OP_SELL + OP_BUY - direction; } if (signalDirection == OP_BUY) { return(direction); } if (signalDirection == OP_SELL) { return(direction); } return(-1); } // Return price of stop-loss double getStopLoss(double basePrice, int orderDirection) { if (OP_BUY == orderDirection) { return(NormalizeDouble(basePrice - StopLoss * Point, Digits)); } if (OP_SELL == orderDirection) { return(NormalizeDouble(basePrice + StopLoss * Point, Digits)); } Print("Invalid order direction at getStopLoss: ", orderDirection); // Return incorrect value here return(-1); } double getTakeProfit() { if (OrderType() == OP_BUY) { // long(buy) position is opened return(NormalizeDouble(OrderOpenPrice() + StartTrailingStop * Point, Digits)); } if (OrderType() == OP_SELL) { // short(sell) position is opened return(NormalizeDouble(OrderOpenPrice() - StartTrailingStop * Point, Digits)); } Print("Invalid order direction at getTakeProfit: ", OrderType()); // Return incorrect value here return(-1); } // Return 1, if order was correctly opened // Return -1, if error was occured at open order // Return 0 otherwise int openOrder() { if ((Hour() < StartHour) || (Hour() >= EndHour)) { return(false); } // Can we open order? Should we Buy or Sell? int orderDirection = directionByEntryLineIndicator(false); if (orderDirection < 0) { return(0); } // Do NOT allow to open order twice per bar int barTime = getIntTime(Time[0]); if (lastOrderTime == barTime) { return(0); } // Ok, lets enter into position // Close opposite position first double entryPrice; string orderDirectionName; if (OP_BUY == orderDirection) { closePosition(OP_SELL, "reverse signal"); orderDirectionName = "Buy"; entryPrice = Ask; } else { closePosition(OP_BUY, "reverse signal"); orderDirectionName = "Sell"; entryPrice = Bid; } // Ensure we have enough money to enter the position if (! haveEnoughMoney()) { Print("Not enough money to open position"); return(0); } Print("Open ", orderDirectionName, " position, use ", Lots, " lots, entryPrice: ", entryPrice); // Send command to broker to open order currentOrderTicket = OrderSend(Symbol(), orderDirection, Lots, entryPrice, 3, 0, 0, "", 16384, 0, Green); if (currentOrderTicket <= 0) { Print("Error opening ", orderDirectionName, " order : ", GetLastError()); Sleep(sleepTimeAtError); return(-1); } if (! OrderSelect(currentOrderTicket,SELECT_BY_TICKET,MODE_TRADES)) { Print("Could not open ", orderDirectionName, " order"); currentOrderTicket = -1; Sleep(sleepTimeAtError); return(-1); } Print(orderDirectionName, " order opened : ",OrderOpenPrice()); OrderPrint(); lastOrderTime = barTime; // Set stop-loss and take-profit for opened order double stopLoss = getStopLoss(OrderOpenPrice(), orderDirection); double takeProfit = 0; if (setTakeProfit) { takeProfit = getTakeProfit(); } setStopLossAndTakeProfit(currentOrderTicket, stopLoss, takeProfit); return(1); } bool closeOrder(double baseClosePrice) { double closePrice = baseClosePrice; double price = getClosePrice(); if (OrderType() == OP_SELL) { // short(sell) position is opened if ((baseClosePrice < 0.000001) || (baseClosePrice > price)) { closePrice = price; } } else { if ((baseClosePrice < 0.000001) || (baseClosePrice < price)) { closePrice = price; } } if (!OrderClose(OrderTicket(), OrderLots(), closePrice, 0, Green)) { Print("Error at close order: ", GetLastError()); } currentOrderTicket = -1; return(true); } // Return true if order was closed. // Return false otherwise. bool tryToCloseOrderByTakeProfit() { bool close = false; double price = getClosePrice(); double takeProfit = getTakeProfit(); if (OrderType() == OP_BUY) { if (price > takeProfit) { close = true; } } if (OrderType() == OP_SELL) { if (price < takeProfit) { close = true; } } if (close) { return(closeOrder(takeProfit)); } return(false); } // Return true if order was closed. // Return false otherwise. bool tryToCloseOrder() { if (currentOrderTicket < 0) { return(false); } // it is important to enter the market correctly, // but it is more important to exit it correctly... OrderSelect(currentOrderTicket, SELECT_BY_TICKET, MODE_TRADES); if (OrderStopLoss() < 0.000001) { // No stop-loss is set, try to exit manually double price = getClosePrice(); double stopLoss = getStopLoss(OrderOpenPrice(), OrderType()); bool close = false; if ((OrderType() == OP_BUY) && (price <= stopLoss)) { close = true; } if ((OrderType() == OP_SELL) && (price >= stopLoss)) { close = true; } if (close) { return(closeOrder(price)); } } if (OrderTakeProfit() < 0.000001) { return(tryToCloseOrderByTakeProfit()); } // Check signal to opposite direction int orderDirection = directionByEntryLineIndicator(false); if (orderDirection < 0) { return(false); } if (orderDirection != OrderType()) { return(closeOrder(price)); } return(false); } int start() { if (StartHour >= EndHour) { return(0); } if (prevBarTime >= Time[0]) { if (currentOrderTicket < 0) { // If we have no active orders, then wait until begin of new bar. return(0); } //if (setTakeProfit) { // If we already set take profit, then we do not need // to do anything until order will be closed. // So wait until start of next bar. // return(0); //} } // initial data checks // it is important to make sure that the expert works with a normal // chart and the user did not make any mistakes setting external // variables (Lots, StopLoss, TakeProfit, // TrailingStop) in our case, we check TakeProfit // on a chart of less than 10 bars if (Bars < 10) { Print("bars less than 10"); return(0); } OrderSelect(currentOrderTicket, SELECT_BY_TICKET, MODE_TRADES); if (OrderCloseTime() != 0) { currentOrderTicket = -1; } if (currentOrderTicket >= 0) { // We have open order, check stop-loss and take-profit if (tryToCloseOrder()) { currentOrderTicket = -1; } } // Try to open new order, if we have no orders now if (prevBarTime < Time[0]) { if (currentOrderTicket < 0) { // If any error occured, than run the expert at next tick. // Otherwise run the expert at next bar. if (openOrder() >= 0) { if (usePrevBarTime) { prevBarTime = Time[0]; } } } else { // If order already exists at first tick of bar, // then do no checks during this bar. if (usePrevBarTime) { prevBarTime = Time[0]; } } } if (currentOrderTicket >= 0) { // Check stop-loss double stopLoss = getStopLoss(OrderOpenPrice(), OrderType()); if ((OrderStopLoss() <= 0.000001) || (OrderTakeProfit() <= 0.000001)) { setStopLossAndTakeProfit(currentOrderTicket, stopLoss, getTakeProfit()); } } return(0); } // the end.