//+-------------------------------------------------------------------+ //| Ben's Stochastic EMA auto trading robot by Steve Hopwood.mq4 | //| Copyright © 2009, Steve Hopwood | //| http://www.hopwood3.freeserve.co.uk | //+-------------------------------------------------------------------+ #property copyright "Copyright © 2009, Steve Hopwood" #property link "http://www.hopwood3.freeserve.co.uk" #include #include #define NL "\n" #define up "Up" #define down "Down" #define none "None" #define both "Both" //Hidden sl and tp lines. If UseStealth enabled, the bot will close trades on a touch/break of these lines. //Each line is named with its appropriate prefix and the ticket number of the relevant trade #define TpPrefix "Tp" #define SlPrefix "Sl" /* Matt Kennel has provided the code for bool O_R_CheckForHistory(int ticket). Cheers Matt, You are a star. Code for adding debugging Sleep Alert("G"); int x = 0; while (x == 0) Sleep(100); Code for returning a value as pips. The example returns the range of the previous candle int PipDivisor = 1; if (Digits == 3 || Digits == 5) PipDivisor = 10; double CandleRange = ((High[1] - Low[1]) / Point) / PipDivisor; Standard order loop code for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (!OrderSelect(cc, SELECT_BY_POS) ) continue; if (OrderSymbol() != Symbol() ) continue; if (OrderMagicNumber() != MagicNumber) continue; }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--) FUNCTIONS LIST int init() int start() ----Trading---- void LookForTradingOpportunities() bool IsTradingAllowed() bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take) void ModifyOrder(int ticket, double stop, double take) bool DoesTradeExist() void CountOpenTrades() bool CloseTrade(int ticket) void LookForTradeClosure() bool CheckTradingTimes() void CloseAllTrades() ----Hidden sl/tp---- Doubles up for pending trades-based ea's void DrawPendingPriceLines() void DeletePendingPriceLines() void ReplaceMissingSlTpLines() ----Balance/swap filters module---- void TradeDirectionBySwap() bool IsThisPairTradable() bool BalancedPair(int type) ----Matt's Order Reliable library code bool O_R_CheckForHistory(int ticket) Cheers Matt, You are a star. void O_R_Sleep(double mean_time, double max_time) ----Indicator readings---- void ReadIndicatorValues() double GetAa(int tf, int price, int period, int mashift, int method, int buffer, int shift) double GetStochastic(int shift) ----Trade management module---- void TradeManagementModule() void BreakEvenStopLoss() void JumpingStopLoss() void HiddenTakeProfit() void HiddenStopLoss() void TrailingStopLoss() */ extern string gen="----General inputs----"; extern double Lot=0.01; extern bool StopTrading=false; extern bool TradeLong=true; extern bool TradeShort=true; extern int TakeProfit=20; extern int StopLoss=40; extern int MagicNumber=0; extern string TradeComment=""; extern bool CriminalIsECN=false; extern double MaxSpread=120; extern string sto="----Stochastic----"; extern int StochOverSold=20; extern int StochOverBought=80; extern int StochCloseBuffer=5; extern int K = 14; extern int D = 5; extern int Slowing=2; extern string pf="0=Low/High; 1=Close/Close"; extern int PriceField=0; extern string mam="0=Simple: 1=Exp: 2=Smooth: 3=Linear"; extern int MaMethod=0; extern string mode="0=Main; 1=Signal"; extern int Mode=0; extern string aal="----All averages inputs----"; extern bool UseAA=true; extern int TimeFrame = 0; extern int Price = 0; extern int MA_Period = 50; extern int MA_Shift = 0; extern int MA_Method = 1; extern int CandleShift = 0; //Hidden tp/sl inputs. extern string hts="----Stealth stop loss and take profit inputs----"; extern int HiddenPips=0;//Added to the 'hard' sl and tp and used for closure calculations extern string bf="----Trading balance filters----"; extern bool UseZeljko=true; extern bool OnlyTradeCurrencyTwice=true; extern string amc="----Available Margin checks----"; extern string sco="Scoobs"; extern bool UseScoobsMarginCheck=false; extern string fk="ForexKiwi"; extern bool UseForexKiwi=true; extern int FkMinimumMarginPercent=1500; extern string tt="----Trading hours----"; extern string Trade_Hours= "Set Morning & Evening Hours"; extern string Trade_Hoursi= "Use 24 hour, local time clock"; extern string Trade_Hours_M= "Morning Hours 0-12"; extern int start_hourm = 0; extern int end_hourm = 12; extern string Trade_Hours_E= "Evening Hours 12-24"; extern int start_houre = 12; extern int end_houre = 24; extern string spt="----Specific time inputs----"; extern double StartTime=12.15; extern string pts="----Swap filter----"; extern bool CadPairsPositiveOnly=true; extern bool AudPairsPositiveOnly=true; extern bool NzdPairsPositiveOnly=true; extern string tmm="----Trade management module----"; //Breakeven has to be enabled for JS and TS to work. extern string BE="Break even settings"; extern bool BreakEven=false; extern int BreakEvenPips=10; extern int BreakEvenProfit=5; extern string cts="----Candlestick trailing stop----"; extern bool UseCandlestickTrailingStop=false; extern string JSL="Jumping stop loss settings"; extern bool JumpingStop=false; extern int JumpingStopPips=10; extern string TSL="Trailing stop loss settings"; extern bool TrailingStop=false; extern int TrailingStopPips=20; extern string mis="----Odds and ends----"; extern bool ShowManagementAlerts=true; extern int DisplayGapSize=30; //Matt's O-R stuff int O_R_Setting_max_retries = 10; double O_R_Setting_sleep_time = 4.0; /* seconds */ double O_R_Setting_sleep_max = 15.0; /* seconds */ //Trading variables int TicketNo, OpenTrades; bool CanTradeThisPair;//Will be false when this pair fails the currency can only trade twice filter, or the balanced trade filter bool BuyOpen, SellOpen; int RetryCount = 10;//Will make this number of attempts to get around the trade context busy error. //All Averages double AaVal, AaUp, AaDown;//Buffers 0 (val) 1 (up) and 3 (down) string trend; //Sotchastic double StochVal, PrevStochVal; //Pending price inputs. Keeps things hidden from the crims bool PendingBuy, PendingSell; double PendingPrice, PendingStop, PendingTake; datetime PendingTime; double PendingCandleRange; double PendingRecreationCancelPips = 2; //Hidden stops variables double HiddenStopLoss, HiddenTakeProfit; //Margin status display bool EnoughMargin; string MarginMessage; //Misc string Gap, ScreenMessage; int OldBars; int OldCstBars;//For candlestick ts string PipDescription=" pips"; bool ForceTradeClosure; void DisplayUserFeedback() { if (IsTesting() && !IsVisualMode()) return; ScreenMessage = ""; ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL); ScreenMessage = StringConcatenate(ScreenMessage, Gap, TimeToStr(TimeLocal(), TIME_DATE|TIME_MINUTES|TIME_SECONDS), NL ); /* //Code for time to bar-end display from Candle Time by Nick Bilak double i; int m,s,k; m=Time[0]+Period()*60-CurTime(); i=m/60.0; s=m%60; m=(m-m%60)/60; ScreenMessage = StringConcatenate(ScreenMessage,Gap, m + " minutes " + s + " seconds left to bar end", NL); */ ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL); ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Lot size: ", Lot, " (Criminal's minimum lot size: ", MarketInfo(Symbol(), MODE_MINLOT), ")", NL); ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Take profit: ", TakeProfit, PipDescription, NL); ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Stop loss: ", StopLoss, PipDescription, NL); ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Magic number: ", MagicNumber, NL); ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trade comment: ", TradeComment, NL); if (CriminalIsECN) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "CriminalIsECN = true", NL); else ScreenMessage = StringConcatenate(ScreenMessage,Gap, "CriminalIsECN = false", NL); ScreenMessage = StringConcatenate(ScreenMessage,Gap, "MaxSpread = ", MaxSpread, ": Spread = ", MarketInfo(Symbol(), MODE_SPREAD), NL, NL ); ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trading hours", NL); if (start_hourm == 0 && end_hourm == 12 && start_houre && end_houre == 24) ScreenMessage = StringConcatenate(ScreenMessage,Gap, " 24H trading", NL); else { ScreenMessage = StringConcatenate(ScreenMessage,Gap, " start_hourm: ", DoubleToStr(start_hourm, 2), ": end_hourm: ", DoubleToStr(end_hourm, 2), NL); ScreenMessage = StringConcatenate(ScreenMessage,Gap, " start_houre: ", DoubleToStr(start_houre, 2), ": end_houre: ", DoubleToStr(end_houre, 2), NL); }//else ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL); ScreenMessage = StringConcatenate(ScreenMessage,Gap, "AA value ", AaVal, ": Trend is ", trend, NL); ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Current Stochastic: ", StochVal, NL); ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Previous Stochastic: ", PrevStochVal, NL); ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL); if (BreakEven) { ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Breakeven is set to ", BreakEvenPips, PipDescription); ScreenMessage = StringConcatenate(ScreenMessage,": BreakEvenProfit = ", BreakEvenProfit, PipDescription); ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL); }//if (BreakEven) if (UseCandlestickTrailingStop) { ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Using candlestick trailing stop", NL); }//if (UseCandlestickTrailingStop) if (JumpingStop) { ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Jumping stop is set to ", JumpingStopPips, PipDescription); ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL); }//if (JumpingStop) if (TrailingStop) { ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trailing stop is set to ", TrailingStopPips, PipDescription); ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL); }//if (TrailingStop) //ScreenMessage = StringConcatenate(ScreenMessage,Gap, "BB Upper line: ", DoubleToStr(BbUpper, Digits), NL); //ScreenMessage = StringConcatenate(ScreenMessage,Gap, "BB Middle line: ", DoubleToStr(BbMiddle, Digits), NL); //ScreenMessage = StringConcatenate(ScreenMessage,Gap, "BB Lower line: ", DoubleToStr(BbLower, Digits), NL); //ScreenMessage = StringConcatenate(ScreenMessage,Gap, "BB Lower line: ", DoubleToStr(BbLower, Digits), NL); if (MarginMessage != "") ScreenMessage = StringConcatenate(ScreenMessage,NL, Gap, MarginMessage, NL); Comment(ScreenMessage); }//void DisplayUserFeedback() //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- //Adapt to x digit criminals int multiplier; if(Digits == 2 || Digits == 4) multiplier = 1; if(Digits == 3 || Digits == 5) multiplier = 10; if(Digits == 6) multiplier = 100; if(Digits == 7) multiplier = 1000; if (multiplier > 1) PipDescription = " points"; TakeProfit*= multiplier; StopLoss*= multiplier; HiddenPips*= multiplier; BreakEvenPips*= multiplier; BreakEvenProfit*= multiplier; JumpingStopPips*= multiplier; TrailingStopPips*= multiplier; Gap=""; if (DisplayGapSize >0) { for (int cc=0; cc< DisplayGapSize; cc++) { Gap = StringConcatenate(Gap, " "); } }//if (DisplayGapSize >0) //Reset CriminIsECN if crim is IBFX and the punter does not know or, like me, keeps on forgetting string name = TerminalCompany(); int ispart = StringFind(name, "IBFX", 0); if (ispart < 0) ispart = StringFind(name, "Interbank FX", 0); if (ispart > -1) CriminalIsECN = true; if (TradeComment == "") TradeComment = " "; ReadIndicatorValues();//For initial display in case user has turned of constant re-display DisplayUserFeedback(); //Call sq's show trades indi //iCustom(NULL, 0, "SQ_showTrades",Magic, 0,0); //---- return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- Comment(""); //---- return(0); } //////////////////////////////////////////////////////////////////////////////////////////////// //TRADE MANAGEMENT MODULE void BreakEvenStopLoss() // Move stop loss to breakeven { double NewStop; bool result; string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0); double sl = ObjectGet(LineName, OBJPROP_PRICE1); if (OrderType()==OP_BUY) { if (sl >= OrderOpenPrice() ) return; if (Bid >= OrderOpenPrice () + (Point*BreakEvenPips)) { //Calculate the new stop NewStop = NormalizeDouble(OrderOpenPrice()+(BreakEvenProfit*Point), Digits); if (ObjectFind(LineName) == -1) { ObjectCreate(LineName, OBJ_HLINE, 0, TimeCurrent(), 0); ObjectSet(LineName, OBJPROP_COLOR, Red); ObjectSet(LineName, OBJPROP_WIDTH, 1); ObjectSet(LineName, OBJPROP_STYLE, STYLE_DOT); }//if (ObjectFind(LineName == -1) ) ObjectMove(LineName, 0, TimeCurrent(), NewStop); }//if (Bid >= OrderOpenPrice () + (Point*BreakEvenPips) && }//if (OrderType()==OP_BUY) if (OrderType()==OP_SELL) { if (sl <= OrderOpenPrice() && sl > 0) return; if (Ask <= OrderOpenPrice() - (Point*BreakEvenPips)) { //Calculate the new stop NewStop = NormalizeDouble(OrderOpenPrice()-(BreakEvenProfit*Point), Digits); if (ObjectFind(LineName) == -1) { ObjectCreate(LineName, OBJ_HLINE, 0, TimeCurrent(), 0); ObjectSet(LineName, OBJPROP_COLOR, Red); ObjectSet(LineName, OBJPROP_WIDTH, 1); ObjectSet(LineName, OBJPROP_STYLE, STYLE_DOT); }//if (ObjectFind(LineName == -1) ) ObjectMove(LineName, 0, Time[0], NewStop); }//if (Ask <= OrderOpenPrice() - (Point*BreakEvenPips) && (OrderStopLoss()>OrderOpenPrice()|| OrderStopLoss()==0)) }//if (OrderType()==OP_SELL) } // End BreakevenStopLoss sub void JumpingStopLoss() { // Jump sl by pips and at intervals chosen by user . if (OrderProfit() < 0) return;//Nothing to do string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0); double sl = ObjectGet(LineName, OBJPROP_PRICE1); if (sl == 0) return;//No line, so nothing to do double NewStop; if (OrderType()==OP_BUY) { if (sl < OrderOpenPrice() ) return;//Not at breakeven yet // Increment sl by sl + JumpingStopPips. // This will happen when market price >= (sl + JumpingStopPips) if (Bid>= sl + ((JumpingStopPips*2)*Point) ) { NewStop = NormalizeDouble(sl + (JumpingStopPips * Point), Digits); ObjectMove(LineName, 0, Time[0], NewStop); }// if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice()) }//if (OrderType()==OP_BUY) if (OrderType()==OP_SELL) { if (sl > OrderOpenPrice() ) return;//Not at breakeven yet // Decrement sl by sl - JumpingStopPips. // This will happen when market price <= (sl - JumpingStopPips) if (Bid<= sl - ((JumpingStopPips*2)*Point)) { NewStop = NormalizeDouble(sl - (JumpingStopPips * Point), Digits); ObjectMove(LineName, 0, Time[0], NewStop); }// close if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice()) }//if (OrderType()==OP_SELL) } //End of JumpingStopLoss sub void TrailingStopLoss() { if (OrderProfit() < 0) return;//Nothing to do string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0); double sl = ObjectGet(LineName, OBJPROP_PRICE1); if (sl == 0) return;//No line, so nothing to do double NewStop; if (OrderType()==OP_BUY) { if (sl < OrderOpenPrice() ) return;//Not at breakeven yet // Increment sl by sl + JumpingStopPips. // This will happen when market price >= (sl + JumpingStopPips) if (Bid>= sl + (TrailingStopPips * Point) ) { NewStop = NormalizeDouble(sl + (TrailingStopPips * Point), Digits); ObjectMove(LineName, 0, Time[0], NewStop); }// if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice()) }//if (OrderType()==OP_BUY) if (OrderType()==OP_SELL) { if (sl > OrderOpenPrice() ) return;//Not at breakeven yet // Decrement sl by sl - JumpingStopPips. // This will happen when market price <= (sl - JumpingStopPips) if (Bid<= sl - (TrailingStopPips * Point) ) { NewStop = NormalizeDouble(sl - (TrailingStopPips * Point), Digits); ObjectMove(LineName, 0, Time[0], NewStop); }// close if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice()) }//if (OrderType()==OP_SELL) } // End of TrailingStopLoss sub void CandlestickTrailingStop() { //Trails the stop at the hi/lo of the previous candle. //Only tries to do this once per bar, so an invalid stop error will only be generated once. if (OldCstBars == Bars) return; OldCstBars = Bars; if (OrderProfit() < 0) return;//Nothing to do string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0); double sl = ObjectGet(LineName, OBJPROP_PRICE1); if (sl == 0) return;//No line, so nothing to do double NewStop; Alert("W"); if (OrderType() == OP_BUY) { if (Low[1] > sl) { NewStop = NormalizeDouble(Low[1], Digits); ObjectMove(LineName, 0, Time[0], NewStop); }//if (Low[1] > sl) }//if (OrderType == OP_BUY) if (OrderType() == OP_SELL) { if (High[1] < sl) { NewStop = NormalizeDouble(High[1], Digits); ObjectMove(LineName, 0, Time[0], NewStop); }//if (High[1] < sl) }//if (OrderType() == OP_SELL) }//End void CandlestickTrailingStop() void TradeManagementModule() { // Call the working subroutines one by one. //Candlestick trailing stop if (UseCandlestickTrailingStop) CandlestickTrailingStop(); // Breakeven if(BreakEven) BreakEvenStopLoss(); // JumpingStop if(JumpingStop) JumpingStopLoss(); //TrailingStop if(TrailingStop) TrailingStopLoss(); }//void TradeManagementModule() //END TRADE MANAGEMENT MODULE //////////////////////////////////////////////////////////////////////////////////////////////// bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take) { //pah (Paul) contributed the code to get around the trade context busy error. Many thanks, Paul. int slippage = 10; if (Digits == 3 || Digits == 5) slippage = 100; color col = Red; if (type == OP_BUY || type == OP_BUYSTOP) col = Green; int expiry = 0; //if (SendPendingTrades) expiry = TimeCurrent() + (PendingExpiryMinutes * 60); //RetryCount is declared as 10 in the Trading variables section at the top of this file for (int cc = 0; cc < RetryCount; cc++) { for (int d = 0; (d < RetryCount) && IsTradeContextBusy(); d++) Sleep(100); RefreshRates(); if (type == OP_BUY) price = NormalizeDouble(Ask, Digits); if (type == OP_SELL) price = NormalizeDouble(Bid, Digits); if (!CriminalIsECN) int ticket = OrderSend(Symbol(),type, lotsize, price, slippage, stop, take, comment, MagicNumber, expiry, col); //Is a 2 stage criminal if (CriminalIsECN) { ticket = OrderSend(Symbol(),type, lotsize, price, slippage, 0, 0, comment, MagicNumber, expiry, col); if (ticket > -1) { ModifyOrder(ticket, stop, take); }//if (ticket > 0)} }//if (CriminalIsECN) if (ticket > -1) break;//Exit the trade send loop if (cc == RetryCount - 1) return(false); }//for (int cc = 0; cc < RetryCount; cc++); //Error trapping for both if (ticket < 0) { string stype; if (type == OP_BUY) stype = "OP_BUY"; if (type == OP_SELL) stype = "OP_SELL"; if (type == OP_BUYLIMIT) stype = "OP_BUYLIMIT"; if (type == OP_SELLLIMIT) stype = "OP_SELLLIMIT"; if (type == OP_BUYSTOP) stype = "OP_BUYSTOP"; if (type == OP_SELLSTOP) stype = "OP_SELLSTOP"; int err=GetLastError(); Alert(Symbol(), " jor ", stype," order send failed with error(",err,"): ",ErrorDescription(err)); Print(Symbol(), " jor ", stype," order send failed with error(",err,"): ",ErrorDescription(err)); return(false); }//if (ticket < 0) TicketNo = ticket; //Make sure the trade has appeared in the platform's history to avoid duplicate trades. //My mod of Matt's code attempts to overcome the bastard crim's attempts to overcome Matt's code. bool TradeReturnedFromCriminal = false; while (!TradeReturnedFromCriminal) { TradeReturnedFromCriminal = O_R_CheckForHistory(ticket); if (!TradeReturnedFromCriminal) { Alert(Symbol(), " sent trade not in your trade history yet. Turn of this ea NOW."); }//if (!TradeReturnedFromCriminal) }//while (!TradeReturnedFromCriminal) //Got this far, so trade send succeeded return(true); }//End bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take) void ModifyOrder(int ticket, double stop, double take) { //Modifies an order already sent if the crim is ECN. if (!OrderSelect(ticket, SELECT_BY_TICKET) ) return;//Trade does not exist, so no mod needed //RetryCount is declared as 10 in the Trading variables section at the top of this file for (int cc = 0; cc < RetryCount; cc++) { for (int d = 0; (d < RetryCount) && IsTradeContextBusy(); d++) Sleep(100); if (take > 0 && stop > 0) { while(IsTradeContextBusy()) Sleep(100); if (OrderModify(ticket, OrderOpenPrice(), stop, take, OrderExpiration(), CLR_NONE)) return; }//if (take > 0 && stop > 0) if (take != 0 && stop == 0) { while(IsTradeContextBusy()) Sleep(100); if (OrderModify(ticket, OrderOpenPrice(), OrderStopLoss(), take, OrderExpiration(), CLR_NONE)) return; }//if (take == 0 && stop != 0) if (take == 0 && stop != 0) { while(IsTradeContextBusy()) Sleep(100); if (OrderModify(ticket, OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE)) return; }//if (take == 0 && stop != 0) }//for (int cc = 0; cc < RetryCount; cc++) //Got this far, so the order modify failed int err=GetLastError(); Print(Symbol(), " SL/TP order modify failed with error(",err,"): ",ErrorDescription(err)); Alert(Symbol(), " SL/TP order modify failed with error(",err,"): ",ErrorDescription(err)); }//void ModifyOrder(int ticket, double tp, double sl) bool IsTradingAllowed() { //Returns false if any of the filters should cancel trading, else returns true to allow trading //Maximum spread if (MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread) return(false); //Swap filter if (OpenTrades == 0) TradeDirectionBySwap(); //An individual currency can only be traded twice, so check for this CanTradeThisPair = true; if (OnlyTradeCurrencyTwice && OpenTrades == 0) { IsThisPairTradable(); }//if (OnlyTradeCurrencyTwice) if (!CanTradeThisPair) return(false); return(true); }//End bool IsTradingAllowed() void LookForTradingOpportunities() { RefreshRates(); double take, stop, price; int type; bool SendTrade; double SendLots = Lot; //Check filters if (!IsTradingAllowed() ) return; //Long if (StochVal > StochOverSold && PrevStochVal < StochOverSold && trend == up) { if (!TradeLong) return; //Balanced pair trade filter. Only apply to pre-recovery trades. //Will remove the comments when I add Recovery //if (OpenTrades + 1 < Start_Recovery_at_trades || !UseRecovery) //{ if (UseZeljko && !BalancedPair(OP_BUY) ) return; //}//if (OpenTrades + 1 < Start_Recovery_at_trades) if (TakeProfit > 0) { take = NormalizeDouble(Ask + (TakeProfit * Point), Digits); HiddenTakeProfit = take; take = NormalizeDouble(take + (HiddenPips * Point), Digits); }//if (TakeProfit > 0) if (StopLoss > 0) { stop = NormalizeDouble(Ask - (StopLoss * Point), Digits); HiddenStopLoss = stop; stop = NormalizeDouble(stop - (HiddenPips * Point), Digits); }//if (StopLoss > 0) type = OP_BUY; price = Ask; SendTrade = true; }//if (StochVal > StochOverSold && PrevStochVal < StochOverSold && trend == up) //Short if (StochVal < StochOverBought && PrevStochVal > StochOverBought && trend == down) { if (!TradeShort) return; //Balanced pair trade filter. Only apply to pre-recovery trades //Will remove the comments when I add Recovery //if (OpenTrades + 1 < Start_Recovery_at_trades || !UseRecovery) //{ if (UseZeljko && !BalancedPair(OP_SELL) ) return; //}//if (OpenTrades + 1 < Start_Recovery_at_trades) if (TakeProfit > 0) { take = NormalizeDouble(Bid - (TakeProfit * Point), Digits); HiddenTakeProfit = take; take = NormalizeDouble(take - (HiddenPips * Point), Digits); }//if (TakeProfit > 0) if (StopLoss > 0) { stop = NormalizeDouble(Bid + (StopLoss * Point), Digits); HiddenStopLoss = stop; stop = NormalizeDouble(stop + (HiddenPips * Point), Digits); }//if (StopLoss > 0) type = OP_SELL; price = Bid; SendTrade = true; }//if (StochVal < StochOverBought && PrevStochVal > StochOverBought && trend == down) if (SendTrade) { bool result = SendSingleTrade(type, TradeComment, SendLots, price, stop, take); }//if (SendTrade) //Actions when trade send succeeds if (SendTrade && result) { if (HiddenPips > 0) ReplaceMissingSlTpLines(); }//if (result) //Actions when trade send fails if (SendTrade && !result) { }//if (!result) }//void LookForTradingOpportunities() bool CloseTrade(int ticket) { while(IsTradeContextBusy()) Sleep(100); bool result = OrderClose(ticket, OrderLots(), OrderClosePrice(), 1000, CLR_NONE); //Actions when trade send succeeds if (result) { return(true); }//if (result) //Actions when trade send fails if (!result) { return(false); }//if (!result) }//End bool CloseTrade(ticket) //////////////////////////////////////////////////////////////////////////////////////////////// //Indicator module double GetAa(int tf, int price, int period, int mashift, int method, int buffer, int shift) { return(iCustom(NULL, 0, "AllAverages_v2.1 cc", tf, price, period, mashift, method, buffer, shift)); }//End double GetAa(int tf, int price, int period, int mashift, int method, int buffer, int shift) double GetStochastic(int shift) { return(iStochastic(NULL,0,K,D,Slowing,MaMethod,PriceField,Mode,shift)); }//double GetStochastic(int shift) void ReadIndicatorValues() { //AA AaVal = GetAa(TimeFrame, Price, MA_Period, MA_Shift, MA_Method, 0, CandleShift); AaUp = GetAa(TimeFrame, Price, MA_Period, MA_Shift, MA_Method, 1, CandleShift);//Up buffer AaDown = GetAa(TimeFrame, Price, MA_Period, MA_Shift, MA_Method, 3, CandleShift);//Down buffer if (AaUp != EMPTY_VALUE) trend = up; if (AaDown != EMPTY_VALUE) trend = down; if (AaUp != EMPTY_VALUE && AaDown != EMPTY_VALUE) trend = both;//Happens at the turn //Stochastic StochVal = GetStochastic(0); if (OldBars != Bars) { PrevStochVal = GetStochastic(1); OldBars = Bars; }//if (OldBars != Bars) }//void ReadIndicatorValues() //End Indicator module //////////////////////////////////////////////////////////////////////////////////////////////// void LookForTradeClosure() { //Close the trade if the new candle opens inside the bands if (!OrderSelect(TicketNo, SELECT_BY_TICKET) ) return; if (OrderSelect(TicketNo, SELECT_BY_TICKET) && OrderCloseTime() > 0) return; bool CloseTrade; string LineName = TpPrefix + DoubleToStr(TicketNo, 0); //Work with the lines on the chart that represent the hidden tp/sl double take = ObjectGet(LineName, OBJPROP_PRICE1); LineName = SlPrefix + DoubleToStr(TicketNo, 0); double stop = ObjectGet(LineName, OBJPROP_PRICE1); if (OrderType() == OP_BUY) { //TP if (Bid >= take && take > 0) CloseTrade = true; //SL if (Bid <= stop && stop > 0) CloseTrade = true; }//if (OrderType() == OP_BUY) if (OrderType() == OP_SELL) { //TP if (Bid <= take && take > 0) CloseTrade = true; //SL if (Bid >= stop && stop > 0) CloseTrade = true; }//if (OrderType() == OP_SELL) if (CloseTrade) { bool result = CloseTrade(TicketNo); //Actions when trade send succeeds if (result) { DeletePendingPriceLines(); }//if (result) //Actions when trade send fails if (!result) { }//if (!result) }//if (CloseTrade) }//void LookForTradeClosure() void CloseAllTrades() { ForceTradeClosure= false; if (OrdersTotal() == 0) return; for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (!OrderSelect(cc, SELECT_BY_POS) ) continue; if (OrderMagicNumber() != MagicNumber) continue; if (OrderSymbol() != Symbol() ) continue; while(IsTradeContextBusy()) Sleep(100); if (OrderType() == OP_BUY || OrderType() == OP_SELL) bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 1000, CLR_NONE); if (result) cc++; if (!result) ForceTradeClosure= true; }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--) }//End void CloseAllTrades() bool CheckTradingTimes() { int hour = TimeHour(TimeLocal() ); if (end_hourm < start_hourm) { end_hourm += 24; } if (end_houre < start_houre) { end_houre += 24; } bool ok2Trade = true; ok2Trade = (hour >= start_hourm && hour <= end_hourm) || (hour >= start_houre && hour <= end_houre); // adjust for past-end-of-day cases // eg in AUS, USDJPY trades 09-17 and 22-06 // so, the above check failed, check if it is because of this condition if (!ok2Trade && hour < 12) { hour += 24; ok2Trade = (hour >= start_hourm && hour <= end_hourm) || (hour >= start_houre && hour <= end_houre); // so, if the trading hours are 11pm - 6am and the time is between midnight to 11am, (say, 5am) // the above code will result in comparing 5+24 to see if it is between 23 (11pm) and 30(6+24), which it is... } // check for end of day by looking at *both* end-hours if (hour >= MathMax(end_hourm, end_houre)) { ok2Trade = false; }//if (hour >= MathMax(end_hourm, end_houre)) return(ok2Trade); }//bool CheckTradingTimes() void CountOpenTrades() { OpenTrades = 0; TicketNo = -1; BuyOpen = false; SellOpen = false; if (OrdersTotal() == 0) return; for (int cc = 0; cc <= OrdersTotal(); cc++) { if (!OrderSelect(cc, SELECT_BY_POS) ) continue; if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) { OpenTrades++; TicketNo = OrderTicket(); if (OrderType() == OP_BUY) BuyOpen = true; if (OrderType() == OP_SELL) SellOpen = true; //Replace missing tp and sl lines if (HiddenPips > 0) ReplaceMissingSlTpLines(); //Management if (OrderProfit() > 0) TradeManagementModule(); //Check for possible trade closure if (HiddenPips > 0) LookForTradeClosure(); return; }//if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) }//for (int cc = 0; cc < OrdersTotal() - 1; cc++) }//End void CountOpenTrades(); //============================================================================= // O_R_CheckForHistory() // // This function is to work around a very annoying and dangerous bug in MT4: // immediately after you send a trade, the trade may NOT show up in the // order history, even though it exists according to ticket number. // As a result, EA's which count history to check for trade entries // may give many multiple entries, possibly blowing your account! // // This function will take a ticket number and loop until // it is seen in the history. // // RETURN VALUE: // TRUE if successful, FALSE otherwise // // // FEATURES: // * Re-trying under some error conditions, sleeping a random // time defined by an exponential probability distribution. // // * Displays various error messages on the log for debugging. // // ORIGINAL AUTHOR AND DATE: // Matt Kennel, 2010 // //============================================================================= bool O_R_CheckForHistory(int ticket) { //My thanks to Matt for this code. He also has the undying gratitude of all users of my trading robots int lastTicket = OrderTicket(); int cnt = 0; int err = GetLastError(); // so we clear the global variable. err = 0; bool exit_loop = false; bool success=false; while (!exit_loop) { /* loop through open trades */ int total=OrdersTotal(); for(int c = 0; c < total; c++) { if(OrderSelect(c,SELECT_BY_POS,MODE_TRADES) == true) { if (OrderTicket() == ticket) { success = true; exit_loop = true; } } } if (cnt > 3) { /* look through history too, as order may have opened and closed immediately */ total=OrdersHistoryTotal(); for(c = 0; c < total; c++) { if(OrderSelect(c,SELECT_BY_POS,MODE_HISTORY) == true) { if (OrderTicket() == ticket) { success = true; exit_loop = true; } } } } cnt = cnt+1; if (cnt > O_R_Setting_max_retries) { exit_loop = true; } if (!(success || exit_loop)) { Print("Did not find #"+ticket+" in history, sleeping, then doing retry #"+cnt); O_R_Sleep(O_R_Setting_sleep_time, O_R_Setting_sleep_max); } } // Select back the prior ticket num in case caller was using it. if (lastTicket >= 0) { OrderSelect(lastTicket, SELECT_BY_TICKET, MODE_TRADES); } if (!success) { Print("Never found #"+ticket+" in history! crap!"); } return(success); }//End bool O_R_CheckForHistory(int ticket) //============================================================================= // O_R_Sleep() // // This sleeps a random amount of time defined by an exponential // probability distribution. The mean time, in Seconds is given // in 'mean_time'. // This returns immediately if we are backtesting // and does not sleep. // //============================================================================= void O_R_Sleep(double mean_time, double max_time) { if (IsTesting()) { return; // return immediately if backtesting. } double p = (MathRand()+1) / 32768.0; double t = -MathLog(p)*mean_time; t = MathMin(t,max_time); int ms = t*1000; if (ms < 10) { ms=10; } Sleep(ms); }//End void O_R_Sleep(double mean_time, double max_time) /////////////////////////////////////////////////////////////////////////////////////////////////////// //Balance/swap filters module void TradeDirectionBySwap() { //Sets TradeLong & TradeShort according to the positive/negative swap it attracts double LongSwap = MarketInfo(Symbol(), MODE_SWAPLONG); double ShortSwap = MarketInfo(Symbol(), MODE_SWAPSHORT); if (CadPairsPositiveOnly) { if (StringSubstr(Symbol(), 0, 3) == "CAD" || StringSubstr(Symbol(), 0, 3) == "cad" || StringSubstr(Symbol(), 3, 3) == "CAD" || StringSubstr(Symbol(), 3, 3) == "cad" ) { if (LongSwap > 0) TradeLong = true; else TradeLong = false; if (ShortSwap > 0) TradeShort = true; else TradeShort = false; }//if (StringSubstr(Symbol(), 0, 3) == "CAD" || StringSubstr(Symbol(), 0, 3) == "cad" ) }//if (CadPairsPositiveOnly) if (AudPairsPositiveOnly) { if (StringSubstr(Symbol(), 0, 3) == "AUD" || StringSubstr(Symbol(), 0, 3) == "aud" || StringSubstr(Symbol(), 3, 3) == "AUD" || StringSubstr(Symbol(), 3, 3) == "aud" ) { if (LongSwap > 0) TradeLong = true; else TradeLong = false; if (ShortSwap > 0) TradeShort = true; else TradeShort = false; }//if (StringSubstr(Symbol(), 0, 3) == "AUD" || StringSubstr(Symbol(), 0, 3) == "aud" || StringSubstr(Symbol(), 3, 3) == "AUD" || StringSubstr(Symbol(), 3, 3) == "aud" ) }//if (AudPairsPositiveOnly) if (NzdPairsPositiveOnly) { if (StringSubstr(Symbol(), 0, 3) == "NZD" || StringSubstr(Symbol(), 0, 3) == "nzd" || StringSubstr(Symbol(), 3, 3) == "NZD" || StringSubstr(Symbol(), 3, 3) == "nzd" ) { if (LongSwap > 0) TradeLong = true; else TradeLong = false; if (ShortSwap > 0) TradeShort = true; else TradeShort = false; }//if (StringSubstr(Symbol(), 0, 3) == "AUD" || StringSubstr(Symbol(), 0, 3) == "aud" || StringSubstr(Symbol(), 3, 3) == "AUD" || StringSubstr(Symbol(), 3, 3) == "aud" ) }//if (AudPairsPositiveOnly) }//void TradeDirectionBySwap() bool IsThisPairTradable() { //Checks to see if either of the currencies in the pair is already being traded twice. //If not, then return true to show that the pair can be traded, else return false string c1 = StringSubstr(Symbol(), 0, 3);//First currency in the pair string c2 = StringSubstr(Symbol(), 3, 3);//Second currency in the pair int c1open = 0, c2open = 0; CanTradeThisPair = true; for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (!OrderSelect(cc, SELECT_BY_POS) ) continue; if (OrderSymbol() != Symbol() ) continue; if (OrderMagicNumber() != MagicNumber) continue; int index = StringFind(OrderSymbol(), c1); if (index > -1) { c1open++; }//if (index > -1) index = StringFind(OrderSymbol(), c2); if (index > -1) { c2open++; }//if (index > -1) if (c1open == 1 && c2open == 1) { CanTradeThisPair = false; return(false); }//if (c1open == 1 && c2open == 1) }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--) //Got this far, so ok to trade return(true); }//End bool IsThisPairTradable() bool BalancedPair(int type) { //Only allow an individual currency to trade if it is a balanced trade //e.g. UJ Buy open, so only allow Sell xxxJPY. //The passed parameter is the proposed trade, so an existing one must balance that //This code courtesy of Zeljko (zkucera) who has my grateful appreciation. string BuyCcy1, SellCcy1, BuyCcy2, SellCcy2; if (type == OP_BUY || type == OP_BUYSTOP) { BuyCcy1 = StringSubstr(Symbol(), 0, 3); SellCcy1 = StringSubstr(Symbol(), 3, 3); }//if (type == OP_BUY || type == OP_BUYSTOP) else { BuyCcy1 = StringSubstr(Symbol(), 3, 3); SellCcy1 = StringSubstr(Symbol(), 0, 3); }//else for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (!OrderSelect(cc, SELECT_BY_POS)) continue; if (OrderSymbol() == Symbol()) continue; if (OrderMagicNumber() != MagicNumber) continue; if (OrderType() == OP_BUY || OrderType() == OP_BUYSTOP) { BuyCcy2 = StringSubstr(OrderSymbol(), 0, 3); SellCcy2 = StringSubstr(OrderSymbol(), 3, 3); }//if (OrderType() == OP_BUY || OrderType() == OP_BUYSTOP) else { BuyCcy2 = StringSubstr(OrderSymbol(), 3, 3); SellCcy2 = StringSubstr(OrderSymbol(), 0, 3); }//else if (BuyCcy1 == BuyCcy2 || SellCcy1 == SellCcy2) return(false); }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--) //Got this far, so it is ok to send the trade return(true); }//End bool BalancedPair(int type) //End Balance/swap filters module /////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// //Pending trade price lines module. //Doubles up by providing missing lines for the stealth stuff void DrawPendingPriceLines() { //This function will work for a full pending-trade EA. //The pending tp/sl can be used for hiding the stops in a market-trading ea /* ObjectDelete(pendingpriceline); ObjectCreate(pendingpriceline, OBJ_HLINE, 0, TimeCurrent(), PendingPrice); if (PendingBuy) ObjectSet(pendingpriceline, OBJPROP_COLOR, Green); if (PendingSell) ObjectSet(pendingpriceline, OBJPROP_COLOR, Red); ObjectSet(pendingpriceline, OBJPROP_WIDTH, 1); ObjectSet(pendingpriceline, OBJPROP_STYLE, STYLE_DASH); */ string LineName = TpPrefix + DoubleToStr(TicketNo, 0);//TicketNo is set by the calling function - either CountOpenTrades or DoesTradeExist HiddenTakeProfit = 0; if (OrderTakeProfit() > 0) { if (OrderType() == OP_BUY || OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT) { HiddenTakeProfit = NormalizeDouble(OrderTakeProfit() - (HiddenPips * Point), Digits); }//if (OrderType() == OP_BUY) if (OrderType() == OP_SELL) { HiddenTakeProfit = NormalizeDouble(OrderTakeProfit() + (HiddenPips * Point), Digits); }//if (OrderType() == OP_BUY) }//if (OrderTakeProfit() > 0) if (HiddenTakeProfit > 0 && ObjectFind(LineName) == -1) { ObjectDelete(LineName); ObjectCreate(LineName, OBJ_HLINE, 0, TimeCurrent(), HiddenTakeProfit); ObjectSet(LineName, OBJPROP_COLOR, Green); ObjectSet(LineName, OBJPROP_WIDTH, 1); ObjectSet(LineName, OBJPROP_STYLE, STYLE_DOT); }//if (HiddenTakeProfit > 0) LineName = SlPrefix + DoubleToStr(TicketNo, 0);//TicketNo is set by the calling function - either CountOpenTrades or DoesTradeExist HiddenStopLoss = 0; if (OrderStopLoss() > 0) { if (OrderType() == OP_BUY) { HiddenStopLoss = NormalizeDouble(OrderStopLoss() + (HiddenPips * Point), Digits); }//if (OrderType() == OP_BUY) if (OrderType() == OP_SELL || OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT) { HiddenStopLoss = NormalizeDouble(OrderStopLoss() - (HiddenPips * Point), Digits); }//if (OrderType() == OP_BUY) }//if (OrderStopLoss() > 0) if (HiddenStopLoss > 0 && ObjectFind(LineName) == -1) { ObjectDelete(LineName); ObjectCreate(LineName, OBJ_HLINE, 0, TimeCurrent(), HiddenStopLoss); ObjectSet(LineName, OBJPROP_COLOR, Red); ObjectSet(LineName, OBJPROP_WIDTH, 1); ObjectSet(LineName, OBJPROP_STYLE, STYLE_DOT); }//if (HiddenStopLoss > 0) }//End void DrawPendingPriceLines() void DeletePendingPriceLines() { //ObjectDelete(pendingpriceline); string LineName = TpPrefix + DoubleToStr(TicketNo, 0); ObjectDelete(LineName); LineName = SlPrefix + DoubleToStr(TicketNo, 0); ObjectDelete(LineName); }//End void DeletePendingPriceLines() void ReplaceMissingSlTpLines() { if (OrderTakeProfit() > 0 || OrderStopLoss() > 0) DrawPendingPriceLines(); }//End void ReplaceMissingSlTpLines() //END Pending trade price lines module /////////////////////////////////////////////////////////////////////////////////////////////////////// //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { //---- if (OrdersTotal() == 0) { TicketNo = -1; ForceTradeClosure = false; }//if (OrdersTotal() == 0) if (ForceTradeClosure) { CloseAllTrades(); return; }//if (ForceTradeClosure) ReadIndicatorValues(); /////////////////////////////////////////////////////////////////////////////////////////////// //Find open trades. CountOpenTrades(); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Trading times bool TradeTimeOk = CheckTradingTimes(); if (!TradeTimeOk) { Comment("Outside trading hours\nstart_hourm-end_hourm: ", start_hourm, "-",end_hourm, "\nstart_houre-end_houre: ", start_houre, "-",end_houre); return; }//if (hour < start_hourm) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Available margin filters EnoughMargin = true;//For user display MarginMessage = ""; if (UseScoobsMarginCheck && OpenTrades > 0) { if(AccountMargin() > (AccountFreeMargin()/100)) { MarginMessage = "There is insufficient margin to allow trading. You might want to turn off the UseScoobsMarginCheck input."; DisplayUserFeedback(); return; }//if(AccountMargin() > (AccountFreeMargin()/100)) }//if (UseScoobsMarginCheck) if (UseForexKiwi && AccountMargin() > 0) { double ml = NormalizeDouble(AccountEquity() / AccountMargin() * 100, 2); if (ml < FkMinimumMarginPercent) { MarginMessage = StringConcatenate("There is insufficient margin percent to allow trading. ", DoubleToStr(ml, 2), "%"); DisplayUserFeedback(); return; }//if (ml < FkMinimumMarginPercent) }//if (UseForexKiwi && AccountMargin() > 0) /////////////////////////////////////////////////////////////////////////////////////////////// //Trading if (TicketNo == -1 && !StopTrading) { LookForTradingOpportunities(); }//if (TicketNo == -1) /////////////////////////////////////////////////////////////////////////////////////////////// DisplayUserFeedback(); //---- return(0); } //+------------------------------------------------------------------+