//+------------------------------------------------------------------+ //| Strategy: Moving average + Stochastic.mq4 | //| Created with EABuilder.com | //| https://www.eabuilder.com | //+------------------------------------------------------------------+ #property copyright "Created with EABuilder.com" #property link "https://www.eabuilder.com" #property version "1.00" #property description "" #include #include extern double SL_Points = 20; extern double TP_Points = 60; extern double Trail_Points = 10; extern double Trail_Step = 40; extern int _K_period = 5; extern int _D_period = 5; extern int Slowing = 3; extern int MA = 400; int LotDigits; //initialized in OnInit extern int MagicNumber = 730545; extern int MinTradeDurationBars = 1; //minimum trade duration extern double MM_Martingale_Start = 0.01; extern double MM_Martingale_ProfitFactor = 1; extern double MM_Martingale_LossFactor = 2; extern bool MM_Martingale_RestartProfit = true; extern bool MM_Martingale_RestartLoss = false; extern int MM_Martingale_RestartLosses = 1000; extern int MM_Martingale_RestartProfits = 1000; extern int MaxSlippage = 3; //adjusted in OnInit extern bool TradeMonday = true; extern bool TradeTuesday = true; extern bool TradeWednesday = true; extern bool TradeThursday = true; extern bool TradeFriday = true; extern bool TradeSaturday = true; extern bool TradeSunday = true; extern double PriceTooClose = 3; bool crossed[2]; //initialized to true, used in function Cross extern int MaxOpenTrades = 1; int MaxLongTrades = 1000; int MaxShortTrades = 1000; int MaxPendingOrders = 1000; int MaxLongPendingOrders = 1000; int MaxShortPendingOrders = 1000; extern bool Hedging = true; int OrderRetry = 5; //# of retries if sending order returns error int OrderWait = 5; //# of seconds to wait if sending order returns error double myPoint; //initialized in OnInit double MM_Size() //martingale / anti-martingale { double lots = MM_Martingale_Start; double MaxLot = MarketInfo(Symbol(), MODE_MAXLOT); double MinLot = MarketInfo(Symbol(), MODE_MINLOT); if(SelectLastHistoryTrade()) { double orderprofit = OrderProfit(); double orderlots = OrderLots(); double boprofit = BOProfit(OrderTicket()); if(orderprofit + boprofit > 0 && !MM_Martingale_RestartProfit) lots = orderlots * MM_Martingale_ProfitFactor; else if(orderprofit + boprofit < 0 && !MM_Martingale_RestartLoss) lots = orderlots * MM_Martingale_LossFactor; else if(orderprofit + boprofit == 0) lots = orderlots; } if(ConsecutivePL(false, MM_Martingale_RestartLosses)) lots = MM_Martingale_Start; if(ConsecutivePL(true, MM_Martingale_RestartProfits)) lots = MM_Martingale_Start; if(lots > MaxLot) lots = MaxLot; if(lots < MinLot) lots = MinLot; return(lots); } bool TradeDayOfWeek() { int day = DayOfWeek(); return((TradeMonday && day == 1) || (TradeTuesday && day == 2) || (TradeWednesday && day == 3) || (TradeThursday && day == 4) || (TradeFriday && day == 5) || (TradeSaturday && day == 6) || (TradeSunday && day == 0)); } bool Cross(int i, bool condition) //returns true if "condition" is true and was false in the previous call { bool ret = condition && !crossed[i]; crossed[i] = condition; return(ret); } void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | Moving average + Stochastic @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } } int TradesCount(int type) //returns # of open trades for order type, current symbol and magic number { int result = 0; int total = OrdersTotal(); for(int i = 0; i < total; i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) continue; if(OrderMagicNumber() != MagicNumber || OrderSymbol() != Symbol() || OrderType() != type) continue; result++; } return(result); } bool SelectLastHistoryTrade() { int lastOrder = -1; int total = OrdersHistoryTotal(); for(int i = total-1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue; if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) { lastOrder = i; break; } } return(lastOrder >= 0); } double BOProfit(int ticket) //Binary Options profit { int total = OrdersHistoryTotal(); for(int i = total-1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue; if(StringSubstr(OrderComment(), 0, 2) == "BO" && StringFind(OrderComment(), "#"+IntegerToString(ticket)+" ") >= 0) return OrderProfit(); } return 0; } bool ConsecutivePL(bool profits, int n) { int count = 0; int total = OrdersHistoryTotal(); for(int i = total-1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue; if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) { double orderprofit = OrderProfit(); double boprofit = BOProfit(OrderTicket()); if((!profits && orderprofit + boprofit >= 0) || (profits && orderprofit + boprofit <= 0)) break; count++; } } return(count >= n); } int myOrderSend(int type, double price, double volume, string ordername) //send order, return ticket ("price" is irrelevant for market orders) { if(!IsTradeAllowed()) return(-1); int ticket = -1; int retries = 0; int err = 0; int long_trades = TradesCount(OP_BUY); int short_trades = TradesCount(OP_SELL); int long_pending = TradesCount(OP_BUYLIMIT) + TradesCount(OP_BUYSTOP); int short_pending = TradesCount(OP_SELLLIMIT) + TradesCount(OP_SELLSTOP); string ordername_ = ordername; if(ordername != "") ordername_ = "("+ordername+")"; //test Hedging if(!Hedging && ((type % 2 == 0 && short_trades + short_pending > 0) || (type % 2 == 1 && long_trades + long_pending > 0))) { myAlert("print", "Order"+ordername_+" not sent, hedging not allowed"); return(-1); } //test maximum trades if((type % 2 == 0 && long_trades >= MaxLongTrades) || (type % 2 == 1 && short_trades >= MaxShortTrades) || (long_trades + short_trades >= MaxOpenTrades) || (type > 1 && type % 2 == 0 && long_pending >= MaxLongPendingOrders) || (type > 1 && type % 2 == 1 && short_pending >= MaxShortPendingOrders) || (type > 1 && long_pending + short_pending >= MaxPendingOrders) ) { myAlert("print", "Order"+ordername_+" not sent, maximum reached"); return(-1); } //prepare to send order while(IsTradeContextBusy()) Sleep(100); RefreshRates(); if(type == OP_BUY) price = Ask; else if(type == OP_SELL) price = Bid; else if(price < 0) //invalid price for pending order { myAlert("order", "Order"+ordername_+" not sent, invalid price for pending order"); return(-1); } int clr = (type % 2 == 1) ? clrRed : clrBlue; //adjust price for pending order if it is too close to the market price double MinDistance = PriceTooClose * myPoint; if(type == OP_BUYLIMIT && Ask - price < MinDistance) price = Ask - MinDistance; else if(type == OP_BUYSTOP && price - Ask < MinDistance) price = Ask + MinDistance; else if(type == OP_SELLLIMIT && price - Bid < MinDistance) price = Bid + MinDistance; else if(type == OP_SELLSTOP && Bid - price < MinDistance) price = Bid - MinDistance; while(ticket < 0 && retries < OrderRetry+1) { ticket = OrderSend(Symbol(), type, NormalizeDouble(volume, LotDigits), NormalizeDouble(price, Digits()), MaxSlippage, 0, 0, ordername, MagicNumber, 0, clr); if(ticket < 0) { err = GetLastError(); myAlert("print", "OrderSend"+ordername_+" error #"+IntegerToString(err)+" "+ErrorDescription(err)); Sleep(OrderWait*1000); } retries++; } if(ticket < 0) { myAlert("error", "OrderSend"+ordername_+" failed "+IntegerToString(OrderRetry+1)+" times; error #"+IntegerToString(err)+" "+ErrorDescription(err)); return(-1); } string typestr[6] = {"Buy", "Sell", "Buy Limit", "Sell Limit", "Buy Stop", "Sell Stop"}; myAlert("order", "Order sent"+ordername_+": "+typestr[type]+" "+Symbol()+" Magic #"+IntegerToString(MagicNumber)); return(ticket); } int myOrderModify(int ticket, double SL, double TP) //modify SL and TP (absolute price), zero targets do not modify { if(!IsTradeAllowed()) return(-1); bool success = false; int retries = 0; int err = 0; SL = NormalizeDouble(SL, Digits()); TP = NormalizeDouble(TP, Digits()); if(SL < 0) SL = 0; if(TP < 0) TP = 0; //prepare to select order while(IsTradeContextBusy()) Sleep(100); if(!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) { err = GetLastError(); myAlert("error", "OrderSelect failed; error #"+IntegerToString(err)+" "+ErrorDescription(err)); return(-1); } //prepare to modify order while(IsTradeContextBusy()) Sleep(100); RefreshRates(); //adjust targets for market order if too close to the market price double MinDistance = PriceTooClose * myPoint; if(OrderType() == OP_BUY) { if(NormalizeDouble(SL, Digits()) != 0 && Ask - SL < MinDistance) SL = Ask - MinDistance; if(NormalizeDouble(TP, Digits()) != 0 && TP - Ask < MinDistance) TP = Ask + MinDistance; } else if(OrderType() == OP_SELL) { if(NormalizeDouble(SL, Digits()) != 0 && SL - Bid < MinDistance) SL = Bid + MinDistance; if(NormalizeDouble(TP, Digits()) != 0 && Bid - TP < MinDistance) TP = Bid - MinDistance; } if(CompareDoubles(SL, 0)) SL = OrderStopLoss(); //not to modify if(CompareDoubles(TP, 0)) TP = OrderTakeProfit(); //not to modify if(CompareDoubles(SL, OrderStopLoss()) && CompareDoubles(TP, OrderTakeProfit())) return(0); //nothing to do while(!success && retries < OrderRetry+1) { success = OrderModify(ticket, NormalizeDouble(OrderOpenPrice(), Digits()), NormalizeDouble(SL, Digits()), NormalizeDouble(TP, Digits()), OrderExpiration(), CLR_NONE); if(!success) { err = GetLastError(); myAlert("print", "OrderModify error #"+IntegerToString(err)+" "+ErrorDescription(err)); Sleep(OrderWait*1000); } retries++; } if(!success) { myAlert("error", "OrderModify failed "+IntegerToString(OrderRetry+1)+" times; error #"+IntegerToString(err)+" "+ErrorDescription(err)); return(-1); } string alertstr = "Order modified: ticket="+IntegerToString(ticket); if(!CompareDoubles(SL, 0)) alertstr = alertstr+" SL="+DoubleToString(SL); if(!CompareDoubles(TP, 0)) alertstr = alertstr+" TP="+DoubleToString(TP); myAlert("modify", alertstr); return(0); } int myOrderModifyRel(int ticket, double SL, double TP) //modify SL and TP (relative to open price), zero targets do not modify { if(!IsTradeAllowed()) return(-1); bool success = false; int retries = 0; int err = 0; SL = NormalizeDouble(SL, Digits()); TP = NormalizeDouble(TP, Digits()); if(SL < 0) SL = 0; if(TP < 0) TP = 0; //prepare to select order while(IsTradeContextBusy()) Sleep(100); if(!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) { err = GetLastError(); myAlert("error", "OrderSelect failed; error #"+IntegerToString(err)+" "+ErrorDescription(err)); return(-1); } //prepare to modify order while(IsTradeContextBusy()) Sleep(100); RefreshRates(); //convert relative to absolute if(OrderType() % 2 == 0) //buy { if(NormalizeDouble(SL, Digits()) != 0) SL = OrderOpenPrice() - SL; if(NormalizeDouble(TP, Digits()) != 0) TP = OrderOpenPrice() + TP; } else //sell { if(NormalizeDouble(SL, Digits()) != 0) SL = OrderOpenPrice() + SL; if(NormalizeDouble(TP, Digits()) != 0) TP = OrderOpenPrice() - TP; } //adjust targets for market order if too close to the market price double MinDistance = PriceTooClose * myPoint; if(OrderType() == OP_BUY) { if(NormalizeDouble(SL, Digits()) != 0 && Ask - SL < MinDistance) SL = Ask - MinDistance; if(NormalizeDouble(TP, Digits()) != 0 && TP - Ask < MinDistance) TP = Ask + MinDistance; } else if(OrderType() == OP_SELL) { if(NormalizeDouble(SL, Digits()) != 0 && SL - Bid < MinDistance) SL = Bid + MinDistance; if(NormalizeDouble(TP, Digits()) != 0 && Bid - TP < MinDistance) TP = Bid - MinDistance; } if(CompareDoubles(SL, 0)) SL = OrderStopLoss(); //not to modify if(CompareDoubles(TP, 0)) TP = OrderTakeProfit(); //not to modify if(CompareDoubles(SL, OrderStopLoss()) && CompareDoubles(TP, OrderTakeProfit())) return(0); //nothing to do while(!success && retries < OrderRetry+1) { success = OrderModify(ticket, NormalizeDouble(OrderOpenPrice(), Digits()), NormalizeDouble(SL, Digits()), NormalizeDouble(TP, Digits()), OrderExpiration(), CLR_NONE); if(!success) { err = GetLastError(); myAlert("print", "OrderModify error #"+IntegerToString(err)+" "+ErrorDescription(err)); Sleep(OrderWait*1000); } retries++; } if(!success) { myAlert("error", "OrderModify failed "+IntegerToString(OrderRetry+1)+" times; error #"+IntegerToString(err)+" "+ErrorDescription(err)); return(-1); } string alertstr = "Order modified: ticket="+IntegerToString(ticket); if(!CompareDoubles(SL, 0)) alertstr = alertstr+" SL="+DoubleToString(SL); if(!CompareDoubles(TP, 0)) alertstr = alertstr+" TP="+DoubleToString(TP); myAlert("modify", alertstr); return(0); } void TrailingStopTrail(int type, double TS, double step, bool aboveBE, double aboveBEval) //set Stop Loss to "TS" if price is going your way with "step" { int total = OrdersTotal(); TS = NormalizeDouble(TS, Digits()); step = NormalizeDouble(step, Digits()); for(int i = total-1; i >= 0; i--) { while(IsTradeContextBusy()) Sleep(100); if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderMagicNumber() != MagicNumber || OrderSymbol() != Symbol() || OrderType() != type) continue; RefreshRates(); if(type == OP_BUY && (!aboveBE || Bid > OrderOpenPrice() + TS + aboveBEval) && (NormalizeDouble(OrderStopLoss(), Digits()) <= 0 || Bid > OrderStopLoss() + TS + step)) myOrderModify(OrderTicket(), Bid - TS, 0); else if(type == OP_SELL && (!aboveBE || Ask < OrderOpenPrice() - TS - aboveBEval) && (NormalizeDouble(OrderStopLoss(), Digits()) <= 0 || Ask < OrderStopLoss() - TS - step)) myOrderModify(OrderTicket(), Ask + TS, 0); } } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; MaxSlippage *= 10; } //initialize LotDigits double LotStep = MarketInfo(Symbol(), MODE_LOTSTEP); if(NormalizeDouble(LotStep, 3) == round(LotStep)) LotDigits = 0; else if(NormalizeDouble(10*LotStep, 3) == round(10*LotStep)) LotDigits = 1; else if(NormalizeDouble(100*LotStep, 3) == round(100*LotStep)) LotDigits = 2; else LotDigits = 3; int i; //initialize crossed for (i = 0; i < ArraySize(crossed); i++) crossed[i] = true; return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { int ticket = -1; double price; double SL; double TP; TrailingStopTrail(OP_BUY, Trail_Points * myPoint, Trail_Step * myPoint, false, 0); //Trailing Stop = trail TrailingStopTrail(OP_SELL, Trail_Points * myPoint, Trail_Step * myPoint, false, 0); //Trailing Stop = trail //Open Buy Order, instant signal is tested first RefreshRates(); if(Cross(0, iStochastic(NULL, PERIOD_CURRENT, _K_period, _D_period, Slowing, MODE_SMA, 0, MODE_SIGNAL, 0) < iStochastic(NULL, PERIOD_CURRENT, _K_period, _D_period, Slowing, MODE_SMA, 0, MODE_MAIN, 0)) //Stochastic Oscillator crosses below Stochastic Oscillator && iMA(NULL, PERIOD_CURRENT, MA, 0, MODE_EMA, PRICE_CLOSE, 0) < Bid //Moving Average < Price && iStochastic(NULL, PERIOD_CURRENT, _K_period, _D_period, Slowing, MODE_SMA, 0, MODE_MAIN, 0) <= 20 //Stochastic Oscillator <= fixed value ) { RefreshRates(); price = Ask; SL = SL_Points * myPoint; //Stop Loss = value in points (relative to price) TP = TP_Points * myPoint; //Take Profit = value in points (relative to price) if(!TradeDayOfWeek()) return; //open trades only on specific days of the week if(IsTradeAllowed()) { ticket = myOrderSend(OP_BUY, price, MM_Size(), ""); if(ticket <= 0) return; } else //not autotrading => only send alert myAlert("order", ""); myOrderModifyRel(ticket, SL, 0); myOrderModifyRel(ticket, 0, TP); } //Open Sell Order, instant signal is tested first RefreshRates(); if(Cross(1, iStochastic(NULL, PERIOD_CURRENT, _K_period, _D_period, Slowing, MODE_SMA, 0, MODE_SIGNAL, 0) > iStochastic(NULL, PERIOD_CURRENT, _K_period, _D_period, Slowing, MODE_SMA, 0, MODE_MAIN, 0)) //Stochastic Oscillator crosses above Stochastic Oscillator && iMA(NULL, PERIOD_CURRENT, MA, 0, MODE_EMA, PRICE_CLOSE, 0) > Bid //Moving Average > Price && iStochastic(NULL, PERIOD_CURRENT, _K_period, _D_period, Slowing, MODE_SMA, 0, MODE_MAIN, 0) >= 80 //Stochastic Oscillator >= fixed value ) { RefreshRates(); price = Bid; SL = SL_Points * myPoint; //Stop Loss = value in points (relative to price) TP = TP_Points * myPoint; //Take Profit = value in points (relative to price) if(!TradeDayOfWeek()) return; //open trades only on specific days of the week if(IsTradeAllowed()) { ticket = myOrderSend(OP_SELL, price, MM_Size(), ""); if(ticket <= 0) return; } else //not autotrading => only send alert myAlert("order", ""); myOrderModifyRel(ticket, SL, 0); myOrderModifyRel(ticket, 0, TP); } } //+------------------------------------------------------------------+