//+-----------------------------------------------------------------------------------+ //| Stoch_Power_Hedger_V4.3.mq4 | //| David Moser, 10/17/2009 | //| dmoser71@gmail.com | //| Copyright © 2009, David Moser | //| | //| A special thanks and recognition to Forrest Miller for the original concept, | //| Wackena, and Spike for getting SPH V3 code to where it was, and to the | //| [MT_E and I] community for all their feedback and support of this project! | //| | //| forrest@thevision.net wackena@bogie-enterprises.com bulldogge1232000@yahoo.com | //+-----------------------------------------------------------------------------------+ // Please, do not sell this EA because it's FREE // //+-----------------------------------------------------------------------------------+ //| Change Log: | //| 20091007 (V4.0_Beta1): added AutoGMT function, reworked trading hours logic, and | //| restructured the code base to make it more manageable. Corrected the prior | //| hacks made to the code. Program core completely re-engineered. -David Moser | //| | //| 20091008 (V4.0_Beta1): Removed the following per Spike's request: | //| AllSymbolsProtect, Manual, OrdersTimeAlive, EquityProtection, | //| AccountMoneyProtection, AccountEquityPercentProtection. -David Moser | //| | //| DDControl enhanced to work during backtest or during live trading. | //| Trading hours logic revamped, now only one set of trading times based on GMT. | //| System auto-detects account type and adjusts risk accordingly. -David Moser | //| | //| 20091015: (V4.0_Beta2): Added special risk management algorithm (mm=2), plus | //| added a trade recovery feature that will catch up trades missed during non-trade | //| times according to pip spacing rules. Added additional error handling in trade | //| opening and closing routines, including checking for sufficient margin to open | //| new trades. Fixed Account Sentry Hook so that the EA will close all trades and | //| remain disabled. Fixed My Money Profit Target logic. Added a Max DD indicator to | //| gauge the amount of draw down per trade sequence if SL is hit. -David Moser | //| | //| 20091016: (V4.0): Removed ExitOnStoch Parameter, added Strategy Parameter to make | //| it easy to implement new trading strategies. Made the Lot Size Array sensitive | //| to account draw down so that trade sequence sizing is not broken, added globals | //| to preserve lot size sequences between restarts of EA. | //| | //| 20091028: (V4.01): Fixed GMT Offset bug in time management code. Updated time | //| management parameters to indicate that Start/End Times are in GMT. Chart format | //| improved. | //| | //| 20091104: (V4.2): Fixed problem where the EA would not close out trades on Friday | //| sometimes. Also, added a new parameter FridayGMTStopHour which if left on its | //| default of -1, does nothing, but if is increased to 0 or higher, will not trade | //| on Fridays starting at that hour GMT. If used with TTMGoFlat, can close all your | //| positions at the end of each trading week at whatever GMT Hour you specify. | //| | //| 20091109: (V4.2): Fixed problem on 4-digit brokers where sometimes the OrderSend | //| & Orderclose functions would fail with invalid prices. | //| | //| 20091126: (V4.3): Rewrote CloseAllOrders subroutine to address issue where some | //| orders will be orphaned when the system needs to close all buy or sell orders. | //| | //+-----------------------------------------------------------------------------------+ #property copyright "Copyright © 2009, David Moser" #property link "http://www.ForexMT4.com/mt_yahoo/" #import "wininet.dll" int InternetOpenA(string param1, int param2, string param3, string param4, int param5); int InternetOpenUrlA(int param1, string param2, string param3, int param4, int param5, int param6); int InternetReadFile(int param1, string paramp, int param3, int ¶m4[]); int InternetCloseHandle(int param1); #import extern bool USE_INTERNAL_AUTO_PAIR_SETTINGS = TRUE; extern string INFO43="Stoch_Power_Hedger_V4.3"; extern string s01="--STOCH SETTINGS--"; extern int K_Period = 145; extern int D_Period = 20; extern int Slow_Period = 80; extern int Stoch_TF = 60; extern int shift= 4; extern int H_level = 78; extern int L_level = 22; extern string ChooseMAMode43="Choose 1=mode SMA, 2=mode LWMA, 3=mode EMA, 4=mode SMMA"; extern int stochMAmode = 1; extern string s02="--ENVELOPE SETTINGS--"; extern int ENVELOPE_Slow_Period = 14; extern int ENVELOPE_TF = 1440; extern string s03="--MOVING AVERAGE SETTINGS--"; extern int MA_TF = 60; extern int MA_Long_Period = 190; extern int MA_Short_Period = 80; extern string s04="--TRADE SETTINGS--"; extern int Strategy = 1; // S1 is Spike's original SPH strategy, S2 is Spike's new SPH strategy extern double Lots = 0.01; // We start with this number of lots extern int TakeProfit = 110; // Profit Goal in PIPs for the latest order opened extern double multiply= 1.7; extern int MaxTrades= 6; // Maximum number of orders to open extern int Pips= 90; // Distance in Pips from one order to another extern int StopLoss = 600; // StopLoss extern int TrailingStop = 0; // Pips to trail the StopLoss extern int TrailingStep = 0; // Pip interval to increment Trailing StopLoss by each time extern bool RecoveryMode = false; // If non-trading hours blocks opening more than 1 market order to maintain // PIP spacing, then open up 2+ orders as needed if true, only 1 if false. extern string s05="--MONEY MANAGEMENT--"; extern string MM_0="mm=0, risk is ignored, just use Lots parameter"; extern string MM_1="mm=1, risk is basic multiplier based on account balance"; extern string MM_2="mm=2, risk is % of account balance to risk per sequence"; extern int mm= 2; extern string MyRisk="set risk to use when calculating lot size"; extern double risk= 15; // risk to calculate the lots size (only if mm is enabled) extern bool TradeMicroLots = false; // will auto-detect account types, but override available here extern string s06="--MAGIC NUMBERS--"; extern int MagicNumber= 222777; // Primary Magic number for all orders placed extern int MagicMigrate= 111333; // Magic number of trades from previous EA version (to be removed later) extern string s07="--CUTLOSS SETTING--"; extern bool MyMoneyProfitTarget=false; extern double My_Money_Profit_Target=5000; extern bool SecureProfitProtection=false; extern string SP43="If profit made is bigger than SecureProfit we close the orders"; extern int SecureProfit= 15; // If profit made is bigger than SecureProfit we close the orders extern string OTP43="Number of orders to trigger SP Protection"; extern int OrderstoProtect= 3; // Number of orders to enable the account protection extern string s08="--TRADING TIME MANAGEMENT--"; extern string TTM1="Set time frames when new trades can open."; extern string TTM2="If Starthour = Stophour, then trade 24/5."; extern string TTM3="If TTMGoFlat=true, close all open trades"; extern string TTM4="when outside trading hours or days."; extern bool UseAutoGMToffset = true; // If true, attempt to connect to public time source to detect GMT offset. extern bool AutoFallbackOnFail = true; // If true, will use the ManualGMToffset value if the EA cannot read from the public time source. extern int ManualGMToffset = 3; // Set your broker's GMT Offset here in case AutoGMT fails extern int GMTStartHour = 0; // Start trading at 0:00/GMT extern int GMTStopHour = 0; // Stop trading at 23:59/GMT extern bool TradeOnFriday = true; extern int FridayGMTStopHour = -1; // If set to 0 or higher, will prevent new trades from opening on Friday starting at that hour GMT. // If used in conjunction with TTMGoFlat, will close all trades at the end of the trading week. extern bool TTMGoFlat = false; extern string s09="--DRAWDOWN CONTROL TOOL--"; extern string DDC1="Max DD in money allowed?"; extern bool MaxDDControl = false; extern double MaxAllowedDD = -1000.0; extern string DDC2="Max DD in percentage allowed?"; extern bool MaxPercentDDControl = false; extern double MaxAllowedPercentDD = -30.0; extern string s10="--DRAWDOWN REPORTING=="; extern bool ShowDDinfoOnChart = true; extern string s11="--OTHER SETTINGS--"; extern string reverse43="If true, the decision to go long/short will be reversed"; extern bool ReverseCondition= false; // if one the decision to go long/short will be reversed extern string limitorder43="if true, instead open market orders it will open limit orders "; extern bool SetLimitOrders= false; // if true, instead open market orders it will open limit orders color ArrowsColor= Yellow; // color for the orders arrows // Program Variables for Time Management int InternetHandle; string GMTOffsetStatusInfo; bool AutoGMTfailure=false; bool OneTimeInitialize=true; bool EADisabled=false; bool TradingDisabled=false; datetime dtBuyAllowed=0, dtSellAllowed=0; // This is used to control the manual confirmation dialog // Program Variables for Order Management int CurrentOpenOrders[2]={0,0}; int MarketOpenOrders[2]={0,0}; int LimitOpenOrders[2]={0,0}; int PreviousOpenOrders[2]={0,0}; datetime LastOrderOpenTime[2]={0,0}; double LastOrderOpenPrice[2]={0,0}; double MMProfit[2]={0,0}; // Track MyMoney Profit Target Info double SPProfit[2]={0,0}; // Track Secure Profit Protection Info double sl=0, tp=0, BuyPrice=0, SellPrice=0; double BaseLot=0, myBaseLot=0; double LotSizeArray[100,2]; // Element 99,0 and 99,1 used to hold account balance at start of sequence // Second dimension *,0 or *,1 is OP_BUY, OP_SELL specification int mode=0, myOrderTypetmp=0, slippage=50; // Program Variables for Order Opening double Stoch, Var1, Var2, Var3, Var4, Var5, Var6, Var7, Var8; // Program Variables for Statistical Tracking double MaxDD,MaxPercentDD; // General Program Variables string text="", TTstatus = "False", MMPTstatus = "False", SPPstatus = "False", LBOT, LSOT; double ActualRiskPercentS, ActualRiskPercentB; bool result; int cnt=0, myDigits; //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- if(USE_INTERNAL_AUTO_PAIR_SETTINGS) SetParameters(); if (!IsDllsAllowed() && UseAutoGMToffset && !IsTesting()) { Comment("Error: Parameter \"AllowDLL Imports\" must be ON."); Print("Error: Parameter \"AllowDLL Imports\" must be ON."); EADisabled=true; Print("EA Disabled due to DLL setting conflict with UseAutoGMTOffset."); Sleep(10000); return(0); } while (!IsConnected()) { Comment("Waiting for connection..."); Sleep(10000); } myDigits=MarketInfo(Symbol(),MODE_DIGITS); int x; if(myDigits==2) x= 1; if(myDigits==3) x=10; if(myDigits==4) x= 1; if(myDigits==5) x=10; TakeProfit *= x; StopLoss *= x; Pips *= x; TrailingStop *= x; TrailingStep *= x; // Determine Existing Orders, if any. UpdateOrderStatus(true); // Set status strings for display on chart if (MyMoneyProfitTarget) MMPTstatus = "True"; if (SecureProfitProtection) SPPstatus = "True"; // Determine Lot Sizing if (IsTesting()) { CalculateLotArray(OP_BUY,0); CalculateLotArray(OP_SELL,0); } else { ReadLotArray(); // Load LotArray from Globals and/or call for initial calculation as needed } //---- return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- if (!IsTesting()) WriteLotArray(); Print("MaxDD: ",MaxDD); Print("MaxPercDD: ",MaxPercentDD); DeleteAllObjects(); //---- return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { if (EADisabled) { if (IsTesting()) Comment("EA Disabled! Check Journal Log for details.\n"+text); else Comment("EA Disabled! Check Experts Log for details.\n"+text); Sleep(60000); return(0); } // One-time Initialization of GMT Offset and Time-based variables if (OneTimeInitialize) { while (InitializeTimeVariables() < 0) Sleep(1000); return(0); } //**************ADDED FOR ACCOUNT SENTRY *************** if (GlobalVariableGet("GV_CloseAllAndHalt") > 0) { CloseAllOrders(OP_BUY); CloseAllOrders(OP_SELL); EADisabled = true; text="Account Sentry Signaled to Close All and Halt"; return (0); } else //**************END ACCOUNT SENTRY HOOK **************** text=""; TrackDrawDown(); bool exitBuy = false, exitSell = false; int CloseOutStatus = CloseOutTradesCheck(exitBuy, exitSell); // Check to see if we should go flat on long or short positions if (CloseOutStatus > 0) // CloseOutTradesCheck also updates profit information { if (exitBuy) CloseAllOrders(OP_BUY); if (exitSell) CloseAllOrders(OP_SELL); if (CloseOutStatus == 2) { EADisabled = true; text="My Money Profit Target Achieved!"; Print(text); return(0); } if (CloseOutStatus == 3) { EADisabled = true; text="DrawDown Threshold Breached!"; Print(text); return(0); } } else // no reason to close out trades and/or disable the EA, so let's continue... { bool TT = false; if (IsTradingTime() && !TradingDisabled) { TT = true; PrepareIndicators(); // Obtain indicator data values // Check for new entry signals. myOrderTypetmp = 1 for sell, 2 for buy, 3 for no signal. myOrderTypetmp=CheckEntrySignal(); if (ReverseCondition) { if (myOrderTypetmp==1) myOrderTypetmp=2; else if (myOrderTypetmp==2) myOrderTypetmp=1; } if (myOrderTypetmp==1 && CurrentOpenOrders[OP_SELL]==0 && IsTradeAllowed() && dtSellAllowed < TimeCurrent()) { Print("Starting New SELL Sequence"); OpenMarketOrders(myOrderTypetmp); // Pass along the Sell Signal if (SetLimitOrders) OpenLimitOrders(myOrderTypetmp); // Pass along the Sell Signal } if (myOrderTypetmp==2 && CurrentOpenOrders[OP_BUY]==0 && IsTradeAllowed() && dtBuyAllowed < TimeCurrent()) { Print("Starting New BUY Sequence"); OpenMarketOrders(myOrderTypetmp); // Pass along the Buy Signal if (SetLimitOrders) OpenLimitOrders(myOrderTypetmp); // Pass along the Buy Signal } if (!SetLimitOrders && IsTradeAllowed()) OpenMarketOrders(3); // Called with no signal present and will open new orders in an existing sequence as needed } } // Now execute the following code whenever the EA is active, regardless of trade time restrictions or disabled trading condition TSManager(); // Check and maintain trailing stops TTstatus = "False"; if (TT) TTstatus = "True"; if (SecureProfitProtection && MarketOpenOrders[OP_BUY]>=OrderstoProtect) text=StringConcatenate(text, "\nSecure Profit Protection Active on BUY sequence."); if (SecureProfitProtection && MarketOpenOrders[OP_SELL]>=OrderstoProtect) text=StringConcatenate(text, "\nSecure Profit Protection Active on SELL sequence."); if (MyMoneyProfitTarget) text=StringConcatenate(text, "\nMy Money Profit Target Progress: ", DoubleToStr(MMProfit[OP_BUY]+MMProfit[OP_SELL],2), " of ", DoubleToStr(My_Money_Profit_Target,2)); if (myOrderTypetmp!=2 && CurrentOpenOrders[OP_BUY]==0) text=StringConcatenate(text, "\nWAITING FOR BUY SIGNAL..."); if (myOrderTypetmp!=1 && CurrentOpenOrders[OP_SELL]==0) text=StringConcatenate(text, "\nWAITING FOR SELL SIGNAL..."); if (LastOrderOpenTime[OP_BUY]==0) LBOT="............................"; else LBOT=TimeToStr(LastOrderOpenTime[OP_BUY],TIME_DATE|TIME_SECONDS); if (LastOrderOpenTime[OP_SELL]==0) LSOT="............................"; else LSOT=TimeToStr(LastOrderOpenTime[OP_SELL],TIME_DATE|TIME_SECONDS); string myComment=StringConcatenate(GMTOffsetStatusInfo,ShowLotSizeSequence(), "\nIsTradeTime=",TTstatus,", myOrderTypetmp=",myOrderTypetmp,", SPP Enabled=",SPPstatus,", MMPT Enabled=",MMPTstatus, "\nBuy: Last Price=",DoubleToStr(LastOrderOpenPrice[OP_BUY],Digits),", Last Time=",LBOT,", Open Mkt Orders=",MarketOpenOrders[OP_BUY],"/",MaxTrades,", Open Profit=",DoubleToStr(SPProfit[OP_BUY],2), "\nSell: Last Price=",DoubleToStr(LastOrderOpenPrice[OP_SELL],Digits),", Last Time=",LSOT,", Open Mkt Orders=",MarketOpenOrders[OP_SELL],"/",MaxTrades,", Open Profit=",DoubleToStr(SPProfit[OP_SELL],2), text); Comment(myComment); return(0); } //+------------------------------------------------------------------+ int CheckEntrySignal() // Check for new entry signals. Return 1 for sell, 2 for buy, 3 for no signal. { int myOrderType = 3; if (Strategy == 1) // Spike's Original SPH Strategy { if ((Var7 < Var6 && Var7 < Var8)||(Var3 < Var4 && ((Var1 < Var2) || (Stoch>H_level)) && (Var7 > Var6 && Var7 < Var5))) myOrderType = 1; // signal a sell if ((Var7 > Var5 && Var7 > Var8)||(Var3 > Var4 && ((Var1 > Var2) || (Stoch Var6 && Var7 < Var5))) myOrderType = 2; // signal a buy } ////////////////////////////////////////// // // // ADD NEW STRATEGIES BELOW HERE! // // // ////////////////////////////////////////// if (Strategy == 2) // Spike's New Strategy { if (((Var3 < Var4 && ((Var1 < Var2) || (Stoch>H_level)) && (Var7 > Var6 && Var7 < Var5)||(Var7 < Var6 && Var7 < Var8)))) myOrderType=1; // signal a sell if (((Var3 > Var4 && ((Var1 > Var2) || (Stoch Var6 && Var7 < Var5)||(Var7 > Var6 && Var7 > Var8)))) myOrderType=2; // signal a buy } return(myOrderType); } void PrepareIndicators() { int myMAMode=0; switch (stochMAmode) { case 1: myMAMode=MODE_SMA; break; case 2: myMAMode=MODE_LWMA; break; case 3: myMAMode=MODE_EMA; break; case 4: myMAMode=MODE_SMMA; break; default: myMAMode=MODE_LWMA; break; } // If you add a new indicator, don't forget to add a global variable for it just after the externs. Stoch = iStochastic(NULL, Stoch_TF, K_Period, D_Period, Slow_Period, myMAMode, 0, MODE_SIGNAL, shift); Var1 = iStochastic(NULL, Stoch_TF, 145, D_Period, Slow_Period, MODE_SMA, 1, MODE_MAIN, 0); Var2 = iStochastic(NULL, Stoch_TF, 124, D_Period, Slow_Period, MODE_EMA, 1, MODE_SIGNAL, 0); Var3 = iMA(NULL, MA_TF,MA_Long_Period, 0, MODE_SMA, PRICE_CLOSE, 0); Var4 = iMA(NULL, MA_TF,MA_Short_Period, 0, MODE_EMA, PRICE_CLOSE, 0); Var5 = iEnvelopes(NULL,ENVELOPE_TF ,ENVELOPE_Slow_Period, MODE_SMA, 0, PRICE_CLOSE, 0.9, 1, 1); Var6 = iEnvelopes(NULL,ENVELOPE_TF ,ENVELOPE_Slow_Period, MODE_SMA, 0, PRICE_CLOSE, 0.9, 2, 1); Var7 = iMA(NULL, PERIOD_D1, 2, 0, MODE_SMA, PRICE_CLOSE, 0); Var8 = iMA(NULL, PERIOD_D1, 56, 0, MODE_SMMA, PRICE_CLOSE, 0); } void TSManager() { if (TrailingStop>0) { cnt=OrdersTotal()-1; while(cnt>=0) { if(OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES)==false) break; if (IsMyOrder()) { if (OrderType()==OP_SELL) { if ((OrderOpenPrice()-MarketInfo(OrderSymbol(),MODE_ASK))>=(TrailingStop*Point+Pips*Point)) { if (OrderStopLoss()-TrailingStep*Point>(MarketInfo(OrderSymbol(),MODE_ASK)+TrailingStop*Point)) { if(GetTradeContext()) RefreshRates(); result=OrderModify(OrderTicket(),OrderOpenPrice(),MarketInfo(OrderSymbol(),MODE_ASK)+TrailingStop*Point,OrderTakeProfit(),0,Purple); if(result!=true) Print("Trailing Stop Error = ", GetLastError()); else OrderPrint(); } } } if (OrderType()==OP_BUY) { if ((MarketInfo(OrderSymbol(),MODE_BID)-OrderOpenPrice())>=(TrailingStop*Point+Pips*Point)) { if (OrderStopLoss()+TrailingStep*Point<(MarketInfo(OrderSymbol(),MODE_BID)-TrailingStop*Point)) { if(GetTradeContext()) RefreshRates(); result=OrderModify(OrderTicket(),OrderOpenPrice(),MarketInfo(OrderSymbol(),MODE_BID)-TrailingStop*Point,OrderTakeProfit(),0,ArrowsColor); if(result!=true) Print("Trailing Stop Error = ", GetLastError()); else OrderPrint(); return(0); } } } } cnt--; } } } void OpenMarketOrders(int mySignal) // mySignal = 1 for sell, 2 for buy, 3 for no signal. { int cnt=0, gle=0, ticket, attempts, myCount; bool ModifySucceeded; if ((mySignal==1 || mySignal==3) && (dtSellAllowed < TimeCurrent()) && ((CurrentOpenOrders[OP_SELL]>0 && CurrentOpenOrders[OP_SELL]=Pips*Point) && (LastOrderOpenPrice[OP_SELL]>0)) || (CurrentOpenOrders[OP_SELL]==0 && mySignal==1))) { myCount=1; if (RecoveryMode && CurrentOpenOrders[OP_SELL]>0 && CurrentOpenOrders[OP_SELL]=Pips*Point*2) myCount = MathFloor((Bid-LastOrderOpenPrice[OP_SELL])/(Pips*Point)); CalculateLotArray(OP_SELL,CurrentOpenOrders[OP_SELL]); for(cnt=0;cnt0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) { Print("SELL order opened : ",OrderOpenPrice()); LastOrderOpenPrice[OP_SELL]=OrderOpenPrice(); LastOrderOpenTime[OP_SELL]=OrderOpenTime(); UpdateOrderStatus(true); break; } } else { gle=GetLastError(); if (gle==2 || gle==144) { dtSellAllowed = TimeCurrent() + 3600; Print("Manual Trade Confirmation Dialog aborted. No Sell Positions will be attempted for the next 1 hour."); return; } Print("Error opening SELL order : ",gle); attempts++; Sleep(5000); RefreshRates(); } if(attempts >= 20) { Print("20 attempts to open SELL position have failed"); break; } } ModifySucceeded=false; attempts=0; while(!ModifySucceeded && attempts<100) { if(GetTradeContext()) RefreshRates(); ModifySucceeded=OrderModify(ticket,OrderOpenPrice(),sl,tp,0,GreenYellow); if(!ModifySucceeded) { gle=GetLastError(); if (gle==2 || gle==144 || gle==4051) { Print("Manual Trade Confirmation Dialog aborted or invalid ticket. No Sell Positions will be attempted for the next 1 hour."); dtSellAllowed = TimeCurrent() + 3600; return; } Print("Error modifying SELL order : ",gle); attempts++; Sleep(2000); RefreshRates(); } } if(attempts >= 50) { Print("A Critical Error Occurred! The expert could not modify SELL position!"); } } } if ((mySignal==2 || mySignal==3) && (dtBuyAllowed < TimeCurrent()) && ((CurrentOpenOrders[OP_BUY]>0 && CurrentOpenOrders[OP_BUY]=Pips*Point) && (LastOrderOpenPrice[OP_BUY]>0)) || (CurrentOpenOrders[OP_BUY]==0 && mySignal==2))) { myCount=1; if (RecoveryMode && CurrentOpenOrders[OP_BUY]>0 && CurrentOpenOrders[OP_BUY]=Pips*Point*2) myCount = MathFloor((LastOrderOpenPrice[OP_BUY]-Ask)/(Pips*Point)); CalculateLotArray(OP_BUY,CurrentOpenOrders[OP_BUY]); for(cnt=0;cnt0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) { Print("BUY order opened : ",OrderOpenPrice()); LastOrderOpenPrice[OP_BUY]=OrderOpenPrice(); LastOrderOpenTime[OP_BUY]=OrderOpenTime(); UpdateOrderStatus(true); break; } } else { gle=GetLastError(); if (gle==2 || gle==144) { Print("Manual Trade Confirmation Dialog aborted. No Buy Positions will be attempted for the next 1 hour."); dtBuyAllowed = TimeCurrent() + 3600; return; } Print("Error opening BUY order : ",gle); attempts++; Sleep(5000); RefreshRates(); } if(attempts >= 20) { Print("20 attempts to open BUY position have failed"); break; } } ModifySucceeded=false; attempts=0; while(!ModifySucceeded && attempts<100) { if(GetTradeContext()) RefreshRates(); ModifySucceeded=OrderModify(ticket,OrderOpenPrice(),sl,tp,0,GreenYellow); if(!ModifySucceeded) { gle=GetLastError(); if (gle==2 || gle==144 || gle==4051) { Print("Manual Trade Confirmation Dialog aborted or invalid ticket. No Buy Positions will be attempted for the next 1 hour."); dtBuyAllowed = TimeCurrent() + 3600; return; } Print("Error modifying BUY order : ",gle); Print("cnt=",cnt,", myBaseLot=",myBaseLot,", BuyPrice=",BuyPrice,", ticket=",ticket); attempts++; Sleep(2000); RefreshRates(); } } if(attempts >= 50) { Print("A Critical Error Occurred! The expert could not modify BUY position!"); } } } } bool GetTradeContext() { bool hadToWait=false; while(!IsTradeAllowed()) { Sleep(5000); hadToWait=true; } while(IsTradeContextBusy()) { Sleep(200); hadToWait=true; } return(hadToWait); } void OpenLimitOrders(int mySignal) // mySignal = 1 for sell, 2 for buy, 3 for no signal. { int myCount; if (mySignal==1 && CurrentOpenOrders[OP_SELL]= 5) return(false); // GMT Adjusted Day of Week if (currentDay >= 5 && currentHour >= FridayGMTStopHour && FridayGMTStopHour >= 0) return(false); if (GMTStartHour == GMTStopHour) return(true); return(IsTradingTimeSub(GMTStartHour, GMTStopHour)); } bool IsTradingTimeSub(int myStartHour, int myEndHour) { int currentHour = TimeHour(TimeCurrent() - 3600 * ManualGMToffset); int adjustedEndHour = NormalizedHourParam(myEndHour - 1); if (myStartHour == adjustedEndHour) if (currentHour != myStartHour) return(false); if (myStartHour > adjustedEndHour) if (currentHour < myStartHour && currentHour > adjustedEndHour) return(false); if (myStartHour < adjustedEndHour) if (currentHour < myStartHour || currentHour > adjustedEndHour) return(false); return(true); } string GMTSourceURL = "http://ntp.greenwich-mean-time.com/time/scripts/clock-8/x.php"; string GMTUserAgent = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-us) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9"; int AutoGMTOffset() { string status; int result, offsetTmp; InternetHandle = InternetOpenA(GMTUserAgent, 0, "0", "0", 0); string myBuffer = "ABCDEFGHIJ"; if (!RetrieveURLData(GMTSourceURL, myBuffer)) { if (InternetHandle == 0) status = "Error connecting to AutoGMT time source."; if (AutoFallbackOnFail) { result = ManualGMToffset; status = StringConcatenate(status, " Will auto-fallback to Manual Offset."); } else { result = -999999999; } Comment(status); Print(status); Sleep(5000); } else { offsetTmp = TimeCurrent() - StrToInteger(myBuffer); result = MathFloor((offsetTmp + 1800) / 3600); } InternetCloseHandle(InternetHandle); return(result); } bool RetrieveURLData(string URL, string &datum) { int thisHandle = InternetOpenUrlA(InternetHandle, URL, "0", 0, -2080374528, 0); if (thisHandle == 0) return (false); //failure int a[] = {1}; string anotherBuffer = "abcdefghij"; int myStatus = InternetReadFile(thisHandle, anotherBuffer, 10, a); if (thisHandle != 0) InternetCloseHandle(thisHandle); datum = anotherBuffer; return(true); //since datum is a pointer, its contents updated between functions } // Normalize hours to fall into 0-23 range, regardless of input int NormalizedHourParam(int myParam) { while (true) { if (myParam >= 24) { myParam -= 24; continue; } if (myParam >= 0) break; myParam += 24; } return(myParam); } // Track Draw Down statistics for this traded symbol void TrackDrawDown() { double OpenProfit = SPProfit[0]+SPProfit[1]; if (OpenProfit < MaxDD) MaxDD = OpenProfit; if ((OpenProfit/AccountBalance())*100 < MaxPercentDD) MaxPercentDD = (OpenProfit/AccountBalance())*100; if (ShowDDinfoOnChart) { ObjectCreate( "B/E", OBJ_LABEL,0,0,0,0,0,0); ObjectSet( "B/E", OBJPROP_CORNER,3); ObjectSet( "B/E", OBJPROP_XDISTANCE, 3); ObjectSet( "B/E", OBJPROP_YDISTANCE, 30); ObjectSetText("B/E", "B/E: $"+DoubleToStr(NormalizeDouble(AccountBalance(),2),2)+"/"+DoubleToStr(NormalizeDouble(AccountEquity(),2),2),12,"Impact",White); ObjectCreate( "MaxDD", OBJ_LABEL,0,0,0,0,0,0); ObjectSet( "MaxDD", OBJPROP_CORNER,3); ObjectSet( "MaxDD", OBJPROP_XDISTANCE, 3); ObjectSet( "MaxDD", OBJPROP_YDISTANCE, 2); ObjectSetText("MaxDD", "RDD Max: $"+DoubleToStr(NormalizeDouble(MaxDD,2),2)+"/"+DoubleToStr(NormalizeDouble(MaxPercentDD,2),1)+"%",12,"Impact",White); } return; } // Check for any conditions where we should close out trades and possibly halt further trading on this symbol // return 0: no close signal, 1: close for buy, sell or both, 2: close for buy, sell or both, and Disable EA // return 3: Signal Disabling of EA due to Draw Down Control int CloseOutTradesCheck(bool &closeBuy, bool &closeSell) { int result = 0; // Check to see if I reached my equity + closed profit target for this symbol + magic numbers if (MyMoneyProfitTarget) { MMProfit[0]=0; MMProfit[1]=0; // First, we iterate through all open positions for this symbol for(cnt=0;cnt= My_Money_Profit_Target) { text = text + "\nClosing all orders and stop trading because My_Money_Profit_Target reached for this symbol."; Print("Closing all orders and stop trading because My_Money_Profit_Target reached for this symbol."); Print("Profit: ",MMProfit[OP_BUY]+MMProfit[OP_SELL]," Equity: ",AccountEquity()); result = 2; closeBuy = true; closeSell = true; } } // SecureProfit Protection: Close out long running trades with a small profit SPProfit[0]=0; SPProfit[1]=0; for(cnt=0;cnt=SecureProfit && MarketOpenOrders[OP_BUY]>=OrderstoProtect) { text = text + "\nClosing BUY orders because account protection with SecureProfit was triggered."; Print("Closing BUY orders because account protection with SecureProfit was triggered."); Print("Balance: ",AccountBalance()," Equity: ", AccountEquity()," Profit: ",SPProfit[OP_BUY]); result = 1; closeBuy = true; } if (SecureProfitProtection && SPProfit[OP_SELL]>=SecureProfit && MarketOpenOrders[OP_SELL]>=OrderstoProtect) { text = text + "\nClosing SELL orders because account protection with SecureProfit was triggered."; Print("Closing SELL orders because account protection with SecureProfit was triggered."); Print("Balance: ",AccountBalance()," Equity: ", AccountEquity()," Profit: ",SPProfit[OP_SELL]); result = 1; closeSell = true; } // Check to see if any trades recently closed due to hitting StopLoss or TakeProfit, if so, close out that sequence UpdateOrderStatus(false); // Refresh current open order count, but leave previous count alone if (PreviousOpenOrders[OP_BUY] > CurrentOpenOrders[OP_BUY]) { closeBuy = true; result = 1; } if (PreviousOpenOrders[OP_SELL] > CurrentOpenOrders[OP_SELL]) { closeSell = true; result = 1; } // Close out any open trades if TTMGoFlat=true and we are outside of trading hours or trading days if (!IsTradingTime() && TTMGoFlat) { closeBuy = true; closeSell = true; result = 1; } // If DDC thresholds are breached, go flat and disabled further trading if ((MaxDDControl && MaxDD<=MaxAllowedDD) || (MaxPercentDDControl && MaxPercentDD<=MaxAllowedPercentDD)) { closeBuy = true; closeSell = true; result = 3; } return(result); } // All the fancy risk management code is here. If mm=0, just use the user-specified lot size. // If mm=1, use the basic risk multiplier approach. If mm=2, set max % of account balance to risk per trade sequence void CalculateLotArray(int myDirection,int openTradeCount) { double MaxLossAmount; if (mm <= 0 || mm > 2 ) { LotSizeArray[0,myDirection]=NormalizedLots(Lots,true); for (cnt=1;cnt0 && AccountBalance() > LotSizeArray[99,myDirection])) // Only recalc if no trades open or if account balance has increased since the trade sequence has begun { double myLotStep = MarketInfo(Symbol(), MODE_LOTSTEP); if (TradeMicroLots) myLotStep = 0.01; BaseLot=MathCeil(AccountBalance()*risk/10000)/100; // BaseLot amount to 0.01 precision BaseLot=BaseLot * 100000 / MarketInfo(Symbol(), MODE_LOTSIZE); // Adjust for broker lot size information (mini vs. std) LotSizeArray[0,myDirection]=NormalizedLots(BaseLot,true); for (cnt=1;cnt0 && AccountBalance() > LotSizeArray[99,myDirection])) // Only recalc if no trades open or if account balance has increased since the trade sequence has begun { MaxLossAmount = 0; for (cnt=0;cnt=MaxTradeLotSize1) { // Assign incrementally increasing lot size values from the outside in to ramp up risk more evenly // Also called to handle when MaxTradeLotSize exceeds maximum allowed by broker LotSizeArray[MaxTrades-1,myDirection]=MaxTradeLotSize2; for (cnt=MaxTrades-2;cnt>=0;cnt--) LotSizeArray[cnt,myDirection]=LotSizeArray[cnt+1,myDirection]/multiply; for (cnt=MaxTrades-2;cnt>=0;cnt--) LotSizeArray[cnt,myDirection]=NormalizedLots(LotSizeArray[cnt,myDirection],false); } else { // BaseLot is below Minimum Allowed Lotsize, so MaxTradeLotSize2 not large enough to properly spread out the risk LotSizeArray[0,myDirection]=NormalizedLots(BaseLot,false); for (cnt=1;cntMarketInfo(Symbol(), MODE_MAXLOT)) myLotSize=MarketInfo(Symbol(), MODE_MAXLOT); return(myLotSize); } // Get all the time variables set to a proper 0-23 range after adjusting for GMT offset using public time server // or manual GMT offset depending on the configuration parameter externs int InitializeTimeVariables() { string GMTMode; if (UseAutoGMToffset) { if (!IsTesting()) { ManualGMToffset = AutoGMTOffset(); if (ManualGMToffset == -999999999) { text="Failure getting AutoGMToffset, cannot open time-based trades until condition clears."; Comment(text); Print(text); Sleep(120000); // After 2 minutes, we will try again. return(-1); } GMTMode = " (auto)"; } else { text="WARNING: When backtesting, only ManualGMTOffset value can be used, ensure it is set correctly!"; Print(text); GMTMode = " (manual)"; } } else { GMTMode = " (manual)"; } GMTOffsetStatusInfo = StringConcatenate("GMT Offset: ", DoubleToStr(ManualGMToffset, 1), GMTMode); GMTStartHour = NormalizedHourParam(GMTStartHour); GMTStopHour = NormalizedHourParam(GMTStopHour); OneTimeInitialize = false; // clear the flag so this code base runs only one time return(0); } // Move this frequently used code block here to make the code easier to maintain bool IsMyOrder() { if (OrderSymbol() == Symbol() && (OrderMagicNumber() == MagicNumber || OrderMagicNumber() == MagicMigrate)) return(true); return(false); } // Close all Buy or Sell orders. orderMode should be OP_BUY or OP_SELL void CloseAllOrders(int orderMode) { int OrderCount=0; int TicketArray[100]; // first, we retrieve all ticket IDs for existing orders to close out for(cnt=OrdersTotal()-1;cnt>=0;cnt--) { if (OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES)) { mode=OrderType(); if (IsMyOrder()) { if ((mode==orderMode) || (mode==(orderMode+2)) || (mode==(orderMode+4))) { TicketArray[OrderCount]=OrderTicket(); OrderCount++; } } } } // second, we close out all applicable orders in the array. this two step method prevents problems closing out all orders successfully at once. for(cnt=0;cnt 1) myOrderType-=2; // Normalize all buy types to OP_BUY and all sell types to OP_SELL CurrentOpenOrders[myOrderType]++; if(LastOrderOpenTime[myOrderType]0 || CurrentOpenOrders[OP_SELL]>0) { for (int count=0;count 0 && CurrentOpenOrders[OP_BUY]>0) // BUY Lot Array Entry { a = StringFind(gvName, "_", StringLen(gvBase) + 1); b = StringFind(gvName, "_", a + 1); a += 1; StoredPos = StrToInteger(StringSubstr(gvName,a,b-a)); LotSizeArray[StoredPos,OP_BUY] = GlobalVariableGet(gvName); } if (StringFind(gvName, "S_", StringLen(gvBase)-1) > 0 && CurrentOpenOrders[OP_SELL]>0) // SELL Lot Array Entry { a = StringFind(gvName, "_", StringLen(gvBase) + 1); b = StringFind(gvName, "_", a + 1); a += 1; StoredPos = StrToInteger(StringSubstr(gvName,a,b-a)); LotSizeArray[StoredPos,OP_SELL] = GlobalVariableGet(gvName); } } } // Now verify arrays, if either is inconsistent, we will just recalculate that one for (count=0;count0)) BuyReadSuccess=false; if (!(LotSizeArray[count,OP_SELL]>0)) SellReadSuccess=false; } if (!(LotSizeArray[99,OP_BUY]>0)) BuyReadSuccess=false; if (!(LotSizeArray[99,OP_SELL]>0)) SellReadSuccess=false; if (!BuyReadSuccess) CalculateLotArray(OP_BUY,0); if (!SellReadSuccess) CalculateLotArray(OP_SELL,0); } else // No BUY or SELL orders opened { CalculateLotArray(OP_BUY,0); CalculateLotArray(OP_SELL,0); } // Calculate the maximum draw down potential per sequence here // This is the same code from the bottom of the CalculateLotArray function double MaxLossAmount = 0; for (cnt=0;cnt