Jump to content

Dellan

Community Member
  • Posts

    3
  • Joined

  • Last visited

Everything posted by Dellan

  1. Deal all, I'm new to forex and EA, trying to execute the EA to run a backtesting, but it show error unable to load file, need help regarding this issue. Due to unable upload EA file, hence I upload the file My First EA to google share drive (is an EA i create by using AlgoWizard "Simple").
  2. Deal all, I'm new to forex and EA, trying to execute the EA to run a backtesting, but it show error unable to load file, need help regarding this issue. Due to unable upload EA file, hence I paste the code bellow (is an EA i create by using AlgoWizard "Simple"). //+------------------------------------------------------------------+ //| New strategy EA //| //| Generated by StrategyQuant 3.9.132 at 12/30/2022 14:11 //| //| Backtested on EURUSD / D1, 2021.12.28 - 2022.12.28 //| //| This EA uses 3rd party library OrderReliable for industry-strength //| order handling. OrderReliable library is normally distributed under //| GPL license. Its author provided it under MIT license limited to //| usage only within strategies generated by StrategyQuant. //| //| This means that this library doesn't restrict you to use your EA //| generated by SQ comercially in any way you want. //| But if you'll use any method from OrderReliable library outside //| of this EA in your own EAs or projects, its use will be governed //| by its standard GPL license. //| //| Scroll to the very bottom of this source code for the full text //| of OrderReliable license. //+------------------------------------------------------------------+ #property copyright "StrategyQuant.com" #property link "http://www.StrategyQuant.com" #property strict #include <stdlib.mqh> #include <stderror.mqh> const int SLPTTYPE_RANGE = 0; const int SLPTTYPE_LEVEL = 1; //+------------------------------------------------------------------+ // -- Variables //+------------------------------------------------------------------+ extern string CustomComment = "New strategy"; extern int MagicNumber = 11111; bool LongEntrySignal = false; bool ShortEntrySignal = false; bool LongExitSignal = false; bool ShortExitSignal = false; extern int MABarOpensPeriod = 10; //+------------------------------------------------------------------+ // Money Management variables //+------------------------------------------------------------------+ extern string smm = "----------- Money Management - Fixed size -----------"; extern double mmLots = 0.1; //+------------------------------------------------------------------+ // Trading Options variables //+------------------------------------------------------------------+ extern string sdtw = "----------- Dont Trade On Weekends -----------"; extern bool DontTradeOnWeekends = false; extern string FridayCloseTime = "23:00"; extern string SundayOpenTime = "23:00"; extern string seod = "----------- Exit At End Of Day -----------"; extern bool ExitAtEndOfDay = false; extern string EODExitTime = "23:55"; extern string seof = "----------- Exit On Friday -----------"; extern bool ExitOnFriday = false; extern string FridayExitTime = "23:00"; extern string sltr = "----------- Limit Time Range -----------"; extern bool LimitTimeRange = false; extern string SignalTimeRangeFrom = "08:00"; extern string SignalTimeRangeTo = "16:00"; extern bool ExitAtEndOfRange = false; extern int OrderTypeToExit = 0; extern string smmmdfmp = "----------- Max distance from market price -----------"; extern bool LimitMaxDistanceFromMarketPrice = false; //Limit max distance extern double MaxDistanceFromMarketPct = 6; //Max distance % extern string smtpd = "----------- Max Trades Per Day -----------"; extern int MaxTradesPerDay = 0; extern string smmslpt = "----------- Min/Max SL/PT -----------"; extern int MinimumSL = 0; //Minimum SL in pips extern int MinimumPT = 0; //Minimum PT in pips extern int MaximumSL = 0; //Maximum SL in pips extern int MaximumPT = 0; //Maximum PT in pips extern string slts = "----------- Use Tick size from SQ (for CFDs) -----------"; // For exotic pairs (usually non forex CFDs) the default method of computing // tick size in EA might not work correctly. // By turning this on and specifying MainChartTickSizeSQ value you can let EA // use the correct tick size extern bool UseSQTickSize = false; extern double MainChartTickSizeSQ = 1.0E-4; //+------------------------------------------------------------------+ // OrderReliable library variables //+------------------------------------------------------------------+ string OrderReliableVersion = "v36"; string OrderReliable_Fname = "OrderReliable (Function Name Not Set)"; int retry_attempts = 100; // general retry attempts int retry_attempts_bad_price = 3; // retry attempts if the error is bad price double sleep_time = 2.0; double sleep_maximum = 20.0; int ErrorLevel = 3; bool UseLimitToMarket = false; bool UseForTesting = false; bool AddSpreadToComment = false; //+------------------------------------------------------------------+ // -- SQ internal variables // add word "extern" in front of the variable you want // to make configurable //+------------------------------------------------------------------+ int sqMaxEntrySlippage = 5; //Max tolerated entry slippage in pips. Zero means unlimited slippage int sqMaxCloseSlippage = 0; //Max tolerated close slippage in pips. Zero means unlimited slippage bool autoCorrectMaxSlippage = true; //If set to true, it will automatically adjust max slippage according to symbol digits (*10 for 3 and 5 digit symbols) //Some brokers have problems with updating position counts. Set this timeout to non-zero value if you experience this. //For example EnterReverseAtMarket doesn't work well for Admiral Markets, because OrdersTotal() returns 1 even after the order has been closed. uint orderSelectTimeout = 0; //in ms double sqMinDistance = 0.0; //+------------------------------------------------------------------+ // Verbose mode values: // 0 - don't print messages to log at all // 1 - print messages to log only when trading (not when backtesting) // 2 - print messages to log always //+------------------------------------------------------------------+ int sqVerboseMode = 2; extern bool sqDisplayInfoPanel = true; extern bool ModifyInsteadOfReplacing = true; extern int OpenBarDelay = 0; // open bar delay in minutes // it can be used for Daily strategies to trigger trading a few minutes later - // because brokers sometimes have technical delay after midnight and we have to postpone order execution int sqLabelCorner = 1; int sqOffsetHorizontal = 5; int sqOffsetVertical = 20; color sqLabelColor = White; datetime _sqLastOpenBarTime = 0; bool _sqIsBarOpen = false; double gPointCoef = 0; int _ticket; bool cond[100]; double initialBalance = 0; bool openingOrdersAllowed = true; bool firstCall = true; bool strategyUsesATM = false; ////////// //+------------------------------------------------------------------+ // -- Functions //+------------------------------------------------------------------+ void OnTick() { sqInitStart(); sqManageOrders(MagicNumber); openingOrdersAllowed = sqHandleTradingOptions(); //------------------------ // Rule: Trading signals //------------------------ if (sqIsBarOpen()) { // init signals only on bar open LongEntrySignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) > sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1)); ShortEntrySignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) < sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1)); LongExitSignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) < sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1)); ShortExitSignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) > sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1)); } //------------------------ // Rule: Long entry //------------------------ if (sqIsBarOpen() && ((LongEntrySignal && (!(ShortEntrySignal))) && (!(LongExitSignal)))) { // Action #1 _ticket = sqOpenOrder(OP_BUY, "Current", mmLots, 0, MagicNumber, "", 0, false, false, CLR_NONE); if(_ticket > 0 && OrderSelect(_ticket, SELECT_BY_TICKET)) { // set or initialize all order exit methods (SL, PT, Trailing Stop, Exit After Bars, etc.) // StopLoss & ProfitTarget } } //------------------------ // Rule: Short entry //------------------------ if (sqIsBarOpen() && ((ShortEntrySignal && (!(LongEntrySignal))) && (!(ShortExitSignal)))) { // Action #1 _ticket = sqOpenOrder(OP_SELL, "Current", mmLots, 0, MagicNumber, "", 0, false, false, CLR_NONE); if(_ticket > 0 && OrderSelect(_ticket, SELECT_BY_TICKET)) { // set or initialize all order exit methods (SL, PT, Trailing Stop, Exit After Bars, etc.) // StopLoss & ProfitTarget } } //------------------------ // Rule: Long exit //------------------------ if (sqIsBarOpen() && (LongExitSignal && sqMarketPositionIsLong(MagicNumber, "Any", ""))) { // Action #1 sqClosePosition(OrderLots(), // size: SQ.Formulas.CloseSize.FullPosition MagicNumber, // magic number "Any", // symbol 1, // direction "" // comment ); } //------------------------ // Rule: Short exit //------------------------ if (sqIsBarOpen() && (ShortExitSignal && sqMarketPositionIsShort(MagicNumber, "Any", ""))) { // Action #1 sqClosePosition(OrderLots(), // size: SQ.Formulas.CloseSize.FullPosition MagicNumber, // magic number "Any", // symbol -1, // direction "" // comment ); } return; } //+------------------------------------------------------------------+ int OnInit() { VerboseLog("--------------------------------------------------------"); VerboseLog("Starting the EA"); if(!checkComments()){ return(INIT_FAILED); } gPointCoef = calculatePointCoef(Symbol()); VerboseLog("--------------------------------------------------------"); if(sqDisplayInfoPanel) { sqInitInfoPanel(); } SQTime = new CSQTime(); if(!IsTesting() && !IsOptimization()) { initTimer(); } initialBalance = AccountInfoDouble(ACCOUNT_BALANCE); objDontTradeOnWeekends = new CDontTradeOnWeekends(); objExitAtEndOfDay = new CExitAtEndOfDay(); objExitOnFriday = new CExitOnFriday(); objLimitTimeRange = new CLimitTimeRange(); objMaxDistanceFromMarket = new CMaxDistanceFromMarket(); objMaxTradesPerDay = new CMaxTradesPerDay(); objMinMaxSLPT = new CMinMaxSLPT(); double minDistanceMT = NormalizeDouble(MarketInfo(Symbol(), MODE_STOPLEVEL) * MarketInfo(Symbol(), MODE_POINT), Digits); double minDistanceSQ = NormalizeDouble(sqMinDistance * sqGetPointCoef(Symbol()), Digits); if(minDistanceSQ < minDistanceMT){ VerboseLog("--------------------------------------------------------"); VerboseLog("Warning! Min distance of this symbol is greater than min distance set in SQ! The backtest results may differ"); VerboseLog("MT min distance: ", DoubleToStr(minDistanceMT), ", SQ min distance: ", DoubleToStr(minDistanceSQ)); VerboseLog("--------------------------------------------------------"); } //Show all subchart symbols in market watch return(0); } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { sqDeinitInfoPanel(); delete SQTime; delete objDontTradeOnWeekends; delete objExitAtEndOfDay; delete objExitOnFriday; delete objLimitTimeRange; delete objMaxDistanceFromMarket; delete objMaxTradesPerDay; delete objMinMaxSLPT; return; } //+------------------------------------------------------------------+ bool checkComments(){ if(StringLen(CustomComment) > 30){ Alert("Strategy initialization error - Comment CustomComment is longer than 30 characters"); return false; } return true; } //+------------------------------------------------------------------+ void initTimer(){ int period = 20 * 3600; //20 hours period += MathRand() % (10 * 3600); //add another 0-10 hours randomly if(!EventSetTimer(period)){ VerboseLog("Cannot set timer. Error code: ", IntegerToString(GetLastError())); } } //+------------------------------------------------------------------+ void OnTimer(){ //clear unused variables int deletedCount = 0; VerboseLog("Clearing variables..."); for(int a=GlobalVariablesTotal() - 1; a>=0; a--){ string variableName = GlobalVariableName(a); if(GlobalVariableCheck(variableName)){ string variableNameParts[]; int parts = StringSplit(variableName, '_', variableNameParts); if(parts != 3 || variableNameParts[0] != getVariablePrefix()) continue; int ticketNo = StrToInteger(variableNameParts[1]); bool variableUsed = false; for(int i=0; i < OrdersTotal(); i++) { if(OrderSelect(i, SELECT_BY_POS) == true) { if(OrderTicket() == ticketNo){ variableUsed = true; break; } } } ResetLastError(); if(!variableUsed){ if(GlobalVariableDel(variableName)){ deletedCount++; } else { VerboseLog("Cannot delete variable. Error code: ", IntegerToString(GetLastError())); } } } } VerboseLog(IntegerToString(deletedCount), " variables cleared"); } //+------------------------------------------------------------------+ bool sqHandleTradingOptions() { bool continueWithBarUpdate = true; if(!objDontTradeOnWeekends.onBarUpdate()) continueWithBarUpdate = false; if(!objExitAtEndOfDay.onBarUpdate()) continueWithBarUpdate = false; if(!objExitOnFriday.onBarUpdate()) continueWithBarUpdate = false; if(!objLimitTimeRange.onBarUpdate()) continueWithBarUpdate = false; if(!objMaxDistanceFromMarket.onBarUpdate()) continueWithBarUpdate = false; if(!objMaxTradesPerDay.onBarUpdate()) continueWithBarUpdate = false; if(!objMinMaxSLPT.onBarUpdate()) continueWithBarUpdate = false; return(continueWithBarUpdate); } //+------------------------------------------------------------------+ bool checkMagicNumber(int magicNo){ if(magicNo == MagicNumber){ return true; } return false; } //+------------------------------------------------------------------+ double sqGetMarketTickSize(string symbol){ symbol = correctSymbol(symbol); if(symbol == Symbol()){ return MainChartTickSizeSQ; } return -1; } //+------------------------------------------------------------------+ double sqGetGlobalSL(string symbol, int orderType, double price) { return(sqGetSLLevel(symbol, orderType, price, 1, 0)); } //+------------------------------------------------------------------+ double sqGetGlobalPT(string symbol, int orderType, double price) { return(sqGetPTLevel(symbol, orderType, price, 1, 0)); } //+------------------------------------------------------------------+ double sqGetIndicatorByIdentification(string idHash, int shift) { return(0); } //+------------------------------------------------------------------+ double sqGetValueByIdentification(string idHash) { if(idHash == (string) sqStringHash("0")) { return (0); } if(idHash == (string) sqStringHash("0")) { return (0); } if(idHash == (string) sqStringHash("0")) { return (0); } if(idHash == (string) sqStringHash("0")) { return (0); } if(idHash == (string) sqStringHash("0")) { return (0); } if(idHash == (string) sqStringHash("0")) { return (0); } if(idHash == (string) sqStringHash("0")) { return (0); } if(idHash == (string) sqStringHash("0")) { return (0); } if(idHash == (string) sqStringHash("0")) { return (0); } if(idHash == (string) sqStringHash("0")) { return (0); } if(idHash == (string) sqStringHash("0")) { return (0); } if(idHash == (string) sqStringHash("0")) { return (0); } return(0); } //---------------------------------------------------------------------------- void sqManageOrders(int magicNumber) { if(_sqIsBarOpen) { for(int i=OrdersTotal()-1; i>=0; i--) { if (OrderSelect(i,SELECT_BY_POS)==true) { if(OrderMagicNumber() != magicNumber || isMarketClosed(OrderSymbol())) { continue; } int ticket = OrderTicket(); if(OrderType() == OP_BUY || OrderType() == OP_SELL) { // handle Exit Methods only for live orders sqManageSL2BE(ticket); sqManageTrailingStop(ticket); sqManageExitAfterXBars(ticket); } sqManageOrderExpiration(ticket); } if(OrdersTotal() <= 0) return; } } } //---------------------------------------------------------------------------- void sqResetGlobalVariablesForTicket(int ticket) { sqSetGlobalVariable(ticket, "sqOrderExpiration", 0); sqSetGlobalVariable(ticket, "sqOrderOpenTime", Time[0]); sqSetGlobalVariable(ticket, "MoveSL2BE", 0); sqSetGlobalVariable(ticket, "SL2BEAddPips", 0); sqSetGlobalVariable(ticket, "TrailingStop", 0); sqSetGlobalVariable(ticket, "TrailingActivation", 0); sqSetGlobalVariable(ticket, "ExitAfterBars", 0); } //+------------------------------------------------------------------+ void sqInitStart() { // changed recognition of bar open to support also range/renko charts if(_sqLastOpenBarTime == 0) { _sqLastOpenBarTime = Time[0]; _sqIsBarOpen = true; } else { if(_sqLastOpenBarTime != Time[0]) { bool processBarOpen = true; if(OpenBarDelay > 0) { // set bar to open after X minutes from real open processBarOpen = false; long diffInSeconds = TimeCurrent() - Time[0]; if(diffInSeconds >= OpenBarDelay * 60) { processBarOpen = true; } } if(processBarOpen) { _sqIsBarOpen = true; _sqLastOpenBarTime = Time[0]; } } else { _sqIsBarOpen = false; } } if(_sqIsBarOpen && Bars<30) { Print("NOT ENOUGH DATA: Less Bars than 30"); return; } if(!IsTesting() && !IsOptimization()) { sqTextFillOpens(); if(_sqIsBarOpen) { sqTextFillTotals(); } } } //+------------------------------------------------------------------+ bool sqIsBarOpen() { return(_sqIsBarOpen); } //+------------------------------------------------------------------+ int sqGetOrderExpiration(int ticket) { return (int) sqGetGlobalVariable(ticket, "sqOrderExpiration"); } //+------------------------------------------------------------------+ void sqSetOrderExpiration(int ticket, int bars) { sqSetGlobalVariable(ticket, "sqOrderExpiration", bars); } //+------------------------------------------------------------------+ void sqManageOrderExpiration(int ticket) { int tempValue = 0; int barsOpen = 0; // Stop/Limit Order Expiration if(OrderType() != OP_BUY && OrderType() != OP_SELL) { // handle only pending orders tempValue = sqGetOrderExpiration(ticket); if(tempValue > 0) { barsOpen = sqGetOpenBarsForOrder(ticket, tempValue+10); if(barsOpen >= tempValue) { Verbose("Order with ticket: ", IntegerToString(ticket), " expired"); sqDeletePendingOrder(ticket); } } } } //---------------------------------------------------------------------------- double sqIndicatorHighest(int period, int nthValue, string indicatorIdentification) { if(period > 1000) { Alert("Period used for sqIndicatorHighest function is too high. Max value is 1000"); period = 1000; } if(nthValue < 0 || nthValue >= period) { return(-1); } double indicatorValues[1000]; int i; for(i=0; i<1000; i++) { indicatorValues[i] = -2147483647; } for(i=0; i<period; i++) { indicatorValues[i] = sqGetIndicatorByIdentification(indicatorIdentification, i); } ArraySort(indicatorValues, WHOLE_ARRAY,0,MODE_DESCEND); if(nthValue < 0 || nthValue >= period) { return(-1); } return(indicatorValues[nthValue]); } //---------------------------------------------------------------------------- double sqIndicatorLowest(int period, int nthValue, string indicatorIdentification) { if(period > 1000) { Alert("Period used for sqIndicatorLowest function is too high. Max value is 1000"); period = 1000; } if(nthValue < 0 || nthValue >= period) { return(-1); } double indicatorValues[1000]; int i; for(i=0; i<1000; i++) { indicatorValues[i] = 2147483647; } for(i=0; i<period; i++) { indicatorValues[i] = sqGetIndicatorByIdentification(indicatorIdentification, i); } ArraySort(indicatorValues,WHOLE_ARRAY,0,MODE_ASCEND); if(nthValue < 0 || nthValue >= period) { return(-1); } return(indicatorValues[nthValue]); } //---------------------------------------------------------------------------- double sqIndicatorAverage(int period, int maMethod, string indicatorIdentification) { double indicatorValues[10000]; for(int i=0; i<period; i++) { indicatorValues[i] = sqGetIndicatorByIdentification(indicatorIdentification, i); } double maValue = iMAOnArray(indicatorValues, period, period, 0, maMethod, 0); return(maValue); } //---------------------------------------------------------------------------- double sqIndicatorRecent(int barsBack, string indicatorIdentification) { return(sqGetIndicatorByIdentification(indicatorIdentification, barsBack)); } //---------------------------------------------------------------------------- bool sqIsRising(string indicatorIdentification, int bars, bool allowSameValues, int shift) { bool atLeastOnce = false; double previousValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1), 6); for(int i=1; i<bars; i++) { double currentValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1-i), 6); if(currentValue < previousValue) { // indicator was falling return(false); } if(currentValue == previousValue && allowSameValues == false) { // indicator was the same, not allowed return(false); } if(currentValue > previousValue) { atLeastOnce = true; } previousValue = currentValue; } if(atLeastOnce) { return(true); } // indicator was not rising once return(false); } //---------------------------------------------------------------------------- bool sqIsFalling(string indicatorIdentification, int bars, bool allowSameValues, int shift) { bool atLeastOnce = false; double previousValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1), 6); for(int i=1; i<bars; i++) { double currentValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1-i), 6); if(currentValue > previousValue) { // indicator was rising return(false); } if(currentValue == previousValue && allowSameValues == false) { // indicator was the same, not allowed return(false); } if(currentValue < previousValue) { atLeastOnce = true; } previousValue = currentValue; } if(atLeastOnce) { return(true); } // indicator was not falling once return(false); } //+------------------------------------------------------------------+ string getVariablePrefix(){ return IsTesting() ? "SQX(Test)" : "SQX"; } //+------------------------------------------------------------------+ void sqSetGlobalVariable(int ticket, string name, double value) { GlobalVariableSet(getVariablePrefix()+"_"+IntegerToString(ticket)+"_"+name, value); } //+------------------------------------------------------------------+ double sqGetGlobalVariable(int ticket, string name) { return (GlobalVariableGet(getVariablePrefix()+"_"+IntegerToString(ticket)+"_"+name)); } //+------------------------------------------------------------------+ int sqStringHash(string str){ int i, h=0, k; for (i=0; i<StringLen(str); i++){ k = StringGetChar(str, i); h = (h << 5) + h + k; } return(h); } //+------------------------------------------------------------------+ void sqClosePosition(double size, int magicNumber, string symbol, int direction, string comment) { Verbose("Closing order with Magic Number: ", IntegerToString(magicNumber), ", symbol: ", symbol, ", direction: ", IntegerToString(direction), ", comment: ", comment); if(!sqSelectOrder(magicNumber, symbol, direction, comment, false, false)) { Verbose("Order cannot be found"); } else { if(OrderType() == OP_BUY || OrderType() == OP_SELL) { sqClosePositionAtMarket(size); } else { sqDeletePendingOrder(OrderTicket()); } } Verbose("Closing order finished ----------------"); } //+------------------------------------------------------------------+ void sqClosePendingOrder(int magicNumber, string symbol, int direction, string comment) { Verbose("Closing pending order with Magic Number: ", IntegerToString(magicNumber), ", symbol: ", symbol, ", direction: ", IntegerToString(direction), ", comment: ", comment); if(!sqSelectOrder(magicNumber, symbol, direction, comment, false, false, true)) { Verbose("Order cannot be found"); } else { sqDeletePendingOrder(OrderTicket()); } Verbose("Closing pending order finished ----------------"); } //+------------------------------------------------------------------+ void sqCloseAllPendingOrders(int magicNumber, string symbol, int direction, string comment) { Verbose("Closing pending orders with Magic Number: ", IntegerToString(magicNumber), ", symbol: ", symbol, ", direction: ", IntegerToString(direction), ", comment: ", comment); while(sqSelectOrder(magicNumber, symbol, direction, comment, false, false, true)) { sqDeletePendingOrder(OrderTicket()); } Verbose("Closing pending orders finished ----------------"); } //+------------------------------------------------------------------+ int sqGetOpenBarsForOrder(int ticket, int expBarsPeriod) { datetime opTime; if (OrderType() == OP_BUY || OrderType() == OP_SELL) { //live order opTime = OrderOpenTime(); } else { //pending order opTime = (datetime) sqGetGlobalVariable(ticket, "sqOrderOpenTime"); } int numberOfBars = 0; int limit = MathMin(expBarsPeriod + 10, Bars); for(int i=0; i<limit; i++) { if(opTime < Time[i]) { numberOfBars++; } } return(numberOfBars); } //+------------------------------------------------------------------+ void Verbose(string st1, string st2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="", string s13="", string s14="" ) { if(sqVerboseMode == 0) { return; } if(sqVerboseMode == 1 && (IsTesting() || IsOptimization())) { return; } Print("- SQ LOG ", TimeToStr(TimeCurrent()), " ", st1, st2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14); } //+------------------------------------------------------------------+ void VerboseLog(string s1, string s2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) { if(sqVerboseMode != 1) { Log(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12); } Verbose(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12); } //+------------------------------------------------------------------+ void Log(string s1, string s2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) { Print(TimeToStr(TimeCurrent()), " ", s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12); } //+------------------------------------------------------------------+ void sqLog(string st1, string st2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) { Print(TimeToStr(TimeCurrent()), " ", st1, st2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12); } //+------------------------------------------------------------------+ void sqLogToFile(string fileName, string st1, string st2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) { int handle = FileOpen(fileName, FILE_READ | FILE_WRITE, ";"); if(handle>0) { FileSeek(handle,0,SEEK_END); FileWrite(handle, TimeToStr(TimeCurrent()), " ", st1, st2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12); FileClose(handle); } } //+------------------------------------------------------------------+ bool sqSelectOrder(int magicNumber, string symbol, int direction, string comment, bool goFromNewest=true, bool skipPending=true, bool skipFilled=false) { int cc = 0; if(orderSelectTimeout > 0){ Sleep(orderSelectTimeout); } if(goFromNewest){ for (cc = OrdersTotal() - 1; cc >= 0; cc--) { if(orderFits(cc, magicNumber, symbol, direction, comment, skipPending, skipFilled)){ return true; } } } else { for (cc = 0; cc < OrdersTotal(); cc++) { if(orderFits(cc, magicNumber, symbol, direction, comment, skipPending, skipFilled)){ return true; } } } return(false); } //+------------------------------------------------------------------+ bool orderFits(int index, int magicNumber, string symbol, int direction, string comment, bool skipPending=true, bool skipFilled=false){ if (OrderSelect(index, SELECT_BY_POS)) { // skip pending orders if(skipPending && (OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT)) { return false; } // skip filled orders if(skipFilled && (OrderType() == OP_BUY || OrderType() == OP_SELL)) { return false; } if(direction != 0) { if(direction > 0 && (OrderType() != OP_BUY && OrderType() != OP_BUYSTOP && OrderType() != OP_BUYLIMIT)) return false; if(direction < 0 && (OrderType() != OP_SELL && OrderType() != OP_SELLSTOP && OrderType() != OP_SELLLIMIT)) return false; } if(magicNumber != 0) { if(!checkMagicNumber(OrderMagicNumber()) || OrderMagicNumber() != magicNumber) return false; } if(symbol != "Any") { if(OrderSymbol() != correctSymbol(symbol)) return false; } if(comment != "") { if(StringFind(OrderComment(), comment) == -1) return false; } // otherwise we found the order return(true); } else return false; } //+------------------------------------------------------------------+ void sqCloseAllPositions(string symbol, int magicNumber, int direction, string comment) { int count = 100; // maximum number of positions to close int lastTicket = -1; while(count > 0) { count--; if(!sqSelectOrder(magicNumber, symbol, direction, comment, false, false)) { // no position found break; } if(lastTicket == OrderTicket()) { // trying to close the same position one more time, there must be some error break; } lastTicket = OrderTicket(); if(OrderType() == OP_BUY || OrderType() == OP_SELL) { sqClosePositionAtMarket(OrderLots()); } else { sqDeletePendingOrder(OrderTicket()); } } } //+------------------------------------------------------------------+ void sqCloseBestPosition(string symbol, int magicNumber, int direction, string comment) { double maxPL = -100000000; int ticket = 0; if(orderSelectTimeout > 0){ Sleep(orderSelectTimeout); } for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS)) { // skip pending orders if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) { continue; } if(magicNumber != 0) { if(OrderMagicNumber() != magicNumber) continue; } else if(!checkMagicNumber(OrderMagicNumber())) continue; if(OrderProfit() > maxPL) { // found order with better profit maxPL = OrderProfit(); ticket = OrderTicket(); Verbose("Better position found, ticket: ", IntegerToString(ticket),", PL: ", DoubleToString(maxPL)); } } } if(ticket > 0) { if(OrderSelect(ticket, SELECT_BY_TICKET)) { sqClosePositionAtMarket(OrderLots()); } } } //+------------------------------------------------------------------+ void sqCloseWorstPosition(string symbol, int magicNumber, int direction, string comment) { double minPL = 100000000; int ticket = 0; if(orderSelectTimeout > 0){ Sleep(orderSelectTimeout); } for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS)) { // skip pending orders if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) { continue; } if(magicNumber != 0) { if(OrderMagicNumber() != magicNumber) continue; } else if(!checkMagicNumber(OrderMagicNumber())) continue; if(OrderProfit() < minPL) { // found order with worse profit minPL = OrderProfit(); ticket = OrderTicket(); Verbose("Worse position found, ticket: ", IntegerToString(ticket),", PL: ", DoubleToString(minPL)); } } } if(ticket > 0) { if(OrderSelect(ticket, SELECT_BY_TICKET)) { sqClosePositionAtMarket(OrderLots()); } } } //+------------------------------------------------------------------+ int sqGetMarketPosition(string symbol, int magicNumber, string comment) { if(sqSelectOrder(magicNumber, symbol, 0, comment, false)) { if(OrderType() == OP_BUY) { return(1); } else { return(-1); } } return(0); } //+------------------------------------------------------------------+ bool sqMarketPositionIsShort(int magicNo, string symbol, string comment){ return sqSelectOrder(magicNo, symbol, -1, comment, false); } //+------------------------------------------------------------------+ bool sqMarketPositionIsNotShort(int magicNo, string symbol, string comment){ if(sqSelectOrder(magicNo, symbol, -1, comment, false)) { return false; } return true; } //+------------------------------------------------------------------+ bool sqMarketPositionIsLong(int magicNo, string symbol, string comment){ return sqSelectOrder(magicNo, symbol, 1, comment, false); } //+------------------------------------------------------------------+ bool sqMarketPositionIsNotLong(int magicNo, string symbol, string comment){ if(sqSelectOrder(magicNo, symbol, 1, comment, false)) { return false; } return true; } //+------------------------------------------------------------------+ bool sqMarketPositionIsFlat(int magicNo, string symbol, string comment){ return sqGetMarketPosition(symbol, magicNo, comment) == 0; } //+------------------------------------------------------------------+ double sqGetOrderOpenPrice(string symbol, int magicNumber, int direction, string comment) { if(sqSelectOrder(magicNumber, symbol, direction, comment, false)) { return(OrderOpenPrice()); } return(-1); } //+------------------------------------------------------------------+ double sqGetOrderStopLoss(string symbol, int magicNumber, int direction, string comment) { if(sqSelectOrder(magicNumber, symbol, direction, comment, false)) { return(OrderStopLoss()); } return(-1); } //+------------------------------------------------------------------+ double sqGetOrderProfitTarget(string symbol, int magicNumber, int direction, string comment) { if(sqSelectOrder(magicNumber, symbol, direction, comment, false)) { return(OrderTakeProfit()); } return(-1); } //+------------------------------------------------------------------+ double sqGetMarketPositionSize(string symbol, int magicNumber, int direction, string comment) { double lots = 0; if(orderSelectTimeout > 0){ Sleep(orderSelectTimeout); } for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS)) { // skip pending orders if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) { continue; } if(direction != 0) { if(direction > 0 && OrderType() != OP_BUY) continue; if(direction < 0 && OrderType() != OP_SELL) continue; } if(magicNumber != 0) { if(OrderMagicNumber() != magicNumber) continue; } else if(!checkMagicNumber(OrderMagicNumber())) continue; if(symbol != "Any") { if(OrderSymbol() != correctSymbol(symbol)) continue; } if(comment != "") { if(StringFind(OrderComment(), comment) == -1) continue; } lots += OrderLots(); } } return(lots); } //+------------------------------------------------------------------+ double sqGetOpenPL(string symbol, int magicNumber, int direction, string comment) { double pl = 0; if(orderSelectTimeout > 0){ Sleep(orderSelectTimeout); } for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS)) { // skip pending orders if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) { continue; } if(direction != 0) { if(direction > 0 && OrderType() != OP_BUY) continue; if(direction < 0 && OrderType() != OP_SELL) continue; } if(magicNumber != 0) { if(OrderMagicNumber() != magicNumber) continue; } else if(!checkMagicNumber(OrderMagicNumber())) continue; if(symbol != "Any") { if(OrderSymbol() != correctSymbol(symbol)) continue; } if(comment != "") { if(StringFind(OrderComment(), comment) == -1) continue; } pl += OrderProfit(); } } return(pl); } //+------------------------------------------------------------------+ double sqGetOpenPLInPips(string symbol, int magicNumber, int direction, string comment) { double pl = 0; if(orderSelectTimeout > 0){ Sleep(orderSelectTimeout); } for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS)) { // skip pending orders if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) { continue; } if(direction != 0) { if(direction > 0 && OrderType() != OP_BUY) continue; if(direction < 0 && OrderType() != OP_SELL) continue; } if(magicNumber != 0) { if(OrderMagicNumber() != magicNumber) continue; } else if(!checkMagicNumber(OrderMagicNumber())) continue; if(symbol != "Any") { if(OrderSymbol() != correctSymbol(symbol)) continue; } if(comment != "") { if(StringFind(OrderComment(), comment) == -1) continue; } if(OrderType() == OP_BUY) { pl += sqGetBid(OrderSymbol()) - OrderOpenPrice(); } else { pl += OrderOpenPrice() - sqGetAsk(OrderSymbol()); } } } return(sqConvertToPips(OrderSymbol(), pl)); } //+------------------------------------------------------------------+ double sqGetClosedPLInPips(string symbol, int magicNumber, int direction, string comment, int shift) { int index = 0; for(int i=OrdersHistoryTotal(); i>=0; i--) { if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true ) { // skip pending orders if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) { continue; } if(direction != 0) { if(direction > 0 && OrderType() != OP_BUY) continue; if(direction < 0 && OrderType() != OP_SELL) continue; } if(magicNumber != 0) { if(OrderMagicNumber() != magicNumber) continue; } else if(!checkMagicNumber(OrderMagicNumber())) continue; if(symbol != "Any") { if(OrderSymbol() != correctSymbol(symbol)) continue; } if(comment != "") { if(StringFind(OrderComment(), comment) == -1) continue; } if(index == shift) { if(OrderType() == OP_BUY) { return(sqConvertToPips(OrderSymbol(), OrderClosePrice() - OrderOpenPrice())); } else { return(sqConvertToPips(OrderSymbol(), OrderOpenPrice() - OrderClosePrice())); } } index++; } } return(0); } //+------------------------------------------------------------------+ double sqGetClosedPLInMoney(string symbol, int magicNumber, int direction, string comment, int shift) { int index = 0; for(int i=OrdersHistoryTotal(); i>=0; i--) { if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true ) { // skip pending orders if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) { continue; } if(direction != 0) { if(direction > 0 && OrderType() != OP_BUY) continue; if(direction < 0 && OrderType() != OP_SELL) continue; } if(magicNumber != 0) { if(OrderMagicNumber() != magicNumber) continue; } else if(!checkMagicNumber(OrderMagicNumber())) continue; if(symbol != "Any") { if(OrderSymbol() != correctSymbol(symbol)) continue; } if(comment != "") { if(StringFind(OrderComment(), comment) == -1) continue; } if(index == shift) { return(OrderProfit()); } index++; } } return(0); } //+------------------------------------------------------------------+ int sqGetMarketPositionCount(string symbol, int magicNumber, int direction, string comment) { int count = 0; if(orderSelectTimeout > 0){ Sleep(orderSelectTimeout); } for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS)) { // skip pending orders if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) { continue; } if(direction != 0) { if(direction > 0 && OrderType() != OP_BUY) continue; if(direction < 0 && OrderType() != OP_SELL) continue; } if(magicNumber != 0) { if(OrderMagicNumber() != magicNumber) continue; } else if(!checkMagicNumber(OrderMagicNumber())) continue; if(symbol != "Any") { if(OrderSymbol() != correctSymbol(symbol)) continue; } if(comment != "") { if(StringFind(OrderComment(), comment) == -1) continue; } count++; } } return(count); } //+------------------------------------------------------------------+ int sqGetBarsSinceOpen(string symbol, int magicNumber, int direction, string comment) { if(sqSelectOrder(magicNumber, symbol, direction, comment, false, false)) { datetime opTime = OrderOpenTime(); int numberOfBars = 0; int limit = MathMin(10000, Bars); for(int i=0; i<limit; i++) { if(opTime < Time[i]) { numberOfBars++; } } return(numberOfBars); } return(-1); } //+------------------------------------------------------------------+ int sqGetBarsSinceClose(string symbol, int magicNumber, int direction, string comment) { if(sqSelectOrderInHistory(magicNumber, symbol, direction, comment)) { datetime clTime = OrderCloseTime(); int numberOfBars = 0; int limit = MathMin(10000, Bars); for(int i=0; i<limit; i++) { if(clTime < Time[i]) { numberOfBars++; } } return(numberOfBars); } return(-1); } //+------------------------------------------------------------------+ int sqGetLastOrderType(string symbol, int magicNumber, string comment) { if(sqSelectOrderInHistory(magicNumber, symbol, 0, comment)) { if(OrderType() == OP_BUY || OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT) { return(1); } else { return(-1); } } return(0); } //+------------------------------------------------------------------+ bool sqSelectOrderInHistory(int magicNumber, string symbol, int direction, string comment) { for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS,MODE_HISTORY)) { // skip pending orders if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT) { continue; } if(direction != 0) { if(direction > 0 && OrderType() != OP_BUY) continue; if(direction < 0 && OrderType() != OP_SELL) continue; } if(magicNumber != 0) { if(OrderMagicNumber() != magicNumber) continue; } else if(!checkMagicNumber(OrderMagicNumber())) continue; if(symbol != "Any") { if(OrderSymbol() != correctSymbol(symbol)) continue; } if(comment != "") { if(StringFind(OrderComment(), comment) == -1) continue; } // otherwise we found the order return(true); } } return(false); } //+------------------------------------------------------------------+ bool sqSelectPendingOrderByType(int magicNumber, string symbol, int orderType, string comment) { if(orderSelectTimeout > 0){ Sleep(orderSelectTimeout); } for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS)) { if(OrderType() == OP_BUY || OrderType() == OP_SELL) { continue; } if(orderType != 0) { if(OrderType() != orderType) continue; } if(magicNumber != 0) { if(OrderMagicNumber() != magicNumber) continue; } else if(!checkMagicNumber(OrderMagicNumber())) continue; if(symbol != "Any") { if(OrderSymbol() != correctSymbol(symbol)) continue; } if(comment != "") { if(StringFind(OrderComment(), comment) == -1) continue; } // otherwise we found the order return(true); } } return(false); } //+------------------------------------------------------------------+ bool sqSelectPendingOrderByDir(int magicNumber, string symbol, int direction, string comment) { if(orderSelectTimeout > 0){ Sleep(orderSelectTimeout); } for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS)) { if(OrderType() == OP_BUY || OrderType() == OP_SELL) { continue; } if(direction != 0) { int orderDirection = sqGetDirectionFromOrderType(OrderType()); if(orderDirection != direction) continue; } if(magicNumber != 0) { if(OrderMagicNumber() != magicNumber) continue; } else if(!checkMagicNumber(OrderMagicNumber())) continue; if(symbol != "Any") { if(OrderSymbol() != correctSymbol(symbol)) continue; } if(comment != "") { if(StringFind(OrderComment(), comment) == -1) continue; } // otherwise we found the order return(true); } } return(false); } //+------------------------------------------------------------------+ bool sqClosePositionAtMarket(double size) { int ticket = OrderTicket(); Verbose("Closing order with ticket: ", IntegerToString(ticket)); int orderType = OrderType(); if(orderType != OP_BUY && orderType != OP_SELL) { Verbose("Trying to close non-live order"); return(false); } if(!sqCheckConnected()) { return(false); } bool result; double price = sqGetClosePrice(orderType, OrderSymbol(), 0); result = OrderCloseReliable(ticket, size, price, correctSlippage(sqMaxCloseSlippage, OrderSymbol())); if(result) { Verbose("Order deleted successfuly"); return(true); } return(false); } //+------------------------------------------------------------------+ double sqGetAsk(string symbol) { if(symbol == "NULL" || symbol == "Current") { return(NormalizeDouble(Ask, Digits)); } else { return(NormalizeDouble(MarketInfo(correctSymbol(symbol),MODE_ASK), Digits)); } } //+------------------------------------------------------------------+ double sqGetBid(string symbol) { if(symbol == "NULL" || symbol == "Current") { return(NormalizeDouble(Bid, Digits)); } else { return(NormalizeDouble(MarketInfo(correctSymbol(symbol),MODE_BID), Digits)); } } //+------------------------------------------------------------------+ bool sqDeleteOrder(int ticket){ if(!OrderSelect(ticket, SELECT_BY_TICKET)){ Verbose("Warning! Cannot delete order - order with ticket ", IntegerToString(ticket), " can't be selected"); return false; } if(sqIsPendingOrder(OrderType())){ return OrderDeleteReliable(ticket); } else { return OrderCloseReliableMKT(ticket, OrderLots(), sqGetDirectionFromOrderType(OrderType()) == 1 ? Bid : Ask, correctSlippage(0, OrderSymbol())); } } //+------------------------------------------------------------------+ bool sqDeletePendingOrder(int ticket) { Verbose(" Deleting pending order, ticket: " + IntegerToString(ticket)); int orderType = OrderType(); if(orderType == OP_BUY || orderType == OP_SELL) { Verbose("Trying to delete non-pending order"); return(false); } if(!sqCheckConnected()) { return(false); } bool result = OrderDeleteReliable(ticket); if(result) { Verbose("Order deleted successfuly"); return(true); } return(false); } //+------------------------------------------------------------------+ int sqOpenOrder(int orderType, string symbol, double size, double price, int magicNumber, string comment, datetime expirationInTime, bool replaceExisting, bool allowDuplicateTrades, color arrowColor, const bool isExitLevel = false) { if(size <= 0) return (0); string correctedSymbol = correctSymbol(symbol); if(isMarketClosed(correctedSymbol)){ return 0; } double ask = sqGetAsk(correctedSymbol); double bid = sqGetBid(correctedSymbol); int direction = sqGetDirectionFromOrderType(orderType); double marketPrice = direction == 1 ? ask : bid; price = (orderType == OP_BUY || orderType == OP_SELL) ? marketPrice : price; price = sqFixMarketPrice(price, correctedSymbol); if(LimitMaxDistanceFromMarketPrice && (orderType != OP_BUY && orderType != OP_SELL)){ double pctDistance = NormalizeDouble(MathAbs(price-marketPrice) / marketPrice * 100, 2); if(pctDistance > NormalizeDouble(MaxDistanceFromMarketPct, 2)){ Verbose("Order skipped - too far from market price. Open price: ", DoubleToStr(price), ", Market price: ", DoubleToStr(marketPrice), ", Max distance: ", DoubleToStr(MaxDistanceFromMarketPct), "%"); return(0); } } openingOrdersAllowed = openingOrdersAllowed && sqHandleTradingOptions(); if(!openingOrdersAllowed) return(0); Verbose("Opening order type ", OrderTypeToString(orderType)," with price ", DoubleToString(price), ". Current market prices: ", DoubleToString(ask), " / ", DoubleToString(bid)); // check if live order exists if(!isExitLevel && sqSelectOrder(magicNumber, correctedSymbol, 0, comment) && !allowDuplicateTrades) { Verbose("Order with these parameters already exists and duplicate trades are not allowed. Canceling order..."); Verbose("----------------------------------"); return(0); } // check if pending order exists if(!isExitLevel){ while(sqSelectOrder(magicNumber, correctedSymbol, direction, comment, false, false, true)) { if(replaceExisting) { if(!strategyUsesATM && ModifyInsteadOfReplacing && size == OrderLots()) { // modify existing pending order if(OrderModifyReliable(OrderTicket(), price, 0, 0, expirationInTime)) { // reset global variables for this order sqResetGlobalVariablesForTicket(OrderTicket()); return ( OrderTicket() ); } else { Verbose("Modifying order failed, deleting it"); sqDeletePendingOrder(OrderTicket()); return(0); } } else { // delete existing pending order sqDeletePendingOrder(OrderTicket()); } } else { Verbose("Pending Order with these parameters already exists, and replace is not allowed. Canceling order...", " ----------------"); return(0); } } } if(!checkOrderPriceValid(orderType, correctedSymbol, price, marketPrice)){ return 0; } //check free margin if(AccountFreeMarginCheck(correctedSymbol, isLongOrder(orderType) ? OP_BUY : OP_SELL, size) <= 0 || GetLastError()==134) { Alert("Balance too low for trading!"); return(0); } string commentToUse = ""; if(comment != ""){ commentToUse = comment; } else { commentToUse = CustomComment; } int ticket = OrderSendReliable(correctedSymbol, orderType, size, price, correctSlippage(sqMaxEntrySlippage, correctedSymbol), 0, 0, commentToUse, magicNumber, expirationInTime, arrowColor); if(ticket > 0) { // reset global variables for this order sqResetGlobalVariablesForTicket(ticket); } return(ticket); } //+------------------------------------------------------------------+ bool isLongOrder(int orderType){ return orderType == OP_BUY || orderType == OP_BUYLIMIT || orderType == OP_BUYSTOP; } //---------------------------------------------------------------------------- int correctSlippage(int slippage, string symbol = NULL){ if(slippage <= 0) return 100000; if(autoCorrectMaxSlippage){ int realDigits = (int) MarketInfo(correctSymbol(symbol), MODE_DIGITS); if(realDigits > 0 && realDigits != 2 && realDigits != 4) { return slippage * 10; } } return slippage; } //---------------------------------------------------------------------------- bool checkOrderPriceValid(int orderType, string symbol, double price, double marketPrice){ if(orderType == OP_BUY || orderType == OP_SELL){ if(marketPrice == price){ return true; } else { Verbose("Based on its logic, the strategy tried to place order a market order at incorrect price. Market price: ", DoubleToString(marketPrice), ", order price: ", DoubleToString(price), " (this is NOT an error)"); return false; } } return checkStopPriceValid(orderType, symbol, price, marketPrice, "stop/limit order"); } //---------------------------------------------------------------------------- bool checkStopPriceValid(int orderType, string symbol, double price, double marketPrice, string name){ int stopLevel = (int) MarketInfo(symbol, MODE_STOPLEVEL); double point = MarketInfo(symbol, MODE_POINT); double minDistance = point * stopLevel; double minDistanceSQ = sqMinDistance * sqGetPointCoef(symbol); if(minDistanceSQ > minDistance){ minDistance = minDistanceSQ; } double priceLevel; if(orderType == OP_BUYLIMIT || orderType == OP_SELLSTOP){ priceLevel = marketPrice - minDistance; if(price <= priceLevel){ return true; } else { Verbose("Based on its logic, the strategy tried to place ", name, " at incorrect price. Market price: ", DoubleToString(marketPrice), ", max. price allowed: ", DoubleToString(priceLevel), ", ", name, " price: ", DoubleToString(price), " (this is NOT an error)"); return false; } } else if(orderType == OP_BUYSTOP || orderType == OP_SELLLIMIT){ priceLevel = marketPrice + minDistance; if(price >= priceLevel){ return true; } else { Verbose("Based on its logic, the strategy tried to place ", name, " at incorrect price. Market price: ", DoubleToString(marketPrice), ", min. price allowed: ", DoubleToString(priceLevel), ", ", name," price: ", DoubleToString(price), " (this is NOT an error)"); return false; } } else return true; } //+------------------------------------------------------------------+ int sqGetDirectionFromOrderType(int orderType) { if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) { return(1); } else { return(-1); } } //+------------------------------------------------------------------+ bool sqIsPendingOrder(int orderType) { if(orderType != OP_BUY && orderType != OP_SELL) { return(true); } return(false); } //+------------------------------------------------------------------+ void sqSetSLandPT(int ticket, double sl, double pt) { if(sl == 0 && pt == 0) return; if(!OrderSelect(ticket, SELECT_BY_TICKET)) { Verbose("Cannot select order with ticket: ",IntegerToString(ticket)); return; } if(sl == OrderOpenPrice()) { Verbose("SL is the same as order price, cannot set it, so we'll delete the order!"); if(!sqDeleteOrder(ticket)) { Verbose("Warning! Cannot delete order and SL/PT was not set! Error: ", IntegerToString(GetLastError())); } return; } if(pt == OrderOpenPrice()) { pt = 0; } if(sl > 0 || pt > 0) { bool result = sqOrderModify(ticket, OrderOpenPrice(), sqFixMarketPrice(sl, OrderSymbol()), sqFixMarketPrice(pt, OrderSymbol())); if(!result) { Verbose("Cannot set SL / PT for this order, deleting it!"); if(!sqDeleteOrder(ticket)){ Verbose("Warning! Cannot delete order and SL/PT was not set! Error: ", IntegerToString(GetLastError())); } } } } //+------------------------------------------------------------------+ bool sqOrderModifySL(int ticket,double stopLoss, int type) { if(!OrderSelect(ticket, SELECT_BY_TICKET)) { Verbose("Cannot select order with ticket: ",IntegerToString(ticket)); } if(type == SLPTTYPE_RANGE) { // convert range to price level if(sqGetDirectionFromOrderType(OrderType()) == 1) { // it is long order stopLoss = OrderOpenPrice() - stopLoss; } else { stopLoss = OrderOpenPrice() + stopLoss; } } return(sqOrderModify(ticket, OrderOpenPrice(), sqFixMarketPrice(stopLoss, OrderSymbol()), OrderTakeProfit())); } //+------------------------------------------------------------------+ bool sqOrderModifyPT(int ticket,double profitTarget, int type) { if(!OrderSelect(ticket, SELECT_BY_TICKET)) { Verbose("Cannot select order with ticket: ",IntegerToString(ticket)); } if(type == SLPTTYPE_RANGE) { // convert range to price level if(sqGetDirectionFromOrderType(OrderType()) == 1) { // it is long order profitTarget = OrderOpenPrice() + profitTarget; } else { profitTarget = OrderOpenPrice() - profitTarget; } } return(sqOrderModify(ticket, OrderOpenPrice(), OrderStopLoss(), sqFixMarketPrice(profitTarget, OrderSymbol()))); } //+------------------------------------------------------------------+ bool sqOrderModify(int ticket, double price, double stopLoss, double profitTarget) { if(!OrderSelect(ticket, SELECT_BY_TICKET)) { Verbose("Cannot select order with ticket: ",IntegerToString(ticket)); } int digits = (int) MarketInfo(OrderSymbol(), MODE_DIGITS); if (digits > 0) { stopLoss = NormalizeDouble(stopLoss, digits); profitTarget = NormalizeDouble(profitTarget, digits); } Verbose("Modifying order with ticket: ", IntegerToString(ticket), ", SL: ", DoubleToString(stopLoss), " and PT: ", DoubleToString(profitTarget)); int orderType = OrderType(); if(!sqCheckConnected()) { return(false); } bool result; double closestPossibleSL, closestPossiblePT; double point = MarketInfo(OrderSymbol(), MODE_POINT); double minStopLevel = MarketInfo(OrderSymbol(),MODE_STOPLEVEL); if(stopLoss > 0) { // check if SL isn't too close to price if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) { if(orderType == OP_BUY) { closestPossibleSL = NormalizeDouble(Bid-minStopLevel*point, digits); } else { closestPossibleSL = NormalizeDouble(OrderOpenPrice()-minStopLevel*point, digits); } if(stopLoss > closestPossibleSL) { Verbose("Cannot modify SL, it cannot be closer than minimum allowed: ", DoubleToString(stopLoss), " > ", DoubleToString(closestPossibleSL)); return(false); } } else { if(orderType == OP_SELL) { closestPossibleSL = NormalizeDouble(Ask+minStopLevel*point, digits); } else { closestPossibleSL = NormalizeDouble(OrderOpenPrice()+minStopLevel*point, digits); } if(stopLoss < closestPossibleSL) { Verbose("Cannot modify SL, it cannot be closer than minimum allowed: ", DoubleToString(stopLoss), " < ", DoubleToString(closestPossibleSL)); return(false); } } } if(profitTarget > 0) { // check if PT isn't too close to price if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) { if(orderType == OP_BUY) { closestPossiblePT = NormalizeDouble(Bid+minStopLevel*point, digits); } else { closestPossiblePT = NormalizeDouble(OrderOpenPrice()+minStopLevel*point, digits); } if(profitTarget < closestPossiblePT) { Verbose("Cannot modify PT, it cannot be closer than minimum allowed: ", DoubleToString(profitTarget), " < ", DoubleToString(closestPossiblePT)); return(false); } } else { if(orderType == OP_SELL) { closestPossiblePT = NormalizeDouble(Ask-minStopLevel*point, digits); } else { closestPossiblePT = NormalizeDouble(OrderOpenPrice()-minStopLevel*point, digits); } if(profitTarget > closestPossiblePT) { Verbose("Cannot modify PT, it cannot be closer than minimum allowed: ", DoubleToString(profitTarget), " > ", DoubleToString(closestPossiblePT)); return(false); } } } result = OrderModifyReliable(ticket, price, sqFixMarketPrice(stopLoss, OrderSymbol()), sqFixMarketPrice(profitTarget, OrderSymbol()), OrderExpiration()); if(result) { Verbose("Order modified successfuly"); return(true); } return(false); } //+------------------------------------------------------------------+ double sqGetPrice(int orderType, string symbol, double price) { if(price == 0 && (orderType == OP_BUY || orderType == OP_SELL)) { // get newest Ask/Bid price for market order RefreshRates(); if(orderType == OP_BUY) { price = sqGetAsk(symbol); } else { price = sqGetBid(symbol); } } int digits = (int) MarketInfo(symbol, MODE_DIGITS); if (digits > 0) price = NormalizeDouble(price, digits); return(price); } //+------------------------------------------------------------------+ double sqGetClosePrice(int orderType, string symbol, double price) { if(price == 0 && (orderType == OP_BUY || orderType == OP_SELL)) { // get newest Ask/Bid price for market order RefreshRates(); if(orderType == OP_BUY) { price = sqGetBid(symbol); } else { price = sqGetAsk(symbol); } } int digits = (int) MarketInfo(symbol, MODE_DIGITS); if (digits > 0) price = NormalizeDouble(price, digits); return(price); } //+------------------------------------------------------------------+ bool sqCheckConnected() { if (!IsConnected()) { Verbose("Not connected!"); return(false); } if (IsStopped()) { Verbose("EA stopped!"); return(false); } return(true); } //+------------------------------------------------------------------+ int sleepPeriod = 500; // 0.5 s int maxSleepPeriod = 20000; // 20 s. void sqSleep() { //if(IsTesting()) return; Sleep(sleepPeriod); int periods = maxSleepPeriod / sleepPeriod; for(int i=0; i<periods; i++) { if (MathRand() > 16383) { // 50% chance of quitting break; } Sleep(sleepPeriod); } } //+------------------------------------------------------------------+ string sqGetOrderTypeAsString(int type) { switch(type) { case OP_BUY: return("Buy"); case OP_SELL: return("Sell"); case OP_BUYLIMIT: return("Buy Limit"); case OP_BUYSTOP: return("Buy Stop"); case OP_SELLLIMIT: return("Sell Limit"); case OP_SELLSTOP: return("Sell Stop"); } return("Unknown"); } //+------------------------------------------------------------------+ void sqInitInfoPanel() { ObjectCreate("line1", OBJ_LABEL, 0, 0, 0); ObjectSet("line1", OBJPROP_CORNER, sqLabelCorner); ObjectSet("line1", OBJPROP_YDISTANCE, sqOffsetVertical + 0 ); ObjectSet("line1", OBJPROP_XDISTANCE, sqOffsetHorizontal); ObjectSetText("line1", "New strategy", 9, "Tahoma", sqLabelColor); ObjectCreate("linec", OBJ_LABEL, 0, 0, 0); ObjectSet("linec", OBJPROP_CORNER, sqLabelCorner); ObjectSet("linec", OBJPROP_YDISTANCE, sqOffsetVertical + 16 ); ObjectSet("linec", OBJPROP_XDISTANCE, sqOffsetHorizontal); ObjectSetText("linec", "Generated by StrategyQuant EA Wizard", 8, "Tahoma", sqLabelColor); ObjectCreate("line2", OBJ_LABEL, 0, 0, 0); ObjectSet("line2", OBJPROP_CORNER, sqLabelCorner); ObjectSet("line2", OBJPROP_YDISTANCE, sqOffsetVertical + 28); ObjectSet("line2", OBJPROP_XDISTANCE, sqOffsetHorizontal); ObjectSetText("line2", "------------------------------------------", 8, "Tahoma", sqLabelColor); ObjectCreate("lines", OBJ_LABEL, 0, 0, 0); ObjectSet("lines", OBJPROP_CORNER, sqLabelCorner); ObjectSet("lines", OBJPROP_YDISTANCE, sqOffsetVertical + 44); ObjectSet("lines", OBJPROP_XDISTANCE, sqOffsetHorizontal); ObjectSetText("lines", "Last Signal: -", 9, "Tahoma", sqLabelColor); ObjectCreate("lineopl", OBJ_LABEL, 0, 0, 0); ObjectSet("lineopl", OBJPROP_CORNER, sqLabelCorner); ObjectSet("lineopl", OBJPROP_YDISTANCE, sqOffsetVertical + 60); ObjectSet("lineopl", OBJPROP_XDISTANCE, sqOffsetHorizontal); ObjectSetText("lineopl", "Open P/L: -", 8, "Tahoma", sqLabelColor); ObjectCreate("linea", OBJ_LABEL, 0, 0, 0); ObjectSet("linea", OBJPROP_CORNER, sqLabelCorner); ObjectSet("linea", OBJPROP_YDISTANCE, sqOffsetVertical + 76); ObjectSet("linea", OBJPROP_XDISTANCE, sqOffsetHorizontal); ObjectSetText("linea", "Account Balance: -", 8, "Tahoma", sqLabelColor); ObjectCreate("lineto", OBJ_LABEL, 0, 0, 0); ObjectSet("lineto", OBJPROP_CORNER, sqLabelCorner); ObjectSet("lineto", OBJPROP_YDISTANCE, sqOffsetVertical + 92); ObjectSet("lineto", OBJPROP_XDISTANCE, sqOffsetHorizontal); ObjectSetText("lineto", "Total profits/losses so far: -/-", 8, "Tahoma", sqLabelColor); ObjectCreate("linetp", OBJ_LABEL, 0, 0, 0); ObjectSet("linetp", OBJPROP_CORNER, sqLabelCorner); ObjectSet("linetp", OBJPROP_YDISTANCE, sqOffsetVertical + 108); ObjectSet("linetp", OBJPROP_XDISTANCE, sqOffsetHorizontal); ObjectSetText("linetp", "Total P/L so far: -", 8, "Tahoma", sqLabelColor); } //+------------------------------------------------------------------+ void sqDeinitInfoPanel() { ObjectDelete("line1"); ObjectDelete("linec"); ObjectDelete("line2"); ObjectDelete("lines"); ObjectDelete("lineopl"); ObjectDelete("linea"); ObjectDelete("lineto"); ObjectDelete("linetp"); } //+------------------------------------------------------------------+ void sqTextFillOpens() { ObjectSetText("lineopl", "Open P/L: "+DoubleToStr(sqGetOpenPLInMoney(0), 2), 8, "Tahoma", sqLabelColor); ObjectSetText("linea", "Account Balance: "+DoubleToStr(AccountBalance(), 2) , 8, "Tahoma", sqLabelColor); } //+------------------------------------------------------------------+ void sqTextFillTotals() { ObjectSetText("lineto", "Total profits/losses so far: "+DoubleToStr(sqGetTotalProfits(0, 100))+"/"+DoubleToStr(sqGetTotalLosses(0, 100)), 8, "Tahoma", sqLabelColor); ObjectSetText("linetp", "Total P/L so far: "+DoubleToStr(sqGetTotalClosedPLInMoney(0, 1000), 2), 8, "Tahoma", sqLabelColor); } //+------------------------------------------------------------------+ double sqGetOpenPLInMoney(int orderMagicNumber) { double pl = 0; if(orderSelectTimeout > 0){ Sleep(orderSelectTimeout); } for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (!OrderSelect(cc, SELECT_BY_POS) ) continue; if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue; if(OrderSymbol() != Symbol()) continue; if(orderMagicNumber != 0 && OrderMagicNumber() != orderMagicNumber) continue; pl += OrderProfit(); } return(pl); } //+------------------------------------------------------------------+ int sqGetTotalProfits(int orderMagicNumber, int numberOfLastOrders) { double pl = 0; int count = 0; int profits = 0; for(int i=OrdersHistoryTotal(); i>=0; i--) { if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol() == Symbol()) { if(orderMagicNumber == 0 || OrderMagicNumber() == orderMagicNumber) { // return the P/L of last order // or return the P/L of last order with given Magic Number count++; if(OrderType() == OP_BUY) { pl = (OrderClosePrice() - OrderOpenPrice()); } else { pl = (OrderOpenPrice() - OrderClosePrice()); } if(pl > 0) { profits++; } if(count >= numberOfLastOrders) break; } } } return(profits); } //+------------------------------------------------------------------+ int sqGetTotalLosses(int orderMagicNumber, int numberOfLastOrders) { double pl = 0; int count = 0; int losses = 0; for(int i=OrdersHistoryTotal(); i>=0; i--) { if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol() == Symbol()) { if(orderMagicNumber == 0 || OrderMagicNumber() == orderMagicNumber) { // return the P/L of last order // or return the P/L of last order with given Magic Number count++; if(OrderType() == OP_BUY) { pl = (OrderClosePrice() - OrderOpenPrice()); } else { pl = (OrderOpenPrice() - OrderClosePrice()); } if(pl < 0) { losses++; } if(count >= numberOfLastOrders) break; } } } return(losses); } //+------------------------------------------------------------------+ double sqGetTotalClosedPLInMoney(int orderMagicNumber, int numberOfLastOrders) { double pl = 0; int count = 0; for(int i=OrdersHistoryTotal(); i>=0; i--) { if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol() == Symbol()) { if(orderMagicNumber == 0 || OrderMagicNumber() == orderMagicNumber) { // return the P/L of last order or the P/L of last order with given Magic Number count++; pl = pl + OrderProfit(); if(count >= numberOfLastOrders) break; } } } return(pl); } //+------------------------------------------------------------------+ double sqGetSLLevel(string symbol, int orderType, double price, int valueInPips, double value) { return(sqGetSLPTLevel(-1.0, symbol, orderType, price, valueInPips, value)); } //+------------------------------------------------------------------+ double sqGetPTLevel(string symbol, int orderType, double price, int valueInPips, double value) { return(sqGetSLPTLevel(1.0, symbol, orderType, price, valueInPips, value)); } //+------------------------------------------------------------------+ /** * valueType: 1 - pips, 2 - real pips (ATR range), 3 - price level */ double sqGetSLPTLevel(double SLorPT, string symbol, int orderType, double price, int valueType, double value) { string correctedSymbol = correctSymbol(symbol); double pointCoef = sqGetPointCoef(symbol); if(valueType == 1) { // convert from pips to real points value = sqConvertToRealPips(correctedSymbol, value); } if(price == 0) { // price can be zero for market order if(orderType == OP_BUY) { price = sqGetAsk(correctedSymbol); } else { price = sqGetBid(correctedSymbol); } } double slptValue = value; if(valueType != 3) { if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) { slptValue = price + (SLorPT * value); } else { slptValue = price - (SLorPT * value); } } // check that SL / PT is within predefined boundaries double minSLPTValue, maxSLPTValue; if(SLorPT < 0) { // it is SL if(MinimumSL <= 0) { minSLPTValue = slptValue; } else { if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) { minSLPTValue = price + (SLorPT * MinimumSL * pointCoef); slptValue = MathMin(slptValue, minSLPTValue); } else { minSLPTValue = price - (SLorPT * MinimumSL * pointCoef); slptValue = MathMax(slptValue, minSLPTValue); } } if(MaximumSL <= 0) { maxSLPTValue = slptValue; } else { if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) { maxSLPTValue = price + (SLorPT * MaximumSL * pointCoef); slptValue = MathMax(slptValue, maxSLPTValue); } else { maxSLPTValue = price - (SLorPT * MaximumSL * pointCoef); slptValue = MathMin(slptValue, maxSLPTValue); } } } else { // it is PT if(MinimumPT <= 0) { minSLPTValue = slptValue; } else { if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) { minSLPTValue = price + (SLorPT * MinimumPT * pointCoef); slptValue = MathMax(slptValue, minSLPTValue); } else { minSLPTValue = price - (SLorPT * MinimumPT * pointCoef); slptValue = MathMin(slptValue, minSLPTValue); } } if(MaximumPT <= 0) { maxSLPTValue = slptValue; } else { if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) { maxSLPTValue = price + (SLorPT * MaximumPT * pointCoef); slptValue = MathMin(slptValue, maxSLPTValue); } else { maxSLPTValue = price - (SLorPT * MaximumPT * pointCoef); slptValue = MathMax(slptValue, maxSLPTValue); } } } return (slptValue); } //+------------------------------------------------------------------+ double sqConvertToPips(string symbol, double value) { if(symbol == "NULL" || symbol == "Current") { return(value / gPointCoef); } // recognize point coeficient double ticksize = sqGetMarketTickSize(symbol); if(ticksize < 0){ ticksize = calculatePointCoef(symbol); } return(value / ticksize); } //+------------------------------------------------------------------+ double sqConvertToRealPips(string symbol, double value) { if(symbol == "NULL" || symbol == "Current" || symbol == "Same as main chart") { return NormalizeDouble(gPointCoef * value, 6); } double pointCoef = sqGetPointCoef(symbol); return NormalizeDouble(pointCoef * value, 6); } //+------------------------------------------------------------------+ double sqGetPointCoef(string symbol) { if(symbol == "NULL" || symbol == "Current" || symbol == "Same as main chart") { return(gPointCoef); } return calculatePointCoef(symbol); } //+------------------------------------------------------------------+ double calculatePointCoef(string symbol){ string correctedSymbol = correctSymbol(symbol); if(UseSQTickSize) { double ticksize = sqGetMarketTickSize(correctedSymbol); if(ticksize >= 0){ return ticksize; } } int realDigits = (int) MarketInfo(correctedSymbol, MODE_DIGITS); if(realDigits > 0 && realDigits != 2 && realDigits != 4) { realDigits -= 1; } return 1.0 / MathPow(10, realDigits); } //+------------------------------------------------------------------+ bool sqDoublesAreEqual(double n1, double n2) { string st1 = DoubleToStr(n1, Digits); string st2 = DoubleToStr(n2, Digits); return (st1 == st2); } //+------------------------------------------------------------------+ double sqHighest(string symbol, int timeframe, int computedFrom, int period, int shift) { double maxnum = -100000000; double val; for(int i=shift; i<shift+period; i++) { val = sqGetValue(symbol, timeframe, computedFrom, i); if(val > maxnum) { maxnum = val; } } return(maxnum); } //+------------------------------------------------------------------+ double sqHighestIndex(string symbol, int timeframe, int computedFrom, int period, int shift) { double maxnum = -100000000; int index = 0; double val; for(int i=shift; i<shift+period; i++) { val = sqGetValue(symbol, timeframe, computedFrom, i); if(val > maxnum) { maxnum = val; index = i; } } return(index); } //+------------------------------------------------------------------+ double sqLowest(string symbol, int timeframe, int computedFrom, int period, int shift) { double minnum = 100000000; double val; for(int i=shift; i<shift+period; i++) { val = sqGetValue(symbol, timeframe, computedFrom, i); if(val < minnum) { minnum = val; } } return(minnum); } //+------------------------------------------------------------------+ double sqLowestIndex(string symbol, int timeframe, int computedFrom, int period, int shift) { double minnum = 100000000; int index = 0; double val; for(int i=shift; i<shift+period; i++) { val = sqGetValue(symbol, timeframe, computedFrom, i); if(val < minnum) { minnum = val; index = i; } } return(index); } //+------------------------------------------------------------------+ double sqGetValue(string symbol, int timeframe, int computedFrom, int shift) { double val = 0; if(symbol == "NULL" || symbol == "Current") { switch(computedFrom) { case PRICE_OPEN: val = iOpen(NULL, timeframe, shift); break; case PRICE_HIGH: return iHigh(NULL, timeframe, shift); break; case PRICE_LOW: val = iLow(NULL, timeframe, shift); break; case PRICE_CLOSE: val = iClose(NULL, timeframe, shift); break; case PRICE_MEDIAN: val = (iHigh(NULL, timeframe, shift)+iLow(NULL, timeframe, shift))/2; break; case PRICE_TYPICAL: val = (iHigh(NULL, timeframe, shift)+iLow(NULL, timeframe, shift)+iClose(NULL, timeframe, shift))/3; break; case PRICE_WEIGHTED: val = (iHigh(NULL, timeframe, shift)+iLow(NULL, timeframe, shift)+iClose(NULL, timeframe, shift)+iClose(NULL, timeframe, shift))/4; break; } } else { switch(computedFrom) { case PRICE_OPEN: val = iOpen(symbol, timeframe, shift); break; case PRICE_HIGH: val = iHigh(symbol, timeframe, shift); break; case PRICE_LOW: val = iLow(symbol, timeframe, shift); break; case PRICE_CLOSE: val = iClose(symbol, timeframe, shift); break; case PRICE_MEDIAN: val = (iHigh(symbol, timeframe, shift)+iLow(symbol, timeframe, shift))/2; break; case PRICE_TYPICAL: val = (iHigh(symbol, timeframe, shift)+iLow(symbol, timeframe, shift)+iClose(symbol, timeframe, shift))/3; break; case PRICE_WEIGHTED: val = (iHigh(symbol, timeframe, shift)+iLow(symbol, timeframe, shift)+iClose(symbol, timeframe, shift)+iClose(symbol, timeframe, shift))/4; break; } } return roundValue(val); } //+------------------------------------------------------------------+ void sqDrawUpArrow(int shift) { string name = StringConcatenate("Arrow_", MathRand()); ObjectCreate(name, OBJ_ARROW, 0, Time[shift], Low[shift]-100*Point); //draw an up arrow ObjectSet(name, OBJPROP_STYLE, STYLE_SOLID); ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_ARROWUP); ObjectSet(name, OBJPROP_COLOR, Green); } //+------------------------------------------------------------------+ void sqDrawDownArrow(int shift) { string name = StringConcatenate("Arrow_", MathRand()); ObjectCreate(name, OBJ_ARROW, 0, Time[shift], High[shift]+100*Point); //draw an down arrow ObjectSet(name, OBJPROP_STYLE, STYLE_SOLID); ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_ARROWDOWN); ObjectSet(name, OBJPROP_COLOR, Red); } //+------------------------------------------------------------------+ void sqDrawVerticalLine(int shift) { string name = StringConcatenate("VerticalLine", MathRand()); ObjectCreate(name, OBJ_VLINE, 0, Time[shift], 0); //draw a vertical line ObjectSet(name,OBJPROP_COLOR, Red); ObjectSet(name,OBJPROP_WIDTH, 1); ObjectSet(name,OBJPROP_STYLE, STYLE_DOT); } //+------------------------------------------------------------------+ double sqDaily(string symbol, int tf, string mode, int shift) { return sqGetOHLC(symbol, PERIOD_D1, mode, shift); } //+------------------------------------------------------------------+ double sqWeekly(string symbol, int tf, string mode, int shift) { return sqGetOHLC(symbol, PERIOD_W1, mode, shift); } //+------------------------------------------------------------------+ double sqMonthly(string symbol, int tf, string mode, int shift) { return sqGetOHLC(symbol, PERIOD_MN1, mode, shift); } //+------------------------------------------------------------------+ double sqGetOHLC(string symbol, int tf, string mode, int shift){ if(symbol == "NULL" || symbol == "Current") { if(mode == "Open") { return(iOpen(NULL, tf, shift)); } if(mode == "Close") { return(iClose(NULL, tf, shift)); } if(mode == "High") { return(iHigh(NULL, tf, shift)); } if(mode == "Low") { return(iLow(NULL, tf, shift)); } } else { if(mode == "Open") { return(iOpen(symbol, tf, shift)); } if(mode == "Close") { return(iClose(symbol, tf, shift)); } if(mode == "High") { return(iHigh(symbol, tf, shift)); } if(mode == "Low") { return(iLow(symbol, tf, shift)); } } return(-1); } //+------------------------------------------------------------------+ int getHHMM(string time){ string result[]; int k = StringSplit(time, ':', result); if(k == 2){ int hour = StrToInteger(StringSubstr(result[0], 0, 1) == "0" ? StringSubstr(result[0], 1, 1) : result[0]); int minute = StrToInteger(StringSubstr(result[1], 0, 1) == "0" ? StringSubstr(result[1], 1, 1) : result[1]); return (hour * 100) + minute; } else { Print("Incorrect time value format. Value: '" + time + "'"); return 0; } } //+------------------------------------------------------------------+ int sqGetDate(int day, int month, int year) { return (year - 1900) * 10000 + month * 100 + day; } //+------------------------------------------------------------------+ int sqGetBarDate(datetime dt) { return (TimeYear(dt) - 1900) * 10000 + TimeMonth(dt) * 100 + TimeDay(dt); } //+------------------------------------------------------------------+ double sqGetTime(int hour, int minute, int second) { return 100 * hour + minute + 0.01 * second; } //+------------------------------------------------------------------+ int getSQTime(datetime time){ int minutesToday = (int) ((ulong) time / 60) % (24 * 60); int hours = minutesToday / 60; int minutes = minutesToday % 60; return hours*100 + minutes; } //+------------------------------------------------------------------+ double sqSafeDivide(double var1, double var2) { if(var2 == 0) return(100000000); return(var1/var2); } //+------------------------------------------------------------------+ //+ Candle Pattern functions //+------------------------------------------------------------------+ bool sqBearishEngulfing(string symbol, int timeframe, int shift) { double O = sqOpen(symbol, timeframe, shift); double O1 = sqOpen(symbol, timeframe, shift+1); double C = sqClose(symbol, timeframe, shift); double C1 = sqClose(symbol, timeframe, shift+1); double ocDiff = NormalizeDouble(O-C, _Digits); double o1c1Diff = NormalizeDouble(C1-O1, _Digits); if ((C1>O1)&&(O>C)&&(O>=C1)&&(O1>=C)&&(ocDiff>o1c1Diff)) { return(true); } return(false); } //+------------------------------------------------------------------+ bool sqBullishEngulfing(string symbol, int timeframe, int shift) { double O = sqOpen(symbol, timeframe, shift); double O1 = sqOpen(symbol, timeframe, shift+1); double C = sqClose(symbol, timeframe, shift); double C1 = sqClose(symbol, timeframe, shift+1); double coDiff = NormalizeDouble(C-O, _Digits); double o1c1Diff = NormalizeDouble(O1-C1, _Digits); if ((O1>C1)&&(C>O)&&(C>=O1)&&(C1>=O)&&(coDiff>o1c1Diff)) { return(true); } return(false); } //+------------------------------------------------------------------+ bool sqDarkCloudCover(string symbol, int timeframe, int shift) { double L = sqLow(symbol, timeframe, shift); double H = sqHigh(symbol, timeframe, shift); double O = sqOpen(symbol, timeframe, shift); double O1 = sqOpen(symbol, timeframe, shift+1); double C = sqClose(symbol, timeframe, shift); double C1 = sqClose(symbol, timeframe, shift+1); double tickSize = sqGetPointCoef(symbol); double Piercing_Line_Ratio = 0.5f; double Piercing_Candle_Length = 10.0f; double HL = NormalizeDouble(H-L, _Digits); double OC = NormalizeDouble(O-C, _Digits); double OC_HL = HL != 0 ? NormalizeDouble(OC/HL, 6) : 0; double O1C1_D2 = NormalizeDouble((O1+C1)/2, _Digits); double PCL_MTS = NormalizeDouble(Piercing_Candle_Length*tickSize, _Digits); if(C1 > O1 && O1C1_D2 > C && O > C && C > O1 && OC_HL > Piercing_Line_Ratio && HL >= PCL_MTS) { return true; } return(false); } //+------------------------------------------------------------------+ bool sqDoji(string symbol, int timeframe, int shift) { double diff = NormalizeDouble(MathAbs(sqOpen(symbol, timeframe, shift) - sqClose(symbol, timeframe, shift)), _Digits); double coef = NormalizeDouble(sqGetPointCoef(symbol) * 0.6, _Digits); if(diff < coef) { return(true); } return(false); } //+------------------------------------------------------------------+ bool sqHammer(string symbol, int timeframe, int shift) { double H = sqHigh(symbol, timeframe, shift); double L = sqLow(symbol, timeframe, shift); double L1 = sqLow(symbol, timeframe, shift+1); double L2 = sqLow(symbol, timeframe, shift+2); double L3 = sqLow(symbol, timeframe, shift+3); double O = sqOpen(symbol, timeframe, shift); double C = sqClose(symbol, timeframe, shift); double CL = NormalizeDouble(H-L, _Digits); double BodyLow, BodyHigh; double Candle_WickBody_Percent = 0.9; double CandleLength = 12; if (O > C) { BodyHigh = O; BodyLow = C; } else { BodyHigh = C; BodyLow = O; } double LW = NormalizeDouble(BodyLow - L, _Digits); double UW = NormalizeDouble(H - BodyHigh, _Digits); double BLa = NormalizeDouble(MathAbs(O - C), _Digits); double BL90 = NormalizeDouble(BLa * Candle_WickBody_Percent, _Digits); double pipValue = sqGetPointCoef(symbol); double LW_D2 = NormalizeDouble(LW / 2, _Digits); double LW_D3 = NormalizeDouble(LW / 3, _Digits); double LW_D4 = NormalizeDouble(LW / 4, _Digits); double BL90_M2 = NormalizeDouble(2 * BL90, _Digits); double CL_MPV = NormalizeDouble(CandleLength * pipValue, _Digits); if(L <= L1 && L < L2 && L < L3) { if(LW_D2 > UW && LW > BL90_M2 && CL >= CL_MPV && O != C && LW_D3 <= UW && LW_D4 <= UW) { return(true); } if(LW_D3 > UW && LW > BL90_M2 && CL >= CL_MPV && O != C && LW_D4 <= UW) { return(true); } if(LW_D4 > UW && LW > BL90_M2 && CL >= CL_MPV && O != C) { return(true); } } return(false); } //+------------------------------------------------------------------+ bool sqPiercingLine(string symbol, int timeframe, int shift) { double L = sqLow(symbol, timeframe, shift); double H = sqHigh(symbol, timeframe, shift); double O = sqOpen(symbol, timeframe, shift); double O1 = sqOpen(symbol, timeframe, shift+1); double C = sqClose(symbol, timeframe, shift); double C1 = sqClose(symbol, timeframe, shift+1); double tickSize = sqGetPointCoef(symbol); double Piercing_Line_Ratio = 0.5f; double Piercing_Candle_Length = 10.0f; double HL = NormalizeDouble(H-L, _Digits); double CO = NormalizeDouble(C-O, _Digits); double CO_HL = HL != 0 ? NormalizeDouble(CO/HL, 6) : 0; double O1C1_D2 = NormalizeDouble((O1+C1)/2, _Digits); double PCL_MTS = NormalizeDouble(Piercing_Candle_Length*tickSize, _Digits); if(C1 < O1 && O1C1_D2 < C && O < C && C < O1 && CO_HL > Piercing_Line_Ratio && HL >= PCL_MTS) { return true; } return(false); } //+------------------------------------------------------------------+ bool sqShootingStar(string symbol, int timeframe, int shift) { double L = sqLow(symbol, timeframe, shift); double H = sqHigh(symbol, timeframe, shift); double H1 = sqHigh(symbol, timeframe, shift + 1); double H2 = sqHigh(symbol, timeframe, shift + 2); double H3 = sqHigh(symbol, timeframe, shift + 3); double O = sqOpen(symbol, timeframe, shift); double C = sqClose(symbol, timeframe, shift); double CL = NormalizeDouble(H - L, _Digits); double BodyLow, BodyHigh; double Candle_WickBody_Percent = 0.9; double CandleLength = 12; if (O > C) { BodyHigh = O; BodyLow = C; } else { BodyHigh = C; BodyLow = O; } double LW = NormalizeDouble(BodyLow - L, _Digits); double UW = NormalizeDouble(H - BodyHigh, _Digits); double BLa = NormalizeDouble(MathAbs(O - C), _Digits); double BL90 = NormalizeDouble(BLa * Candle_WickBody_Percent, _Digits); double pipValue = sqGetPointCoef(symbol); double UW_D2 = NormalizeDouble(UW / 2, _Digits); double UW_D3 = NormalizeDouble(UW / 3, _Digits); double UW_D4 = NormalizeDouble(UW / 4, _Digits); double BL90_M2 = NormalizeDouble(2 * BL90, _Digits); double CL_MPV = NormalizeDouble(CandleLength * pipValue, _Digits); if(H >= H1 && H > H2 && H > H3) { if(UW_D2 > LW && UW > BL90_M2 && CL >= CL_MPV && O != C && UW_D3 <= LW && UW_D4 <= LW) { return(true); } if(UW_D3 > LW && UW > BL90_M2 && CL >= CL_MPV && O != C && UW_D4 <= LW) { return(true); } if(UW_D4 > LW && UW > BL90_M2 && CL >= CL_MPV && O != C) { return(true); } } return(false); } //+------------------------------------------------------------------+ double sqOpen(string symbol, int timeframe, int shift) { if(symbol == "NULL") { return (iOpen(NULL, timeframe, shift)); } else { return (iOpen(symbol, timeframe, shift)); } } //+------------------------------------------------------------------+ double sqHigh(string symbol, int timeframe, int shift) { if(symbol == "NULL") { return (iHigh(NULL, timeframe, shift)); } else { return (iHigh(symbol, timeframe, shift)); } } //+------------------------------------------------------------------+ double sqLow(string symbol, int timeframe, int shift) { if(symbol == "NULL") { return (iLow(NULL, timeframe, shift)); } else { return (iLow(symbol, timeframe, shift)); } } //+------------------------------------------------------------------+ double sqClose(string symbol, int timeframe, int shift) { if(symbol == "NULL") { return (iClose(NULL, timeframe, shift)); } else { return (iClose(symbol, timeframe, shift)); } } //+------------------------------------------------------------------+ double sqTrueRange(string symbol, int timeframe, int shift) { double close1 = sqClose(symbol, timeframe, shift+1); double high = sqHigh(symbol, timeframe, shift+1); double low = sqLow(symbol, timeframe, shift+1); double TrueHigh, TrueLow; if(close1 > high) { TrueHigh = close1; } else { TrueHigh = high; } if(close1 < low) { TrueLow = close1; } else { TrueLow = low; } double TrueRange = TrueHigh - TrueLow; return (TrueRange); } //+------------------------------------------------------------------+ bool sqTradeRecentlyClosed(string symbol, int magicNumber, bool checkThisBar, bool checkThisMinute) { int ordersChecked = 0; string strCurrentTimeMinutes = TimeToStr( TimeCurrent(), TIME_DATE|TIME_MINUTES); for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS,MODE_HISTORY)) { // skip pending orders if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT) { continue; } if(magicNumber != 0 && OrderMagicNumber() != magicNumber) continue; if(symbol != "Any") { if(OrderSymbol() != correctSymbol(symbol)) continue; } ordersChecked++; if(ordersChecked > 10) { // check only the very last 10 orders break; } if(checkThisBar) { if(OrderCloseTime() >= Time[0]) { // order finished this bar return(true); } } if(checkThisMinute) { string strCloseTimeMinutes = TimeToStr( OrderCloseTime(), TIME_DATE|TIME_MINUTES); if(strCurrentTimeMinutes == strCloseTimeMinutes) { // order finished this minute return(true); } } } } return(false); } //+------------------------------------------------------------------+ double roundDown(double value, int decimals) { double p = 0; switch(decimals) { case 0: return (int) value; case 1: p = 10; break; case 2: p = 100; break; case 3: p = 1000; break; case 4: p = 10000; break; case 5: p = 100000; break; case 6: p = 1000000; break; default: p = MathPow(10, decimals); } value = value * p; double tmp = MathFloor(value + 0.00000001); return NormalizeDouble(tmp/p, decimals); } //+------------------------------------------------------------------+ class CSQTime { public: datetime setHHMM(datetime time, string hhmm) { string date = TimeToStr(time,TIME_DATE);//"yyyy.mm.dd" return (StrToTime(date + " " + hhmm)); } //+------------------------------------------------------------------+ datetime correctDayStart(datetime time) { MqlDateTime strTime; TimeToStruct(time, strTime); strTime.hour = 0; strTime.min = 0; strTime.sec = 0; return (StructToTime(strTime)); } //+------------------------------------------------------------------+ datetime getDateInMs(datetime time) { MqlDateTime strTime; TimeToStruct(time, strTime); strTime.hour = 0; strTime.min = 0; strTime.sec = 0; return (StructToTime(strTime)); } //+------------------------------------------------------------------+ datetime correctDayEnd(datetime time) { MqlDateTime strTime; TimeToStruct(time, strTime); strTime.hour = 23; strTime.min = 59; strTime.sec = 59; return (StructToTime(strTime)); } //+------------------------------------------------------------------+ datetime setDayOfMonth(datetime time, int day) { MqlDateTime strTime; TimeToStruct(time, strTime); strTime.day = day; return (StructToTime(strTime)); } //+------------------------------------------------------------------+ int getMonth(datetime time) { return TimeMonth(time); } //+------------------------------------------------------------------+ int getDaysInMonth(datetime time) { MqlDateTime strTime; TimeToStruct(time, strTime); if(strTime.mon==2) { return 28+isLeapYear(strTime.year); } return 31-((strTime.mon-1)%7)%2; } //+------------------------------------------------------------------+ bool isLeapYear(const int _year){ if(_year%4 == 0){ if(_year%400 == 0)return true; if(_year%100 > 0)return true; } return false; } //+------------------------------------------------------------------+ datetime addDays(datetime time, int days) { int oneDay = 60 * 60 * 24; return (time + (days * oneDay)); } //+------------------------------------------------------------------+ datetime setDayOfWeek(datetime time, int desiredDow) { int dow = convertToSQDOW(TimeDayOfWeek(time)); desiredDow = convertToSQDOW(desiredDow); int diffInDays = desiredDow - dow; //Print("DiffInDays: ", diffInDays, ", dow: ", dow, ", desiredDow: ", desiredDow); return addDays(time, diffInDays); } //+------------------------------------------------------------------+ /** * converts from MT DOW format: 0 = Sunday, 1 = Monday ... 6 = Saturday * to SQ DOW format: 1 = Monday, 2 = Tuesday ... 7 = Sunday */ int convertToSQDOW(int dow) { if(dow == 0) dow = 7; return(dow); } }; // create variable for class instance (required) CSQTime* SQTime; //+------------------------------------------------------------------+ bool sqEvaluateFuzzySignal(int conditionsCount, int minTrueConditions) { bool signalValue = false; int trueConditionsCount = 0; if(minTrueConditions <= 0) { minTrueConditions = 1; } for(int i=0; i<conditionsCount; i++) { bool value = cond[i]; if(value) { trueConditionsCount++; } if(trueConditionsCount >= minTrueConditions) { signalValue = true; break; } } return(signalValue); } //+------------------------------------------------------------------+ string correctSymbol(string symbol){ if(symbol == "NULL" || symbol == "Current" || symbol == "Same as main chart") { return Symbol(); } else return symbol; } //+------------------------------------------------------------------+ double sqFixMarketPrice(double price, string symbol){ symbol = correctSymbol(symbol); double tickSize = MarketInfo(symbol, MODE_TICKSIZE); if(tickSize == 0){ return price; } int digits = (int) MarketInfo(symbol, MODE_DIGITS); double finalPrice = tickSize * MathRound(NormalizeDouble(price, digits) / tickSize); return NormalizeDouble(finalPrice, digits); } //+------------------------------------------------------------------+ bool sqIsUptrend(string symbol, int timeframe, int method) { if(method == 0) { return (iClose(symbol, timeframe, 1) > sqMA(symbol, timeframe, 200, 0, MODE_SMA, PRICE_CLOSE, 1)); } return(false); } //+------------------------------------------------------------------+ bool sqIsDowntrend(string symbol, int timeframe, int method) { if(method == 0) { return (iClose(symbol, timeframe, 1) < sqMA(symbol, timeframe, 200, 0, MODE_SMA, PRICE_CLOSE, 1)); } return(false); } //+------------------------------------------------------------------+ int sqGetMonthLastTradingDay(string symbol, int timeframe, bool includeWeekends) { datetime barTime = iTime(symbol, timeframe, 0); datetime lastTradingDate = SQTime.setDayOfMonth(barTime, SQTime.getDaysInMonth(barTime)); if(!includeWeekends) { if(TimeDayOfWeek(lastTradingDate) == 6) { lastTradingDate = SQTime.addDays(lastTradingDate, -1); } else if(TimeDayOfWeek(lastTradingDate) == 0) { lastTradingDate = SQTime.addDays(lastTradingDate, -2); } } return TimeDay(lastTradingDate); } //+------------------------------------------------------------------+ datetime monthFirstTradingDay = 0; bool sqIsMonthFirstTradingDay(string symbol, int timeframe, bool includeWeekends) { datetime date = SQTime.getDateInMs(iTime(symbol, timeframe, 0)); if(monthFirstTradingDay == 0) { monthFirstTradingDay = date; } if(SQTime.getMonth(monthFirstTradingDay)!=SQTime.getMonth(date)) { if(!includeWeekends) { if(TimeDayOfWeek(date) != 6 && TimeDayOfWeek(date) != 0) { monthFirstTradingDay = date; } } else { monthFirstTradingDay = date; } } return monthFirstTradingDay==date; } //+------------------------------------------------------------------+ bool isMarketClosed(string symbol){ return !IsTesting() && !IsOptimization() && MarketInfo(symbol, MODE_TRADEALLOWED) == 0; } //+------------------------------------------------------------------+ double fixLotSize(string symbol, double size){ string correctedSymbol = correctSymbol(symbol); double Smallest_Lot = MarketInfo(correctedSymbol, MODE_MINLOT); double Largest_Lot = MarketInfo(correctedSymbol, MODE_MAXLOT); double LotStep = MarketInfo(correctedSymbol, MODE_LOTSTEP); double mod = MathMod(size, LotStep); double finalSize = size; if(MathAbs(mod - LotStep) > 0.000001){ finalSize -= mod; } if(finalSize < Smallest_Lot){ Verbose("Calculated lot size (", DoubleToStr(finalSize), ") is lower than minimum possible (", DoubleToStr(Smallest_Lot), "). Using minimum lot size..."); return Smallest_Lot; } else if(finalSize > Largest_Lot){ Verbose("Calculated lot size (", DoubleToStr(finalSize), ") is larger than maximum possible (", DoubleToStr(Largest_Lot), "). Using maximum lot size..."); return Largest_Lot; } else { return finalSize; } } double roundValue(double value){ return NormalizeDouble(value + 0.0000000001, 6); } //+------------------------------------------------------------------+ int sqFixRanges(int value, int min, int max, int defaultVal) { if(value < min || value > max) { return (defaultVal); } return value; } //+------------------------------------------------------------------+ double sqBarRange(string symbol, int timeframe, int shift) { double range; if(symbol == "NULL" || symbol == "Current") { range = iHigh(NULL, timeframe, shift) - iLow(NULL, timeframe, shift); } else { range = iHigh(symbol, timeframe, shift) - iLow(symbol, timeframe, shift); } return roundValue(range); } //+------------------------------------------------------------------+ double sqHeikenAshi(string symbol, int timeframe, string mode, int shift) { if(symbol == "NULL" || symbol == "Current") { if(mode == "Open") { return(NormalizeDouble(iCustom(NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 2, shift), 6)); } if(mode == "Close") { return(NormalizeDouble(iCustom(NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 3, shift), 6)); } if(mode == "High") { return(NormalizeDouble(MathMax(iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6)); } if(mode == "Low") { return(NormalizeDouble(MathMin(iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6)); } } else { if(mode == "Open") { return(NormalizeDouble(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 2, shift), 6)); } if(mode == "Close") { return(NormalizeDouble(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 3, shift), 6)); } if(mode == "High") { return(NormalizeDouble(MathMax(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6)); } if(mode == "Low") { return(NormalizeDouble(MathMin(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6)); } } return(-1); } //+------------------------------------------------------------------+ double sqBiggestRange(string symbol, int timeframe, int period, int shift) { double maxnum = -100000000; double range; for(int i=shift; i<shift+period; i++) { if(symbol == "NULL" || symbol == "Current") { range = iHigh(NULL, timeframe, i) - iLow(NULL, timeframe, i); } else { range = iHigh(symbol, timeframe, i) - iLow(symbol, timeframe, i); } if(range > maxnum) { maxnum = range; } } return roundValue(maxnum); } //+------------------------------------------------------------------+ double sqSmallestRange(string symbol, int timeframe, int period, int shift) { double minnum = 100000000; double range; for(int i=shift; i<shift+period; i++) { if(symbol == "NULL" || symbol == "Current") { range = iHigh(NULL, timeframe, i) - iLow(NULL, timeframe, i); } else { range = iHigh(symbol, timeframe, i) - iLow(symbol, timeframe, i); } if(range < minnum) { minnum = range; } } return roundValue(minnum); } //+------------------------------------------------------------------+ double sqMA(string symbol, int timeframe, int ma_period, int ma_shift, int ma_method, int applied_price, int shift) { ma_method = sqFixRanges(ma_method, 0, 3, 0); applied_price = sqFixRanges(applied_price, 0, 6, 0); return roundValue(iMA(symbol, timeframe, ma_period, ma_shift, ma_method, applied_price, shift)); } //+------------------------------------------------------------------+ double sqTEMA(string symbol, int timeframe, int ma_period, int applied_price, int shift) { return roundValue(iCustom(symbol, timeframe, "SqTEMA", ma_period, applied_price, 0, shift)); } //+------------------------------------------------------------------+ double sqIchimoku(string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int line, int shift) { return roundValue(iCustom(symbol, timeframe, "SqIchimoku", tenkanPeriod, kijunPeriod, senkouPeriod, line, shift)); } //+------------------------------------------------------------------+ double sqAroon(string symbol, int timeframe, int period, int line, int shift) { return roundValue(iCustom(symbol, timeframe, "SqAroon", period, false, false, line, shift)); } //+------------------------------------------------------------------+ double sqBBWidthRatio(string symbol, int timeframe, int period, double deviation, int appliedPrice, int shift) { return roundValue(iCustom(symbol, timeframe, "SqBBWidthRatio", period, deviation, appliedPrice, 0, shift)); } //+------------------------------------------------------------------+ double sqAvgVolume(string symbol, int timeframe, int period, int shift) { return roundValue(iCustom(symbol, timeframe, "SqAvgVolume", period, 1, shift)); } //+------------------------------------------------------------------+ double sqFibo(string symbol, int timeframe, int fiboRange, double fiboLevel) { fiboRange = sqFixRanges(fiboRange, 1, 7, 1); return roundValue(iCustom(symbol, timeframe, "SqFibo", fiboRange, fiboLevel, 0, 0, 0)); } //+------------------------------------------------------------------+ double sqLinReg(string symbol, int timeframe, int period, int line, int shift) { return roundValue(iCustom(symbol, timeframe, "SqLinReg", period, line, 0, shift)); } //+------------------------------------------------------------------+ double sqPivots(string symbol, int timeframe, int startHour, int startMinute, int line, int shift) { return roundValue(iCustom(symbol, timeframe, "SqPivots", startHour, startMinute, line, shift)); } //+------------------------------------------------------------------+ double sqQQE(string symbol, int timeframe, int rsiPeriod, int sF, double wF, int line, int shift) { return roundValue(iCustom(symbol, timeframe, "SqQQE", rsiPeriod, sF, wF, line, shift)); } //+------------------------------------------------------------------+ double sqKeltnerChannel(string symbol, int timeframe, int period, double Deviation, int line, int shift) { return roundValue(iCustom(symbol, timeframe, "SqKeltnerChannel", period, Deviation, line, shift)); } //+------------------------------------------------------------------+ double sqMTKeltnerChannel(string symbol, int timeframe, int period, double Deviation, int line, int shift) { return roundValue(iCustom(symbol, timeframe, "SqMTKeltnerChannel", period, Deviation, line, shift)); } //+------------------------------------------------------------------+ double sqRSI(string symbol, int timeframe, int period, int applied_price, int shift) { return roundValue(iRSI(symbol, timeframe, period, applied_price, shift)); } //+------------------------------------------------------------------+ double sqCCI(string symbol, int timeframe, int period, int applied_price, int shift) { return roundValue(iCCI(symbol, timeframe, period, applied_price, shift)); } //+------------------------------------------------------------------+ double sqAC(string symbol, int timeframe, int shift) { return roundValue(iAC(symbol, timeframe, shift)); } //+------------------------------------------------------------------+ double sqADX(string symbol, int timeframe, int period, int line, int shift) { return roundValue(iCustom(symbol, timeframe, "SqADX", period, line, shift)); } //+------------------------------------------------------------------+ double sqATR(string symbol, int timeframe, int period, int shift) { return roundValue(iCustom(symbol, timeframe, "SqATR", period, 0, shift)); } //+------------------------------------------------------------------+ double sqAO(string symbol, int timeframe, int shift) { return roundValue(iAO(symbol, timeframe, shift)); } //+------------------------------------------------------------------+ double sqBearsPower(string symbol, int timeframe, int period, int applied_price, int shift) { return roundValue(iBearsPower(symbol, timeframe, period, applied_price, shift)); } //+------------------------------------------------------------------+ double sqBullsPower(string symbol, int timeframe, int period, int applied_price, int shift) { return roundValue(iBullsPower(symbol, timeframe, period, applied_price, shift)); } //+------------------------------------------------------------------+ double sqDeMarker(string symbol, int timeframe, int period, int shift) { return roundValue(iDeMarker(symbol, timeframe, period, shift)); } //+------------------------------------------------------------------+ double sqMACD(string symbol, int timeframe, int fast_ema_period, int slow_ema_period, int signal_period, int applied_price, int mode, int shift) { return roundValue(iMACD(symbol, timeframe, fast_ema_period, slow_ema_period, signal_period, applied_price, mode, shift)); } //+------------------------------------------------------------------+ double sqMomentum(string symbol, int timeframe, int period, int applied_price, int shift) { return roundValue(iMomentum(symbol, timeframe, period, applied_price, shift)); } //+------------------------------------------------------------------+ double sqStochastic(string symbol, int timeframe, int Kperiod, int Dperiod, int slowing, int method, int price_field, int mode, int shift) { price_field = sqFixRanges(price_field, 0, 1, 0); method = sqFixRanges(method, 0, 3, 0); return roundValue(iCustom(symbol, timeframe, "SqStochastic", Kperiod, Dperiod, slowing, method, price_field, mode, shift)); } //+------------------------------------------------------------------+ double sqOsMA(string symbol, int timeframe, int fast_ema_period, int slow_ema_period, int signal_period, int applied_price, int shift) { return roundValue(iOsMA(symbol, timeframe, fast_ema_period, slow_ema_period, signal_period, applied_price, shift)); } //+------------------------------------------------------------------+ double sqBands(string symbol, int timeframe, int period, double deviation, int bands_shift, int applied_price, int mode, int shift) { return roundValue(iBands(symbol, timeframe, period, deviation, bands_shift, applied_price, mode+1, shift)); } //+------------------------------------------------------------------+ double sqBBRange(string symbol, int timeframe, int period, double deviation, int applied_price, int shift) { return roundValue(iBands(symbol, timeframe, period, deviation, 0, applied_price, 1, shift) - iBands(symbol, timeframe, period, deviation, 0, applied_price, 2, shift)); } //+------------------------------------------------------------------+ double sqSAR(string symbol, int timeframe, double step, double maximum, int shift) { return roundValue(iCustom(symbol, timeframe, "SqParabolicSAR", step, maximum, 0, shift)); //return roundValue(iSAR(symbol, timeframe, step, maximum, shift)); } //+------------------------------------------------------------------+ double sqStdDev(string symbol, int timeframe, int ma_period, int ma_shift, int ma_method, int applied_price, int shift) { return roundValue(iStdDev(symbol, timeframe, ma_period, ma_shift, ma_method, applied_price, shift)); } //+------------------------------------------------------------------+ double sqHighestInRange(string symbol, int timeframe, string timeFrom, string timeTo, int shift) { return roundValue(iCustom(symbol, timeframe, "SqHighestInRange", timeFrom, timeTo, 0, shift)); } //+------------------------------------------------------------------+ double sqLowestInRange(string symbol, int timeframe, string timeFrom, string timeTo, int shift) { return roundValue(iCustom(symbol, timeframe, "SqLowestInRange", timeFrom, timeTo, 0, shift)); } //+------------------------------------------------------------------+ double sqFractal(string symbol, int timeframe, int fractal, int bufferIndex, int shift) { return roundValue(iCustom(symbol, timeframe, "SqFractal", fractal, bufferIndex, shift)); } //+------------------------------------------------------------------+ bool sqIchimokuChikouSpanCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) { double chikouSpan1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 4, shift+1); double chikouSpan0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 4, shift); double c = iClose(symbol, timeframe, shift); double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift); double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift); if(kumoBottom > kumoTop) { double temp = kumoBottom; kumoBottom = kumoTop; kumoTop = temp; } signalStrength = sqFixRanges(signalStrength, 0, 2, 1); bool signal; if(bullishOrBearish == -1) { // bearish; signal = (chikouSpan1 >= c) && (chikouSpan0 < c) && (chikouSpan1 > chikouSpan0); if(signalStrength == 2) { // for strong signal the cross should happen below kumo cloud signal = signal && (c < kumoBottom); } else if(signalStrength == 1) { // for neutral signal the cross should happen in kumo cloud signal = signal && (c < kumoTop); } else if(signalStrength == 0) { // do nothing, if there is cross signal is always at least weak } else { return false;; } return signal; } else if(bullishOrBearish == 1) { // bullish signal = (chikouSpan1 <= c) && (chikouSpan0 > c) && (chikouSpan1 < chikouSpan0); if(signalStrength == 2) { // for strong signal the cross should happen above kumo cloud signal = signal && (c > kumoTop); } else if(signalStrength == 1) { // for neutral signal the cross should happen in kumo cloud signal = signal && (c > kumoBottom); } else if(signalStrength == 0) { // do nothing, if there is cross signal is always at least weak } else { return false; } return signal; } else { return false; } } //+------------------------------------------------------------------+ bool sqIchimokuSenkouSpanCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) { double senkouSpanA1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift+1); double senkouSpanA0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift); double senkouSpanB1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift+1); double senkouSpanB0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift); double c = iClose(symbol, timeframe, shift); double kumoTop = MathMax(senkouSpanA0, senkouSpanB0); double kumoBottom = MathMin(senkouSpanA0, senkouSpanB0); bool signal; signalStrength = sqFixRanges(signalStrength, 0, 2, 1); if(bullishOrBearish == -1) { // bearish; signal = (senkouSpanA1 > senkouSpanB1) && (senkouSpanA0 < senkouSpanB0); if(signalStrength == 2) { // for strong signal the cross should happen below kumo cloud signal = signal && (c < kumoBottom); } else if(signalStrength == 1) { // for neutral signal the cross should happen in kumo cloud signal = signal && (c < kumoTop); } else if(signalStrength == 0) { // do nothing, if there is cross signal is always at least weak } else { return false;; } return signal; } else if(bullishOrBearish == 1) { // bullish signal = (senkouSpanA1 < senkouSpanB1) && (senkouSpanA0 > senkouSpanB0); if(signalStrength == 2) { // for strong signal the cross should happen above kumo cloud signal = signal && (c > kumoTop); } else if(signalStrength == 1) { // for neutral signal the cross should happen in kumo cloud signal = signal && (c > kumoBottom); } else if(signalStrength == 0) { // do nothing, if there is cross signal is always at least weak } else { return false; } return signal; } else { return false; } } //+------------------------------------------------------------------+ bool sqIchimokuKijunSenCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) { double o = iOpen(symbol, timeframe, shift); double c = iClose(symbol, timeframe, shift); double kijun = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 1, shift); double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift); double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift); if(kumoBottom > kumoTop) { double temp = kumoBottom; kumoBottom = kumoTop; kumoTop = temp; } bool signal; signalStrength = sqFixRanges(signalStrength, 0, 2, 1); if(bullishOrBearish == -1) { // bearish; signal = (o > kijun) && c < kijun; if(signalStrength == 2) { // for strong signal the cross should happen below kumo cloud signal = signal && (kijun < kumoBottom); } else if(signalStrength == 1) { // for neutral signal the cross should happen in kumo cloud signal = signal && (kijun < kumoTop); } else if(signalStrength == 0) { // do nothing, if there is cross signal is always at least weak } else { return false;; } return signal; } else if(bullishOrBearish == 1) { // bullish signal = (o < kijun) && c > kijun; if(signalStrength == 2) { // for strong signal the cross should happen above kumo cloud signal = signal && (kijun > kumoTop); } else if(signalStrength == 1) { // for neutral signal the cross should happen in kumo cloud signal = signal && (kijun > kumoBottom); } else if(signalStrength == 0) { // do nothing, if there is cross signal is always at least weak } else { return false; } return signal; } else { return false; } } //+------------------------------------------------------------------+ bool sqIchimokuTenkanKijunCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) { double tenkan1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 0, shift+1); double tenkan0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 0, shift); double kijun1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 1, shift+1); double kijun0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 1, shift); double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift); double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift); if(kumoBottom > kumoTop) { double temp = kumoBottom; kumoBottom = kumoTop; kumoTop = temp; } bool signal; signalStrength = sqFixRanges(signalStrength, 0, 2, 1); if(bullishOrBearish == -1) { // bearish; signal = (tenkan1 > kijun1) && tenkan0 < kijun0; if(signalStrength == 2) { // for strong signal the cross should happen below kumo cloud signal = signal && (tenkan0 < kumoBottom); } else if(signalStrength == 1) { // for neutral signal the cross should happen in kumo cloud signal = signal && (tenkan0 < kumoTop); } else if(signalStrength == 0) { // do nothing, if there is cross signal is always at least weak } else { return false;; } return signal; } else if(bullishOrBearish == 1) { // bullish signal = (tenkan1 < kijun1) && tenkan0 > kijun0; if(signalStrength == 2) { // for strong signal the cross should happen above kumo cloud signal = signal && (tenkan0 > kumoTop); } else if(signalStrength == 1) { // for neutral signal the cross should happen in kumo cloud signal = signal && (tenkan0 > kumoBottom); } else if(signalStrength == 0) { // do nothing, if there is cross signal is always at least weak } else { return false; } return signal; } else { return false; } } //+------------------------------------------------------------------+ bool sqIchimokuKumoBreakout(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift) { double o = iOpen(symbol, timeframe, shift); double c = iClose(symbol, timeframe, shift); double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift); double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift); if(kumoBottom > kumoTop) { double temp = kumoBottom; kumoBottom = kumoTop; kumoTop = temp; } bool signal; if(bullishOrBearish == -1) { // bearish; signal = (o > kumoBottom) && c < kumoBottom; return signal; } else if(bullishOrBearish == 1) { // bullish signal = (o < kumoTop) && c > kumoTop; return signal; } else { return false; } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ // ExitMethods includes //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ // Move Stop Loss to Break Even void sqManageSL2BE(int ticket) { double val = sqGetGlobalVariable(ticket, "MoveSL2BE"); if(val == 0) { return; } if(!OrderSelect(ticket, SELECT_BY_TICKET)) { return; } double moveSLAtValue = sqGetValueByIdentification((string) val); if(moveSLAtValue > 0) { double newSL = 0; int error; int valueType = (int) sqGetGlobalVariable(ticket, "MoveSL2BEType"); int orderType = OrderType(); int digits = (int) MarketInfo(OrderSymbol(), MODE_DIGITS); if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) { if(valueType == SLPTTYPE_RANGE) { moveSLAtValue = Bid - moveSLAtValue; } } else { if(valueType == SLPTTYPE_RANGE) { moveSLAtValue = Ask + moveSLAtValue; } } moveSLAtValue = NormalizeDouble(moveSLAtValue, digits); double addPips = NormalizeDouble(sqGetValueByIdentification((string) sqGetGlobalVariable(ticket, "SL2BEAddPips")), digits); double currentSL = OrderStopLoss(); if(orderType == OP_BUY) { newSL = NormalizeDouble(OrderOpenPrice() + addPips, digits); if ((OrderOpenPrice() <= moveSLAtValue || sqDoublesAreEqual(OrderOpenPrice(), moveSLAtValue)) && (currentSL == 0 || currentSL < newSL) && !sqDoublesAreEqual(currentSL, newSL)) { Verbose("Moving SL 2 BE for order with ticket: ", IntegerToString(OrderTicket()), " to :", DoubleToString(newSL)); if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit())) { error = GetLastError(); Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ", DoubleToString(currentSL)); } } } else { // orderType == OP_SELL newSL = NormalizeDouble(OrderOpenPrice() - addPips, digits); if ((OrderOpenPrice() >= moveSLAtValue || sqDoublesAreEqual(OrderOpenPrice(), moveSLAtValue)) && (currentSL == 0 || currentSL > newSL) && !sqDoublesAreEqual(currentSL, newSL)) { Verbose("Moving SL 2 BE for order with ticket: ", IntegerToString(OrderTicket()), " to :", DoubleToString(newSL)); if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit())) { error = GetLastError(); Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ", DoubleToString(currentSL)); } } } } } // Trailing Stop void sqManageTrailingStop(int ticket) { double val = sqGetGlobalVariable(ticket, "TrailingStop"); if(val == 0) { return; } if(!OrderSelect(ticket, SELECT_BY_TICKET)) { return; } double tsValue = sqGetValueByIdentification((string) val); if(tsValue > 0) { double plValue; int error; int valueType = (int) sqGetGlobalVariable(ticket, "TrailingStopType"); int orderType = OrderType(); int digits = (int) MarketInfo(OrderSymbol(), MODE_DIGITS); if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) { if(valueType == SLPTTYPE_RANGE) { tsValue = Bid - tsValue; } } else { if(valueType == SLPTTYPE_RANGE) { tsValue = Ask + tsValue; } } tsValue = NormalizeDouble(tsValue, digits); double tsActivation = NormalizeDouble(sqGetValueByIdentification((string) sqGetGlobalVariable(ticket, "TrailingActivation")), digits); double currentSL = OrderStopLoss(); if(orderType == OP_BUY) { plValue = NormalizeDouble(Bid - OrderOpenPrice(), digits); if ((plValue >= tsActivation || sqDoublesAreEqual(plValue, tsActivation)) && (currentSL == 0 || currentSL < tsValue) && !sqDoublesAreEqual(currentSL, tsValue)) { Verbose("Moving trailing stop for order with ticket: ", IntegerToString(OrderTicket()), " to :", DoubleToString(tsValue)); if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), tsValue, OrderTakeProfit())) { error = GetLastError(); Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ", DoubleToString(currentSL)); } } } else { // orderType == OP_SELL plValue = NormalizeDouble(OrderOpenPrice() - Ask, digits); if ((plValue >= tsActivation || sqDoublesAreEqual(plValue, tsActivation)) && (currentSL == 0 || currentSL > tsValue) && !sqDoublesAreEqual(currentSL, tsValue)) { Verbose("Moving trailing stop for order with ticket: ", IntegerToString(OrderTicket()), " to :", DoubleToString(tsValue)); if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), tsValue, OrderTakeProfit())) { error = GetLastError(); Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ", DoubleToString(currentSL)); } } } } } void sqManageExitAfterXBars(int ticket) { int exitBars = (int) sqGetGlobalVariable(ticket, "ExitAfterBars"); if(exitBars > 0) { if (sqGetOpenBarsForOrder(ticket, exitBars+10) >= exitBars) { Verbose("Exit After ", IntegerToString(exitBars), "bars - closing order with ticket: ", IntegerToString(OrderTicket())); sqClosePositionAtMarket(OrderLots()); } } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ // Trading Options includes //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ class CTradingOption { public: virtual bool onBarUpdate() = 0; }; //+------------------------------------------------------------------+ class CDontTradeOnWeekends: public CTradingOption { private: datetime thisFridayCloseTime; datetime thisSundayOpenTime; public: CDontTradeOnWeekends() { thisFridayCloseTime = D'1970.01.01'; thisSundayOpenTime = D'1970.01.01'; } //+----------------------------------------------+ virtual bool onBarUpdate() { if(!DontTradeOnWeekends) { return true; } if(!sqIsBarOpen()) { return(true); } datetime currentTime = TimeCurrent(); if(thisFridayCloseTime < 100) { initTimes(currentTime, 0); } if(currentTime < thisFridayCloseTime) { // trade normally return true; } if(currentTime < thisSundayOpenTime) { // do not allow opening new positions until sunday. // returning false means there will be no more processing on this tick. // this is what we want because we don't want to be trading after close of all positions return false; } else { // new week starting initTimes(currentTime, DayOfWeek() == 0 ? 1 : 0); return true; } } //+----------------------------------------------+ void initTimes(datetime currentTime, int addDays) { if(addDays > 0) { thisFridayCloseTime = SQTime.addDays(currentTime, addDays); } else { thisFridayCloseTime = currentTime; } // set time of EOD thisFridayCloseTime = SQTime.setDayOfWeek(thisFridayCloseTime, (FridayCloseTime == "00:00" || FridayCloseTime == "0:00") ? SATURDAY : FRIDAY); thisFridayCloseTime = SQTime.setHHMM(thisFridayCloseTime, FridayCloseTime); thisSundayOpenTime = SQTime.setDayOfWeek(currentTime, SUNDAY); thisSundayOpenTime = SQTime.setHHMM(thisSundayOpenTime, SundayOpenTime); } }; // create variable for class instance (required) CDontTradeOnWeekends* objDontTradeOnWeekends;class CExitAtEndOfDay : public CTradingOption { private: datetime dailyEODExitTime; datetime EODTime; bool closedThisDay; public: CExitAtEndOfDay() { dailyEODExitTime = D'1970.01.01'; EODTime = D'1970.01.01'; closedThisDay = false; } //+----------------------------------------------+ virtual bool onBarUpdate() { if(!ExitAtEndOfDay) { return(true); } onTick(); if(!sqIsBarOpen()) { return(true); } datetime currentTime = TimeCurrent(); if(currentTime > EODTime) { //it is a new day initTimesForCurrentDay(currentTime); } if(currentTime >= dailyEODExitTime) { // returning false means there will be no more processing on this tick // this is what we want because we don't want to be trading after close of all positions return(false); } return(true); } //------------------------------------------------------------------------ virtual void onTick() { if(!ExitAtEndOfDay) { return; } datetime currentTime = TimeCurrent(); datetime currentTimeDayStart = SQTime.correctDayStart(currentTime); datetime currentTimeDayEnd = SQTime.correctDayEnd(currentTime); if(!closedThisDay && currentTime >= dailyEODExitTime) { // we should close all positions at midnight, so close them at the first tick of a new day for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS)) { if(!checkMagicNumber(OrderMagicNumber())) continue; bool isLiveOrder = OrderType() == OP_BUY || OrderType() == OP_SELL; //Close all orders at the end of a day. When there is a data gap, on the first tick of new day close all pending orders and orders filled before current day start if(currentTimeDayEnd == EODTime || !isLiveOrder || OrderOpenTime() < currentTimeDayStart) { if(isLiveOrder){ sqClosePositionAtMarket(OrderLots()); } else { sqDeletePendingOrder(OrderTicket()); } } } } closedThisDay = true; } } //+----------------------------------------------+ void initTimesForCurrentDay(datetime currentTime) { // set end time of the current day (so that we now when new day starts) EODTime = SQTime.correctDayEnd(currentTime); // set time of EOD if(EODExitTime == "00:00" || EODExitTime == "0:00"){ dailyEODExitTime = EODTime; } else { dailyEODExitTime = SQTime.setHHMM(currentTime, EODExitTime); } closedThisDay = false; } }; // create variable for class instance (required) CExitAtEndOfDay* objExitAtEndOfDay; class CExitOnFriday : public CTradingOption { private: datetime thisFridayExitTime; datetime thisSundayBeginTime; datetime EOFDayTime; bool closedThisWeek; public: CExitOnFriday() { thisFridayExitTime = D'1970.01.01'; thisSundayBeginTime = D'1970.01.01'; closedThisWeek = false; } //+----------------------------------------------+ virtual bool onBarUpdate() { if(!ExitOnFriday) { return true; } onTick(); if(!sqIsBarOpen()) { return(true); } datetime currentTime = TimeCurrent(); if(thisFridayExitTime < 100) { initFridayExitTime(currentTime, 0); } if(currentTime < thisFridayExitTime) { // trade normally return true; } if(currentTime < thisSundayBeginTime) { // do not allow opening new positions until sunday. // returning false means there will be no more processing on this tick. // this is what we want because we don't want to be trading after close of all positions return false; } else { // new week starting initFridayExitTime(currentTime, DayOfWeek() == 0 ? 1 : 0); return true; } } //------------------------------------------------------------------------ virtual void onTick() { if(!ExitOnFriday) { return; } datetime currentTime = TimeCurrent(); datetime currentTimeDayStart = SQTime.correctDayStart(currentTime); datetime currentTimeDayEnd = SQTime.correctDayEnd(currentTime); if(!closedThisWeek && currentTime >= thisFridayExitTime) { // time is over friday closing time, we should close the positions for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS)) { if(!checkMagicNumber(OrderMagicNumber())) continue; bool isLiveOrder = OrderType() == OP_BUY || OrderType() == OP_SELL; //Close all orders at the end of Friday. When there is a data gap, on the first tick of new day close all pending orders and orders filled before current day start if(currentTimeDayEnd == EOFDayTime || !isLiveOrder || OrderOpenTime() < currentTimeDayStart) { if(isLiveOrder){ sqClosePositionAtMarket(OrderLots()); } else { sqDeletePendingOrder(OrderTicket()); } } } } closedThisWeek = true; } } //+----------------------------------------------+ void initFridayExitTime(datetime currentTime, int addDays) { if(addDays > 0) { thisFridayExitTime = SQTime.addDays(currentTime, addDays); } else { thisFridayExitTime = currentTime; } // set time of EOD thisFridayExitTime = SQTime.setDayOfWeek(thisFridayExitTime, (FridayExitTime == "00:00" || FridayExitTime == "0:00") ? SATURDAY : FRIDAY); thisFridayExitTime = SQTime.setHHMM(thisFridayExitTime, FridayExitTime); EOFDayTime = SQTime.correctDayEnd(thisFridayExitTime); thisSundayBeginTime = SQTime.setDayOfWeek(currentTime, SUNDAY); thisSundayBeginTime = SQTime.correctDayStart(thisSundayBeginTime); closedThisWeek = false; } }; // create variable for class instance (required) CExitOnFriday* objExitOnFriday; class CLimitTimeRange : public CTradingOption { private: datetime dailySignalTimeRangeFrom; datetime dailySignalTimeRangeTo; bool closedThisDay; public: CLimitTimeRange() { closedThisDay = false; } //+----------------------------------------------+ virtual bool onBarUpdate() { if(!LimitTimeRange) { return true; } onTick(); if(!sqIsBarOpen()) { return true; } datetime currentTime = TimeCurrent(); if(currentTime > dailySignalTimeRangeTo) { // it is new day initTimesForCurrentDay(currentTime); } if(currentTime < dailySignalTimeRangeFrom || currentTime >= dailySignalTimeRangeTo) { // time is outside given range // returning false means there will be no more processing on this tick // this is what we want because we don't want to be trading outside of this time range return false; } return true; } //------------------------------------------------------------------------ virtual void onTick() { if(!LimitTimeRange) { return; } datetime currentTime = TimeCurrent(); if(!closedThisDay && ExitAtEndOfRange && currentTime >= dailySignalTimeRangeTo) { for (int cc = OrdersTotal() - 1; cc >= 0; cc--) { if (OrderSelect(cc, SELECT_BY_POS)) { if(!checkMagicNumber(OrderMagicNumber())) continue; bool isLiveOrder = OrderType() == OP_BUY || OrderType() == OP_SELL; if(isLiveOrder){ if(OrderTypeToExit != 2) { // not pending only sqClosePositionAtMarket(OrderLots()); } } else { if(OrderTypeToExit != 1) { // not live only sqDeletePendingOrder(OrderTicket()); } } } } closedThisDay = true; } } //------------------------------------------------------------------------ void initTimesForCurrentDay(datetime currentTime) { // set time of range open dailySignalTimeRangeFrom = SQTime.setHHMM(currentTime, SignalTimeRangeFrom); dailySignalTimeRangeTo = SQTime.setHHMM(currentTime, SignalTimeRangeTo); int timeFrom = getHHMM(SignalTimeRangeFrom); int timeTo = getHHMM(SignalTimeRangeTo); if(timeFrom >= timeTo){ if(getSQTime(currentTime) < timeTo){ dailySignalTimeRangeFrom = SQTime.addDays(dailySignalTimeRangeFrom, -1); } else { dailySignalTimeRangeTo = SQTime.addDays(dailySignalTimeRangeTo, 1); } } else { if(currentTime > dailySignalTimeRangeTo) { dailySignalTimeRangeFrom = SQTime.addDays(dailySignalTimeRangeFrom, 1); dailySignalTimeRangeTo = SQTime.addDays(dailySignalTimeRangeTo, 1); } } closedThisDay = false; } }; // create variable for class instance (required) CLimitTimeRange* objLimitTimeRange; class CMaxDistanceFromMarket : public CTradingOption { private: public: CMaxDistanceFromMarket() { } //+----------------------------------------------+ virtual bool onBarUpdate() { return true; } }; // create variable for class instance (required) CMaxDistanceFromMarket* objMaxDistanceFromMarket; class CMaxTradesPerDay : public CTradingOption { private: int lastHistoryPositionChecked; datetime openTimeToday; datetime EODTime; bool reachedLimitToday; public: CMaxTradesPerDay() { EODTime = D'1970.01.01'; lastHistoryPositionChecked = 0; } //+----------------------------------------------+ virtual bool onBarUpdate() { if(MaxTradesPerDay <= 0) { return true; } datetime currentTime = TimeCurrent(); if(currentTime > EODTime) { // it is new day initTimeForCurrentDay(currentTime); } if(reachedLimitToday) { return false; } if(getNumberOfTradesToday() >= MaxTradesPerDay) { reachedLimitToday = true; return(false); } return true; } //------------------------------------------------------------------------ void initTimeForCurrentDay(datetime currentTime) { // set end time of the current day (so that we now when new day starts) EODTime = SQTime.correctDayEnd(currentTime); openTimeToday = SQTime.correctDayStart(currentTime); reachedLimitToday = false; } //------------------------------------------------------------------------ int getNumberOfTradesToday() { int todayTradesCount = 0; int i = 0; // count closed trades that started today int startAt = lastHistoryPositionChecked -10; if(startAt < 0) { startAt = 0; } for(i=startAt;i<OrdersHistoryTotal();i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && checkMagicNumber(OrderMagicNumber())) { lastHistoryPositionChecked = i; if(OrderOpenTime() >= openTimeToday) { todayTradesCount++; } } } for(i=0; i<OrdersTotal(); i++) { if (OrderSelect(i,SELECT_BY_POS)==true && checkMagicNumber(OrderMagicNumber())) { if(OrderOpenTime() >= openTimeToday) { todayTradesCount++; } } } return todayTradesCount; } }; // create variable for class instance (required) CMaxTradesPerDay* objMaxTradesPerDay; class CMinMaxSLPT : public CTradingOption { private: public: CMinMaxSLPT() { } //+----------------------------------------------+ virtual bool onBarUpdate() { return true; } }; // create variable for class instance (required) CMinMaxSLPT* objMinMaxSLPT; // Money Management - Fixed Size used //============================================================================= // OrderReliable.mqh // // Copyright ? 2006, Derk Wehler (derkwehler@gmail.com) // // This file is simply LibOrderReliable as a header file instead of a library // // In order to read this code most clearly in the Metaeditor, it is advised // that you set your tab settings to 4 (instead of the default 3): // Tools->Options->General Tab, set Tab Size to 4, uncheck "Insert spaces" // // *************************************************************************** // OrderReliable library MIT license // // Copyright (c) 2006 Derk Wehler // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // LICENSE LIMITATION // This MIT license is limited only for use of OrderReliable within // strategies generated by StrategyQuant. Any method from this library // that will be used outside of this source code will be governed // by GPL license. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // *************************************************************************** // *************************************************************************** // // A library for MT4 expert advisors, intended to give more reliable // order handling. This library only concerns the mechanics of sending // orders to the Metatrader server, dealing with transient connectivity // problems better than the standard order sending functions. It is // essentially an error-checking wrapper around the existing transaction // functions. This library provides nothing to help actual trade strategies, // but ought to be valuable for nearly all expert advisors which trade 'live'. // // //============================================================================= // // Contents: // // OrderSendReliable() // This is intended to be a drop-in replacement for OrderSend() // which, one hopes is more resistant to various forms of errors // prevalent with MetaTrader. // // OrderSendReliable2Step() // This function is intended to be used when brokers do not allow // initial stoploss and take-profit settings as part of the initial // market order. After successfully playing an order, it will then // Call OrderModifyReliable() to update the SL and TP settings. // // OrderModifyReliable() // A replacement for OrderModify with more error handling. // // OrderCloseReliable() // A replacement for OrderClose with more error handling. // // OrderCloseReliableMKT() // This function is intended for closing orders ASAP; the // principal difference is that in its internal retry-loop, // it uses the new "Bid" and "Ask" real-time variables as opposed // to the OrderCloseReliable() which uses only the price given upon // entry to the routine. More likely to get the order closed if // price moves, but more likely to "slip" // // OrderDeleteReliable() // A replacement for OrderDelete with more error handling. // //=========================================================================== // CHANGE LOG BEGUN 28 March, 2014 // Prior to this, Source OffSite was used to save changes // Start with revision 32, which is what SOS had as last change // // v32, 28 Mar 14: // Small bug fixes for Build 600 changes // // v33, 25 Apr 16: // Tiny adjustment made to GetOrderDetails() for non-forex pairs // // v34, 21 Jun 16: // Changed SleepRandomTime() to just sleep 200ms // // v35, 20 Jul 16: (important) // Added MySymbolConst2Val(), MySymbolVal2String(), necessary for correct // functioning of GetOrderDetails() // // v36, 23 Apr 19: (Mark Fric, SQ) // Added separate retry_attempts_bad_price variable that can configure repeat // attempts for ERR_INVALID_PRICE and ERR_INVALID_STOPS errors // // 14.10.2020 (Tomas Brynda) - added ERR_MARKET_CLOSED on user requested // "important when using Daily strategies // during roll over market is closed for several seconds" // //=========================================================================== //============================================================================= // OrderSendReliable() // // This is intended to be a drop-in replacement for OrderSend() which, // one hopes, is more resistant to various forms of errors prevalent // with MetaTrader. // // RETURN VALUE: // Ticket number or -1 under some error conditions. // // FEATURES: // * Re-trying under some error conditions, sleeping a random // time defined by an exponential probability distribution. // // * Automatic normalization of Digits // // * Automatically makes sure that stop levels are more than // the minimum stop distance, as given by the server. If they // are too close, they are adjusted. // // * Automatically converts stop orders to market orders // when the stop orders are rejected by the server for // being to close to market. NOTE: This intentionally // applies only to OP_BUYSTOP and OP_SELLSTOP, // OP_BUYLIMIT and OP_SELLLIMIT are not converted to market // orders and so for prices which are too close to current // this function is likely to loop a few times and return // with the "invalid stops" error message. // Note, the commentary in previous versions erroneously said // that limit orders would be converted. Note also // that entering a BUYSTOP or SELLSTOP new order is distinct // from setting a stoploss on an outstanding order; use // OrderModifyReliable() for that. // // * Displays various error messages on the log for debugging. // // ORIGINAL AUTHOR AND DATE: // Matt Kennel, 2006-05-28 // //============================================================================= int OrderSendReliable(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment="", int magic=0, datetime expiration=0, color arrow_color=CLR_NONE) { OrderReliable_Fname = "OrderSendReliable"; int ticket = -1; price = NormalizeDouble(price, Digits); takeprofit = NormalizeDouble(takeprofit, Digits); stoploss = NormalizeDouble(stoploss, Digits); // ======================================================================== // If testing or optimizing, there is no need to use this lib, as the // orders are not real-world, and always get placed optimally. By // refactoring this option to be in this library, one no longer needs // to create similar code in each EA. if (!UseForTesting) { if (IsOptimization() || IsTesting()) { ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color); return(ticket); } } // ======================================================================== // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get information about this order double realPoint = MarketInfo(symbol, MODE_POINT); double adjPoint = realPoint; if (adjPoint == 0.00001 || adjPoint == 0.001) adjPoint *= 10; int digits; double point, M = 0; double bid, ask; double sl, tp; double priceNow = 0; double hasSlippedBy = 0; GetOrderDetails(0, symbol, cmd, digits, point, sl, tp, bid, ask, false); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OrderReliablePrint("Attempted " + OrderTypeToString(cmd) + " " + symbol + ": " + DoubleToStr(volume, 3) + " lots @" + DoubleToStr(price, digits+1) + " sl:" + DoubleToStr(stoploss, digits+1) + " tp:" + DoubleToStr(takeprofit, digits+1)); // Normalize all price / stoploss / takeprofit to the proper # of digits. price = NormalizeDouble(price, digits); stoploss = NormalizeDouble(stoploss, digits); takeprofit = NormalizeDouble(takeprofit, digits); // Check stop levels, adjust if necessary EnsureValidStops(symbol, cmd, price, stoploss, takeprofit); int cnt, cnt_bad_price; GetLastError(); // clear the global variable. int err = 0; bool exit_loop = false; bool limit_to_market = false; bool fixed_invalid_price = false; // Concatenate to comment if enabled double symSpr = MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID); if (AddSpreadToComment) comment = comment + " (Spr: " + DoubleToStr(symSpr / adjPoint, 1) + ")"; // Limit/Stop order............................................................... if (cmd > OP_SELL) { cnt = 0; cnt_bad_price = 0; while (!exit_loop) { // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = // Calculating our own slippage internally should not need to be done for pending orders; see market orders below // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = OrderReliablePrint("About to call OrderSend(), comment = " + comment); ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color); err = GetLastError(); switch (err) { case ERR_NO_ERROR: exit_loop = true; break; // retryable errors case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_TRADE_CONTEXT_BUSY: case ERR_TRADE_TIMEOUT: case ERR_TRADE_DISABLED: case ERR_PRICE_CHANGED: case ERR_REQUOTE: case ERR_MARKET_CLOSED: cnt++; break; case ERR_INVALID_PRICE: case ERR_INVALID_STOPS: cnt++; cnt_bad_price++; break; case ERR_INVALID_TRADE_PARAMETERS: default: // an apparently serious error. exit_loop = true; break; } // end switch if (cnt > retry_attempts) exit_loop = true; if (cnt_bad_price > retry_attempts_bad_price) exit_loop = true; if (exit_loop) { if (!limit_to_market) { if (err != ERR_NO_ERROR && err != ERR_NO_RESULT) OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err)); else if (cnt > retry_attempts) OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts) +"("+IntegerToString(retry_attempts_bad_price)+")"); } } else { OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts)+"("+IntegerToString(retry_attempts_bad_price)+")" + ": Retryable error: " + OrderReliableErrTxt(err)); SleepRandomTime(sleep_time, sleep_maximum); RefreshRates(); } } // We have now exited from loop. if (err == ERR_NO_ERROR || err == ERR_NO_RESULT) { OrderReliablePrint("Ticket #" + IntegerToString(ticket) + ": Successful " + OrderTypeToString(cmd) + " order placed with comment = " + comment + ", details follow."); if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(ticket)); sqOrderPrint(); return(ticket); // SUCCESS! } if (!limit_to_market) { OrderReliablePrint("Failed to execute stop or limit order after " + IntegerToString(retry_attempts) + " retries"); OrderReliablePrint("Failed trade: " + OrderTypeToString(cmd) + " " + DoubleToStr(volume, 2) + " lots " + symbol + "@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss)); OrderReliablePrint("Last error: " + OrderReliableErrTxt(err)); OrderReliablePrint(""); return(-1); } } // end if (limit_to_market) { OrderReliablePrint("Going from stop/limit order to market order because market is too close."); cmd %= 2; if (cmd == OP_BUY) price = ask; else price = bid; } // We now have a market order. err = GetLastError(); // so we clear the global variable. err = 0; ticket = -1; exit_loop = false; // Market order.......................................................... if (cmd == OP_BUY || cmd == OP_SELL) { cnt = 0; cnt_bad_price = 0; while (!exit_loop) { // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = // Get current price and calculate slippage RefreshRates(); if (cmd == OP_BUY) { M = 1.0; priceNow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS)); // Open @ Ask hasSlippedBy = (priceNow - price) / point; // (Adjusted Point) } else if (cmd == OP_SELL) { M = -1.0; priceNow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS)); // Open @ Bid hasSlippedBy = (price - priceNow) / point; // (Adjusted Point) } // Check if slippage is more than caller's maximum allowed if (priceNow != price && hasSlippedBy > slippage) { // Actual price has slipped against us more than user allowed // Log error message, sleep, and try again OrderReliablePrint("Actual Price (Ask for buy, Bid for sell) = " + DoubleToStr(priceNow, Digits+1) + "; Slippage from Requested Price = " + DoubleToStr(hasSlippedBy, 1) + " pips. Retrying..."); err = ERR_PRICE_CHANGED; } else { if (priceNow != price) { // If the price has slipped "acceptably" (either negative or within // "Slippage" param), then we need to adjust the SL and TP accordingly if (stoploss != 0) stoploss += M * hasSlippedBy; if (takeprofit != 0) takeprofit += M * hasSlippedBy; OrderReliablePrint("Actual Price (Ask for buy, Bid for sell) = " + DoubleToStr(priceNow, Digits+1) + "; Requested Price = " + DoubleToStr(price, Digits) + "; Slippage from Requested Price = " + DoubleToStr(hasSlippedBy, 1) + " pips (\'positive slippage\'). Attempting order at market"); } OrderReliablePrint("About to call OrderSend(), comment = " + comment); ticket = OrderSend(symbol, cmd, volume, priceNow, (int)(slippage - hasSlippedBy), stoploss, takeprofit, comment, magic, expiration, arrow_color); err = GetLastError(); } // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = switch (err) { case ERR_NO_ERROR: exit_loop = true; break; case ERR_INVALID_PRICE: if (cmd == OP_BUY) OrderReliablePrint("INVALID PRICE ERROR - Requested Price: " + DoubleToStr(price, Digits) + "; Ask = " + DoubleToStr(MarketInfo(symbol, MODE_ASK), Digits)); else OrderReliablePrint("INVALID PRICE ERROR - Requested Price: " + DoubleToStr(price, Digits) + "; Bid = " + DoubleToStr(MarketInfo(symbol, MODE_BID), Digits)); cnt++; // a retryable error cnt_bad_price++; break; case ERR_INVALID_STOPS: OrderReliablePrint("INVALID STOPS on attempted " + OrderTypeToString(cmd) + " : " + DoubleToStr(volume, 2) + " lots " + " @ " + DoubleToStr(price, Digits) + ", SL = " + DoubleToStr(stoploss, Digits) + ", TP = " + DoubleToStr(takeprofit, Digits)); cnt++; // a retryable error cnt_bad_price++; break; case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_TRADE_CONTEXT_BUSY: case ERR_TRADE_TIMEOUT: case ERR_TRADE_DISABLED: case ERR_PRICE_CHANGED: case ERR_REQUOTE: case ERR_MARKET_CLOSED: cnt++; // a retryable error break; default: // an apparently serious, unretryable error. exit_loop = true; break; } if (cnt > retry_attempts) exit_loop = true; if (cnt_bad_price > retry_attempts_bad_price) exit_loop = true; if (exit_loop) { if (err != ERR_NO_ERROR && err != ERR_NO_RESULT) OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err)); if (cnt > retry_attempts) OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts) +"("+IntegerToString(retry_attempts_bad_price)+")"); } else { OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts) +"("+IntegerToString(retry_attempts_bad_price)+")" + ": Retryable error: " + OrderReliableErrTxt(err)); SleepRandomTime(sleep_time, sleep_maximum); RefreshRates(); } } // We have now exited from loop; if successful, return ticket # if (err == ERR_NO_ERROR || err == ERR_NO_RESULT) { OrderReliablePrint("Ticket #" + IntegerToString(ticket) + ": Successful " + OrderTypeToString(cmd) + " order placed with comment = " + comment + ", details follow."); if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(ticket)); sqOrderPrint(); return(ticket); // SUCCESS! } // If not successful, log and return -1 OrderReliablePrint("Failed to execute OP_BUY/OP_SELL, after " + IntegerToString(retry_attempts) + " retries"); OrderReliablePrint("Failed trade: " + OrderTypeToString(cmd) + " " + DoubleToStr(volume, 2) + " lots " + symbol + "@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss)); OrderReliablePrint("Last error: " + OrderReliableErrTxt(err)); } return(-1); } //============================================================================= // OrderSendReliable2Step() // // Some brokers don't allow the SL and TP settings as part of the initial // market order (Water House Capital). Therefore, this routine will first // place the market order with no stop-loss and take-profit but later // update the order accordingly // // RETURN VALUE: // Same as OrderSendReliable; the ticket number // // NOTES: // Order will not be updated if an error continues during // OrderSendReliableMKT. No additional information will be logged // since OrderSendReliableMKT would have already logged the error // condition // // ORIGINAL AUTHOR AND DATE: // Jack Tomlinson, 2007-05-29 // //============================================================================= int OrderSendReliable2Step(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment="", int magic=0, datetime expiration=0, color arrow_color=CLR_NONE) { OrderReliable_Fname = "OrderSendReliable2Step"; int ticket = -1; double slipped = 0; price = NormalizeDouble(price, Digits); takeprofit = NormalizeDouble(takeprofit, Digits); stoploss = NormalizeDouble(stoploss, Digits); // ======================================================================== // If testing or optimizing, there is no need to use this lib, as the // orders are not real-world, and always get placed optimally. By // refactoring this option to be in this library, one no longer needs // to create similar code in each EA. if (!UseForTesting) { if (IsOptimization() || IsTesting()) { ticket = OrderSend(symbol, cmd, volume, price, slippage, 0, 0, comment, magic, 0, arrow_color); if (!OrderModify(ticket, price, stoploss, takeprofit, expiration, arrow_color)) OrderReliablePrint("Order Modify of Ticket #" + IntegerToString(ticket) + " FAILED"); return(ticket); } } // ======================================================================== OrderReliablePrint("Doing OrderSendReliable, followed by OrderModifyReliable:"); ticket = OrderSendReliable(symbol, cmd, volume, price, slippage, 0, 0, comment, magic, expiration, arrow_color); if (stoploss != 0 || takeprofit != 0) { if (ticket >= 0) { double theOpenPrice = price; if (OrderSelect(ticket, SELECT_BY_TICKET)) { slipped = OrderOpenPrice() - price; theOpenPrice = OrderOpenPrice(); } else OrderReliablePrint("Failed to select ticket #" + IntegerToString(ticket) + " after successful 2step placement; cannot recalculate SL & TP"); if (slipped > 0) { OrderReliablePrint("2step order slipped by: " + DoubleToStr(slipped, Digits) + "; SL & TP modified by same amount"); if (takeprofit != 0) takeprofit += slipped; if (stoploss != 0) stoploss += slipped; } OrderModifyReliable(ticket, theOpenPrice, stoploss, takeprofit, expiration, arrow_color); } } else OrderReliablePrint("Skipping OrderModifyReliable because no SL or TP specified."); return(ticket); } //============================================================================= // OrderModifyReliable() // // This is intended to be a drop-in replacement for OrderModify() which, // one hopes, is more resistant to various forms of errors prevalent // with MetaTrader. // // 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, 2006-05-28 // //============================================================================= bool OrderModifyReliable(int ticket, double price, double stoploss, double takeprofit, datetime expiration, color arrow_color=CLR_NONE) { OrderReliable_Fname = "OrderModifyReliable"; bool result = false; bool non_retryable_error = false; // ======================================================================== // If testing or optimizing, there is no need to use this lib, as the // orders are not real-world, and always get placed optimally. By // refactoring this option to be in this library, one no longer needs // to create similar code in each EA. if (!UseForTesting) { if (IsOptimization() || IsTesting()) { result = OrderModify(ticket, price, stoploss, takeprofit, expiration, arrow_color); return(result); } } // ======================================================================== // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get information about this order string symbol = "ALLOCATE"; // This is so it has memory space allocated int type; int digits; double point; double bid, ask; double sl, tp; GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OrderReliablePrint("Attempted modify of #" + IntegerToString(ticket) + " price:" + DoubleToStr(price, digits+1) + " sl:" + DoubleToStr(stoploss, digits+1) + " tp:" + DoubleToStr(takeprofit, digits+1) + " exp:" + TimeToStr(expiration)); // Below, we call "EnsureValidStops". If the order we are modifying // is a pending order, then we should use the price passed in. But // if it's an open order, the price passed in is irrelevant; we need // to use the appropriate bid or ask, so get those... double prc = price; if (type == OP_BUY) prc = bid; else if (type == OP_SELL) prc = ask; // With the requisite info, we can do error checking on SL & TP prc = NormalizeDouble(prc, digits); price = NormalizeDouble(price, digits); stoploss = NormalizeDouble(stoploss, digits); takeprofit = NormalizeDouble(takeprofit, digits); // If SL/TP are not changing then send in zeroes to EnsureValidStops(), // so that it does not bother to try to change them double newSL = stoploss; double newTP = takeprofit; if (stoploss == sl) newSL = 0; if (takeprofit == tp) newTP = 0; EnsureValidStops(symbol, type, prc, newSL, newTP, false); if (stoploss != sl) stoploss = newSL; if (takeprofit != tp) takeprofit = newTP; int cnt = 0; int cnt_bad_price = 0; int err = GetLastError(); // so we clear the global variable. err = 0; bool exit_loop = false; while (!exit_loop) { result = OrderModify(ticket, price, stoploss, takeprofit, expiration, arrow_color); err = GetLastError(); if (result == true) exit_loop = true; else { switch (err) { case ERR_NO_ERROR: exit_loop = true; OrderReliablePrint("ERR_NO_ERROR received, but OrderClose() returned false; exiting"); break; case ERR_NO_RESULT: // Modification to same value as before // See below for reported result exit_loop = true; break; // Shouldn't be any reason stops are invalid (and yet I've seen it); try again case ERR_INVALID_PRICE: case ERR_INVALID_STOPS: OrderReliablePrint("OrderModifyReliable, ERR_INVALID_STOPS, Broker\'s Min Stop Level (in pips) = " + DoubleToStr(MarketInfo(symbol, MODE_STOPLEVEL) * Point / AdjPoint(symbol), 1)); // EnsureValidStops(symbol, price, stoploss, takeprofit); cnt_bad_price++; case ERR_COMMON_ERROR: case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_TOO_FREQUENT_REQUESTS: case ERR_TRADE_TIMEOUT: // for modify this is a retryable error, I hope. case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_TOO_MANY_REQUESTS: case ERR_TRADE_CONTEXT_BUSY: case ERR_TRADE_DISABLED: case ERR_MARKET_CLOSED: cnt++; // a retryable error break; case ERR_TRADE_MODIFY_DENIED: // This one may be important; have to Ensure Valid Stops AND valid price (for pends) break; case ERR_PRICE_CHANGED: case ERR_REQUOTE: RefreshRates(); continue; // we can apparently retry immediately according to MT docs. default: // an apparently serious, unretryable error. exit_loop = true; non_retryable_error = true; break; } // end switch } if (cnt > retry_attempts) exit_loop = true; if (cnt_bad_price > retry_attempts_bad_price) exit_loop = true; if (!exit_loop) { OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts)+"("+IntegerToString(retry_attempts_bad_price)+")" + ": Retryable error: " + OrderReliableErrTxt(err)); SleepRandomTime(sleep_time, sleep_maximum); RefreshRates(); } else { if (cnt > retry_attempts) OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts)); else if (non_retryable_error) OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err)); } } // we have now exited from loop. if (err == ERR_NO_RESULT) { OrderReliablePrint("Server reported modify order did not actually change parameters."); OrderReliablePrint("Redundant modification: " + IntegerToString(ticket) + " " + symbol + "@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss)); OrderReliablePrint("Suggest modifying code logic to avoid."); } if (result) { OrderReliablePrint("Ticket #" + IntegerToString(ticket) + ": Modification successful, updated trade details follow."); if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(ticket)); sqOrderPrint(); } else { OrderReliablePrint("Failed to execute modify after " + IntegerToString(retry_attempts) + " retries"); OrderReliablePrint("Failed modification: " + IntegerToString(ticket) + " " + symbol + "@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss)); OrderReliablePrint("Last error: " + OrderReliableErrTxt(err)); } return(result); } //============================================================================= // OrderCloseReliable() // // This is intended to be a drop-in replacement for OrderClose() which, // one hopes, is more resistant to various forms of errors prevalent // with MetaTrader. // // 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: // Derk Wehler, 2006-07-19 // //============================================================================= bool OrderCloseReliable(int ticket, double volume, double price, int slippage, color arrow_color=CLR_NONE) { OrderReliable_Fname = "OrderCloseReliable"; bool result = false; bool non_retryable_error = false; // ======================================================================== // If testing or optimizing, there is no need to use this lib, as the // orders are not real-world, and always get placed optimally. By // refactoring this option to be in this library, one no longer needs // to create similar code in each EA. if (!UseForTesting) { if (IsOptimization() || IsTesting()) { result = OrderClose(ticket, volume, price, slippage, arrow_color); return(result); } } // ======================================================================== // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get information about this order string symbol = "ALLOCATE"; // This is so it has memory space allocated int type; int digits; double point; double bid, ask; double sl, tp; GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OrderReliablePrint("Attempted close of #" + IntegerToString(ticket) + " initial price:" + DoubleToStr(price, digits+1) + " lots:" + DoubleToStr(volume, 3) + " slippage:" + IntegerToString(slippage)); if (type != OP_BUY && type != OP_SELL) { OrderReliablePrint("Error: Trying to close ticket #" + IntegerToString(ticket) + ", which is " + OrderTypeToString(type) + ", not OP_BUY or OP_SELL"); return(false); } int cnt = 0; int err = GetLastError(); // so we clear the global variable. err = 0; bool exit_loop = false; double priceNow = 0; double hasSlippedBy = 0; while (!exit_loop) { // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = // Get current price and calculate slippage RefreshRates(); if (type == OP_BUY) { priceNow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS)); // Close @ Bid hasSlippedBy = (price - priceNow) / point; // (Adjusted Point) } else if (type == OP_SELL) { priceNow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS)); // Close @ Ask hasSlippedBy = (priceNow - price) / point; // (Adjusted Point) } // Check if slippage is more than caller's maximum allowed if (priceNow != price && hasSlippedBy > slippage) { // Actual price has slipped against us more than user allowed // Log error message, sleep, and try again OrderReliablePrint("Actual Price (Bid for buy, Ask for sell) Value = " + DoubleToStr(priceNow, Digits) + "; Slippage from Requested Price = " + DoubleToStr(hasSlippedBy, 1) + " pips. Retrying..."); result = false; err = ERR_PRICE_CHANGED; } else { result = OrderClose(ticket, volume, priceNow, (int)(slippage - hasSlippedBy), arrow_color); err = GetLastError(); } // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = if (result == true) exit_loop = true; else { switch (err) { case ERR_NO_ERROR: exit_loop = true; OrderReliablePrint("ERR_NO_ERROR received, but OrderClose() returned false; exiting"); OrderReliablePrint("If order did not actually close, error code is apparently wrong"); break; case ERR_NO_RESULT: exit_loop = true; OrderReliablePrint("ERR_NO_RESULT received, but OrderClose() returned false; exiting"); OrderReliablePrint("If order did not actually close, error code is apparently wrong"); break; case ERR_INVALID_PRICE: OrderReliablePrint("ERR_INVALID_PRICE received, but should not occur since we are refreshing rates"); cnt++; // a retryable error break; case ERR_PRICE_CHANGED: case ERR_COMMON_ERROR: case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_TOO_FREQUENT_REQUESTS: case ERR_TRADE_TIMEOUT: // for close this is a retryable error, I hope. case ERR_TRADE_DISABLED: case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_REQUOTE: case ERR_TOO_MANY_REQUESTS: case ERR_TRADE_CONTEXT_BUSY: case ERR_MARKET_CLOSED: cnt++; // a retryable error break; default: // Any other error is an apparently serious, unretryable error. exit_loop = true; non_retryable_error = true; break; } // end switch } if (cnt > retry_attempts) exit_loop = true; if (exit_loop) { if (cnt > retry_attempts) OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts)); else if (non_retryable_error) OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err)); } else { OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts) + ": Retryable error: " + OrderReliableErrTxt(err)); SleepRandomTime(sleep_time, sleep_maximum); } } // We have now exited from loop if (result || err == ERR_NO_RESULT || err == ERR_NO_ERROR) { if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + " [ Last error: " + OrderReliableErrTxt(err) + " ]"); else if (OrderCloseTime() > 0) // Then it closed ok OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + " [ Last error: " + OrderReliableErrTxt(err) + " ]"); else { OrderReliablePrint("Close result reported success (or failure, but w/ERR_NO_ERROR); yet order remains! Must re-try close from EA logic!"); OrderReliablePrint("Close Failed: Ticket #" + IntegerToString(ticket) + ", Price: " + DoubleToString(price) + ", Slippage: " + DoubleToString(slippage)); OrderReliablePrint("Last error: " + OrderReliableErrTxt(err)); result = false; } } else { OrderReliablePrint("Failed to execute close after " + IntegerToString(cnt-1) + " retries"); OrderReliablePrint("Failed close: Ticket #" + IntegerToString(ticket) + " @ Price: " + DoubleToString(priceNow) + " (Requested Price: " + DoubleToString(price) + "), Slippage: " + IntegerToString(slippage)); OrderReliablePrint("Last error: " + OrderReliableErrTxt(err)); } return(result); } //============================================================================= // OrderCloseReliableMKT() // // This function is intended for closing orders ASAP; the principal // difference is that in its internal retry-loop, it uses the new "Bid" // and "Ask" real-time variables as opposed to the OrderCloseReliable(), // which uses only the price given upon entry to the routine. More likely // to get the order closed if price moves, but more likely to "slip" // // 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: // Derk Wehler, 2009-04-03 // //============================================================================= bool OrderCloseReliableMKT(int ticket, double volume, double price, int slippage, color arrow_color=CLR_NONE) { OrderReliable_Fname = "OrderCloseReliableMKT"; bool result = false; bool non_retryable_error = false; // ======================================================================== // If testing or optimizing, there is no need to use this lib, as the // orders are not real-world, and always get placed optimally. By // refactoring this option to be in this library, one no longer needs // to create similar code in each EA. if (!UseForTesting) { if (IsOptimization() || IsTesting()) { result = OrderClose(ticket, volume, price, slippage, arrow_color); return(result); } } // ======================================================================== // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get information about this order string symbol = "ALLOCATE"; // This is so it has memory space allocated int type; int digits; double point; double bid, ask; double sl, tp; GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OrderReliablePrint("Attempted close of #" + IntegerToString(ticket) + " initial price:" + DoubleToStr(price, digits+1) + " lots:" + DoubleToStr(price, 3) + " slippage:" + IntegerToString(slippage)); if (type != OP_BUY && type != OP_SELL) { OrderReliablePrint("Error: Trying to close ticket #" + IntegerToString(ticket) + ", which is " + OrderTypeToString(type) + ", not OP_BUY or OP_SELL"); return(false); } int cnt = 0; int err = GetLastError(); // so we clear the global variable. err = 0; bool exit_loop = false; double pnow = 0; int slippagenow = 0; while (!exit_loop) { if (type == OP_BUY) { pnow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS)); // we are buying at Ask if (pnow > price) { // Do not allow slippage to go negative; will cause error slippagenow = (int) MathMax(0, slippage - (pnow - price) / point); } } else if (type == OP_SELL) { pnow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS)); // we are buying at Ask if (pnow < price) { // Do not allow slippage to go negative; will cause error slippagenow = (int) MathMax(0, slippage - (price - pnow) / point); } } result = OrderClose(ticket, volume, pnow, slippagenow, arrow_color); err = GetLastError(); if (result == true) exit_loop = true; else { switch (err) { case ERR_NO_ERROR: exit_loop = true; OrderReliablePrint("ERR_NO_ERROR received, but OrderClose() returned false; exiting"); break; case ERR_NO_RESULT: exit_loop = true; OrderReliablePrint("ERR_NO_RESULT received, but OrderClose() returned false; exiting"); break; case ERR_COMMON_ERROR: case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_TOO_FREQUENT_REQUESTS: case ERR_TRADE_TIMEOUT: // for close this is a retryable error, I hope. case ERR_TRADE_DISABLED: case ERR_PRICE_CHANGED: case ERR_INVALID_PRICE: case ERR_OFF_QUOTES: case ERR_BROKER_BUSY: case ERR_REQUOTE: case ERR_TOO_MANY_REQUESTS: case ERR_TRADE_CONTEXT_BUSY: case ERR_MARKET_CLOSED: cnt++; // a retryable error break; default: // Any other error is an apparently serious, unretryable error. exit_loop = true; non_retryable_error = true; break; } // end switch } if (cnt > retry_attempts) exit_loop = true; if (!exit_loop) { OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts)+ ": Retryable error: " + OrderReliableErrTxt(err)); SleepRandomTime(sleep_time, sleep_maximum); } if (exit_loop) { if (cnt > retry_attempts) OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts)); else if (non_retryable_error) OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err)); } } // we have now exited from loop. if (result) { if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + " [ Last error: " + OrderReliableErrTxt(err) + " ]"); else if (OrderCloseTime() > 0) // Then it closed ok OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + " [ Last error: " + OrderReliableErrTxt(err) + " ]"); else { OrderReliablePrint("Close result reported success, but order remains! Must re-try close from EA logic!"); OrderReliablePrint("Close Failed: Ticket #" + IntegerToString(ticket) + ", Price: " + DoubleToString(price) + ", Slippage: " + IntegerToString(slippage)); OrderReliablePrint("Last error: " + OrderReliableErrTxt(err)); result = false; } } else { OrderReliablePrint("Failed to execute close after " + IntegerToString(retry_attempts) + " retries"); OrderReliablePrint("Failed close: Ticket #" + IntegerToString(ticket) + " @ Price: " + DoubleToString(pnow) + " (Initial Price: " + DoubleToString(price) + "), Slippage: " + IntegerToString(slippagenow) + " (Initial Slippage: " + IntegerToString(slippage) + ")"); OrderReliablePrint("Last error: " + OrderReliableErrTxt(err)); } return(result); } //============================================================================= // OrderDeleteReliable() // // This is intended to be a drop-in replacement for OrderDelete() which, // one hopes, is more resistant to various forms of errors prevalent // with MetaTrader. // // 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: // Derk Wehler, 2006-12-21 // //============================================================================= bool OrderDeleteReliable(int ticket, color clr=CLR_NONE) { OrderReliable_Fname = "OrderDeleteReliable"; bool result = false; bool non_retryable_error = false; // ======================================================================== // If testing or optimizing, there is no need to use this lib, as the // orders are not real-world, and always get placed optimally. By // refactoring this option to be in this library, one no longer needs // to create similar code in each EA. if (!UseForTesting) { if (IsOptimization() || IsTesting()) { result = OrderDelete(ticket, clr); return(result); } } // ======================================================================== OrderReliablePrint("Attempted deletion of pending order, #" + IntegerToString(ticket)); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get information about this order string symbol = "ALLOCATE"; // This is so it has memory space allocated int type; int digits; double point; double bid, ask; double sl, tp; GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (type == OP_BUY || type == OP_SELL) { OrderReliablePrint("error: Trying to close ticket #" + IntegerToString(ticket) + ", which is " + OrderTypeToString(type) + ", not OP_BUYSTOP, OP_SELLSTOP, OP_BUYLIMIT, or OP_SELLLIMIT"); return(false); } int cnt = 0; int err = GetLastError(); // so we clear the global variable. err = 0; bool exit_loop = false; while (!exit_loop) { result = OrderDelete(ticket, clr); err = GetLastError(); if (result == true) exit_loop = true; else { switch (err) { case ERR_NO_ERROR: exit_loop = true; OrderReliablePrint("ERR_NO_ERROR received, but OrderDelete() returned false; exiting"); break; case ERR_NO_RESULT: exit_loop = true; OrderReliablePrint("ERR_NO_RESULT received, but OrderDelete() returned false; exiting"); break; case ERR_COMMON_ERROR: case ERR_SERVER_BUSY: case ERR_NO_CONNECTION: case ERR_TOO_FREQUENT_REQUESTS: case ERR_TRADE_TIMEOUT: // for delete this is a retryable error, I hope. case ERR_TRADE_DISABLED: case ERR_OFF_QUOTES: case ERR_PRICE_CHANGED: case ERR_BROKER_BUSY: case ERR_REQUOTE: case ERR_TOO_MANY_REQUESTS: case ERR_TRADE_CONTEXT_BUSY: case ERR_MARKET_CLOSED: cnt++; // a retryable error break; default: // Any other error is an apparently serious, unretryable error. exit_loop = true; non_retryable_error = true; break; } // end switch } if (cnt > retry_attempts) exit_loop = true; if (!exit_loop) { OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts) + ": Retryable error: " + OrderReliableErrTxt(err)); SleepRandomTime(sleep_time, sleep_maximum); } else { if (cnt > retry_attempts) OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts)); else if (non_retryable_error) OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err)); } } // we have now exited from loop. if (result) { OrderReliablePrint("Successful deletion of Ticket #" + IntegerToString(ticket)); return(true); // SUCCESS! } else { OrderReliablePrint("Failed to execute delete after " + IntegerToString(retry_attempts) + " retries"); OrderReliablePrint("Failed deletion: Ticket #" + IntegerToString(ticket)); OrderReliablePrint("Last error: " + OrderReliableErrTxt(err)); } return(result); } //============================================================================= //============================================================================= // Utility Functions //============================================================================= //============================================================================= string OrderReliableErrTxt(int err) { return (IntegerToString(err) + " :: " + ErrorDescription(err)); } // Defaut level is 3 // Use level = 1 to Print all but "Retry" messages // Use level = 0 to Print nothing void OrderReliableSetErrorLevel(int level) { ErrorLevel = level; } void OrderReliablePrint(string s) { // Print to log prepended with stuff; if (ErrorLevel >= 99 || (!(IsTesting() || IsOptimization()))) { if (ErrorLevel > 0) Print(OrderReliable_Fname + " " + OrderReliableVersion + ": " + s); } } void sqOrderPrint() { Print("Ticket: "+IntegerToString(OrderTicket())+" - "+ "OpenTime: "+TimeToString(OrderOpenTime(), TIME_DATE | TIME_MINUTES | TIME_SECONDS)+","+ "Type: "+IntegerToString(OrderType())+","+ "Size: "+DoubleToString(OrderLots())+","+ "Symbol: "+OrderSymbol()+","+ "OpenPrice: "+DoubleToString(OrderOpenPrice())+","+ "SL: "+DoubleToString(OrderStopLoss())+","+ "PT: "+DoubleToString(OrderTakeProfit())); Print("Ticket: "+IntegerToString(OrderTicket())+" (continue) - "+ "CloseTime: "+TimeToString(OrderCloseTime(), TIME_DATE | TIME_MINUTES | TIME_SECONDS)+","+ "ClosePrice: "+DoubleToString(OrderClosePrice())+","+ "Commission: "+DoubleToString(OrderCommission())+","+ "Swap: "+DoubleToString(OrderSwap())+","+ "Profit: "+DoubleToString(OrderProfit())+","+ "Comment: "+OrderComment()+","+ "MagicNumber: "+IntegerToString(OrderMagicNumber())); } string OrderTypeToString(int type) { if (type == OP_BUY) return("BUY"); if (type == OP_SELL) return("SELL"); if (type == OP_BUYSTOP) return("BUY STOP"); if (type == OP_SELLSTOP) return("SELL STOP"); if (type == OP_BUYLIMIT) return("BUY LIMIT"); if (type == OP_SELLLIMIT) return("SELL LIMIT"); return("None (" + IntegerToString(type) + ")"); } //============================================================================= // EnsureValidStops() // // Most MQ4 brokers have a minimum stop distance, which is the number of // pips from price where a pending order can be placed or where a SL & TP // can be placed. THe purpose of this function is to detect when the // requested SL or TP is too close, and to move it out automatically, so // that we do not get ERR_INVALID_STOPS errors. // // FUNCTION COMPLETELY OVERHAULED: // Derk Wehler, 2008-11-08 // //============================================================================= void EnsureValidStops(string symbol, int cmd, double price, double& sl, double& tp, bool isNewOrder=true) { string prevName = OrderReliable_Fname; OrderReliable_Fname = "EnsureValidStops"; double point = MarketInfo(symbol, MODE_POINT); // We only use point for StopLevel, and StopLevel is reported as 10 times // what you expect on a 5-digit broker, so leave it as is. //if (point == 0.001 || point == 0.00001) // point *= 10; double orig_sl = sl; double orig_tp = tp; double new_sl, new_tp; int min_stop_level = (int) MarketInfo(symbol, MODE_STOPLEVEL); double servers_min_stop = min_stop_level * point; double spread = MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID); //Print(" EnsureValidStops: Symbol = " + symbol + ", servers_min_stop = " + servers_min_stop); // Skip if no S/L (zero) if (sl != 0) { if (cmd % 2 == 0) // we are long { // for pending orders, sl/tp can bracket price by servers_min_stop new_sl = price - servers_min_stop; //Print(" EnsureValidStops: new_sl [", new_sl, "] = price [", price, "] - servers_min_stop [", servers_min_stop, "]"); // for market order, sl/tp must bracket bid/ask if (cmd == OP_BUY && isNewOrder) { new_sl -= spread; //Print(" EnsureValidStops: Minus spread [", spread, "]"); } sl = MathMin(sl, new_sl); } else // we are short { new_sl = price + servers_min_stop; // we are short //Print(" EnsureValidStops: new_sl [", new_sl, "] = price [", price, "] + servers_min_stop [", servers_min_stop, "]"); // for market order, sl/tp must bracket bid/ask if (cmd == OP_SELL && isNewOrder) { new_sl += spread; //Print(" EnsureValidStops: Plus spread [", spread, "]"); } sl = MathMax(sl, new_sl); } sl = NormalizeDouble(sl, (int) MarketInfo(symbol, MODE_DIGITS)); } // Skip if no T/P (zero) if (tp != 0) { // check if we have to adjust the stop if (MathAbs(price - tp) <= servers_min_stop) { if (cmd % 2 == 0) // we are long { new_tp = price + servers_min_stop; // we are long tp = MathMax(tp, new_tp); } else // we are short { new_tp = price - servers_min_stop; // we are short tp = MathMin(tp, new_tp); } tp = NormalizeDouble(tp, (int) MarketInfo(symbol, MODE_DIGITS)); } } // notify if changed if (sl != orig_sl) OrderReliablePrint("SL was too close to brokers min distance (" + IntegerToString(min_stop_level) + "); moved SL to: " + DoubleToString(sl)); if (tp != orig_tp) OrderReliablePrint("TP was too close to brokers min distance (" + IntegerToString(min_stop_level) + "); moved TP to: " + DoubleToString(tp)); OrderReliable_Fname = prevName; } //============================================================================= // EnsureValidPendPrice() // // This function is called if OrderSendReliable gets an ERR_INVALID_PRICE // or ERR_INVALID_STOPS error when attempting to place a pending order. // We assume these are signs that the brokers minumum stop distance, which // is what is used for pending distances as well, is too small and the price // is too close to the pending's requested price. Therefore we want to do // one of two things: // // If UseLimitToMarket is enabled, then see if the actual and requested // prices are close enough to be within the requested slippage, and if so // return true to indicate a swap to a market order. // // Otherwise, we move the requested price far enough from current price to // (hopefully) place the pending order, and return false (price, sl & tp // are all I/O params). If this does not work, and the the same error is // received, and the function is called again, it attempts to move the // entry price (and sl & tp) out one more pip at a time. // // RETURN VALUE: // True if calling function should convert this to market order, // otherwise False // // ORIGINAL AUTHOR AND DATE: // Derk Wehler, 2011-05-17 // //============================================================================= bool EnsureValidPendPrice(int err, bool& fixed, string symbol, int cmd, double& price, double& stoploss, double& takeprofit, int slippage, double point, int digits) { OrderReliable_Fname = "EnsureValidPendPrice"; double servers_min_stop = MarketInfo(symbol, MODE_STOPLEVEL) * Point; double old_price, priceNow = 0, hasSlippedBy; // Assume buy pendings relate to Ask, and sell pendings relate to Bid if (cmd % 2 == OP_BUY) priceNow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS)); else if (cmd % 2 == OP_SELL) priceNow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS)); // If we are too close to put in a limit/stop order so go to market. if (MathAbs(priceNow - price) <= servers_min_stop) { if (UseLimitToMarket) { hasSlippedBy = MathAbs(priceNow - price) / point; // (Adjusted Point) // Check if slippage is more than caller's maximum allowed if (priceNow != price && hasSlippedBy > slippage) { // Actual price is too far from requested price to do market order, // and too close to place pending order (because of broker's minimum // stop distance). Therefore, report the problem and try again... OrderReliablePrint("Actual price (Ask for buy, Bid for sell) = " + DoubleToStr(priceNow, Digits) + ", and requested pend price = " + DoubleToStr(priceNow, Digits) + "; slippage between the two = ?" + DoubleToStr(hasSlippedBy, 1) + " pips, which is larger than user specified. Cannot Convert to Market Order."); } else { // Price has moved close enough (within slippage) to requested // pending price that we can go ahead and enter a market position return(true); } } else { if (fixed) { if (cmd == OP_BUYSTOP || cmd == OP_SELLLIMIT) { price += point; if (stoploss > 0) stoploss += point; if (takeprofit > 0) takeprofit += point; OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " Order still has \'" + ErrorDescription(err) + "\', adding 1 pip; new price = " + DoubleToStr(price, Digits)); if (stoploss > 0 || takeprofit > 0) OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately"); } else if (cmd == OP_BUYLIMIT || cmd == OP_SELLSTOP) { price -= point; if (stoploss > 0) stoploss -= point; if (takeprofit > 0) takeprofit -= point; OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " Order still has \'" + ErrorDescription(err) + "\', subtracting 1 pip; new price = " + DoubleToStr(price, digits)); if (stoploss > 0 || takeprofit > 0) OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately"); } } else { if (cmd == OP_BUYLIMIT) { old_price = price; price = priceNow - servers_min_stop; if (stoploss > 0) stoploss += (price - old_price); if (takeprofit > 0) takeprofit += (price - old_price); OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits)); if (stoploss > 0 || takeprofit > 0) OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately"); } else if (cmd == OP_BUYSTOP) { old_price = price; price = priceNow + servers_min_stop; if (stoploss > 0) stoploss += (price - old_price); if (takeprofit > 0) takeprofit += (price - old_price); OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits)); if (stoploss > 0 || takeprofit > 0) OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately"); } else if (cmd == OP_SELLSTOP) { old_price = price; price = priceNow - servers_min_stop; if (stoploss > 0) stoploss -= (old_price - price); if (takeprofit > 0) takeprofit -= (old_price - price); OrderReliablePrint("Pending SellStop has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits)); if (stoploss > 0 || takeprofit > 0) OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately"); } else if (cmd == OP_SELLLIMIT) { old_price = price; price = priceNow + servers_min_stop; if (stoploss > 0) stoploss -= (old_price - price); if (takeprofit > 0) takeprofit -= (old_price - price); OrderReliablePrint("Pending SellLimit has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits)); if (stoploss > 0 || takeprofit > 0) OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately"); } fixed = true; } EnsureValidStops(symbol, cmd, price, stoploss, takeprofit); } } return(false); } //============================================================================= // SleepRandomTime() // // This sleeps a random amount of time defined by an exponential // probability distribution. The mean time, in Seconds is given // in 'mean_time'. // // This is the back-off strategy used by Ethernet. This will // quantize in fiftieths of seconds, so don't call this with a too // small a number. This returns immediately if we are backtesting // and does not sleep. // //============================================================================= void SleepRandomTime(double mean_time, double max_time) { // No need for pauses on tester if (IsTesting()) return; /* // 19Jun16 : Noticed for a long time that when an order fails, // it fails all 10 tries. So try a different tack here and just // sleep a set time per try. Sleep(200); return; */ double tenths = MathCeil(mean_time / 0.1); if (tenths <= 0) return; int maxtenths = (int) MathRound(max_time / 0.1); // 250 double p = 1.0 - 1.0 / tenths; // 0.975 // Always sleep at least some minimum Sleep(20); // Now loop through and sleep 1/10th second a max of // (10 * mean_time) times. But break out "randomly". for (int i = 0; i < maxtenths; i++) { if (MathRand() > p*32768) break; // MathRand() returns in 0..32767 Sleep(20); } } //============================================================================= // Adjusted Point funtion //============================================================================= double AdjPoint(string sym="") { if (sym == "") sym = Symbol(); double ticksize = MarketInfo(sym, MODE_TICKSIZE); if (ticksize == 0.00001 || ticksize == 0.001) ticksize *= 10; return(ticksize); } //============================================================================= // LimitToMarket() // // Setting to toggle what OrderSendReliable does with Stop or Limit orders // that are requested to be placed too close to the current price. // // When set True, it will turn any such conundrum from a stop/limit order // into a simple market order // // When set False, the library will alter the price of the Stop/Limit order\ // just far enough to be able to place the order as a pending order. // //============================================================================= void LimitToMarket(bool limit2market) { UseLimitToMarket = limit2market; } //============================================================================= // OrderReliableUseForTesting() // // Setting to toggle whether this OrderReliable library is used in testing // and optimization. By default, it is set to false, and will thus just pass // orders straight through. // // When set true, it will use the full functions as normally all the time, // including testing / optimization. // //============================================================================= void OrderReliableUseForTesting(bool use) { UseForTesting = use; } //============================================================================= // OrderReliableAddSpreadToComment() // // Setting to toggle whether this to add the current spread to the trade // commment, so that user can monitor variable spread situations on a // per trade basis. // //============================================================================= void OrderReliableAddSpreadToComment(bool use) { AddSpreadToComment = use; } //============================================================================= // GetOrderDetails() // // For some OrderReliable functions (such as Modify), we need to know some // things about the order (such as direction and symbol). To do this, we // need to select the order. However, the caller may already have an order // selected so we need to be responsible and put it back when done. // // Return false if there is a problem, true otherwise. // //============================================================================= bool GetOrderDetails(int ticket, string& symb, int& type, int& digits, double& point, double& sl, double& tp, double& bid, double& ask, bool exists=true) { // If this is existing order, select it and get symbol and type if (exists) { int lastTicket = OrderTicket(); if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) { OrderReliablePrint("OrderSelect() error: " + ErrorDescription(GetLastError())); return(false); } symb = OrderSymbol(); type = OrderType(); tp = OrderTakeProfit(); sl = OrderStopLoss(); // Select back the prior ticket num in case caller was using it. if (lastTicket >= 0) { if (!OrderSelect(lastTicket, SELECT_BY_TICKET, MODE_TRADES)) OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(lastTicket)); } } // Get bid, ask, point & digits bid = NormalizeDouble(MarketInfo(symb, MODE_BID), (int) MarketInfo(symb, MODE_DIGITS)); ask = NormalizeDouble(MarketInfo(symb, MODE_ASK), (int) MarketInfo(symb, MODE_DIGITS)); point = MarketInfo(symb, MODE_POINT); if (point == 0.001 || point == 0.00001) point *= 10; digits = (int) MarketInfo(symb, MODE_DIGITS); // If this is a forex pair (i.e. symbol length == 6), then digits should not be zero if (digits == 0 && StringLen(MySymbolVal2String(MySymbolConst2Val(Symbol()))) == 6) { string prevName = OrderReliable_Fname; OrderReliable_Fname = "GetDigits"; OrderReliablePrint("error: MarketInfo(symbol (" + symb + "), MODE_DIGITS) == 0"); OrderReliable_Fname = prevName; return(false); } else if (exists) { tp = NormalizeDouble(tp, digits); sl = NormalizeDouble(sl, digits); bid = NormalizeDouble(bid, digits); ask = NormalizeDouble(ask, digits); } return(true); } //============================================================================= // 20Jul16: Not sure what BS this is; all this ised to work, but not sure how. // DerksUtils includes OrderReliable, but not vice versa... So copied these // functions from DerksUtils and changed the names. Also, abive, where used, // it WAS: StringLen(MySymbolVal2String(Symbol())) == 6), which was wrong. //============================================================================= int MySymbolConst2Val(string symbol) { // Handle problem of trailing chars on mini accounts. string mySymbol = StringSubstr(symbol,0,6); if (mySymbol == "AUDCAD") return(1); if (mySymbol == "AUDJPY") return(2); if (mySymbol == "AUDNZD") return(3); if (mySymbol == "AUDUSD") return(4); if (mySymbol == "CADJPY") return(5); if (mySymbol == "CHFJPY") return(6); if (mySymbol == "EURAUD") return(7); if (mySymbol == "EURCAD") return(8); if (mySymbol == "EURCHF") return(9); if (mySymbol == "EURGBP") return(10); if (mySymbol == "EURJPY") return(11); if (mySymbol == "EURUSD") return(12); if (mySymbol == "GBPCHF") return(13); if (mySymbol == "GBPJPY") return(14); if (mySymbol == "GBPUSD") return(15); if (mySymbol == "NZDJPY") return(16); if (mySymbol == "NZDUSD") return(17); if (mySymbol == "USDCAD") return(18); if (mySymbol == "USDCHF") return(19); if (mySymbol == "USDJPY") return(20); // These symbols were added 26Sep10 if (mySymbol == "AUDCHF") return(22); if (mySymbol == "AUDDKK") return(23); if (mySymbol == "AUDNOK") return(24); if (mySymbol == "AUDSEK") return(25); if (mySymbol == "CADCHF") return(26); if (mySymbol == "CHFNOK") return(27); if (mySymbol == "EURDKK") return(28); if (mySymbol == "EURNZD") return(29); if (mySymbol == "EURPLN") return(30); if (mySymbol == "EURSEK") return(31); if (mySymbol == "EURSGD") return(32); if (mySymbol == "EURZAR") return(33); if (mySymbol == "GBPAUD") return(34); if (mySymbol == "GBPCAD") return(35); if (mySymbol == "GBPNOK") return(36); if (mySymbol == "GBPNZD") return(37); if (mySymbol == "GBPSGD") return(38); if (mySymbol == "NOKJPY") return(39); if (mySymbol == "NZDCAD") return(40); if (mySymbol == "NZDCHF") return(41); if (mySymbol == "NZDGBP") return(42); if (mySymbol == "SEKJPY") return(43); if (mySymbol == "USDAED") return(44); if (mySymbol == "USDBHD") return(45); if (mySymbol == "USDDKK") return(46); if (mySymbol == "USDEGP") return(47); if (mySymbol == "USDHKD") return(48); if (mySymbol == "USDJOD") return(49); if (mySymbol == "USDKWD") return(50); if (mySymbol == "USDMXN") return(51); if (mySymbol == "USDNOK") return(52); if (mySymbol == "USDPLN") return(53); if (mySymbol == "USDQAR") return(54); if (mySymbol == "USDSAR") return(55); if (mySymbol == "USDSEK") return(56); if (mySymbol == "USDSGD") return(57); if (mySymbol == "USDTHB") return(58); if (mySymbol == "USDZAR") return(59); if (mySymbol == "XAGUSD") return(60); if (mySymbol == "XAUUSD") return(61); // Originally, this was "other"; kept // the same for backward compatability return(21); } string MySymbolVal2String(int val) { if (val == 1) return("AUDCAD"); if (val == 2) return("AUDJPY"); if (val == 3) return("AUDNZD"); if (val == 4) return("AUDUSD"); if (val == 5) return("CADJPY"); if (val == 6) return("CHFJPY"); if (val == 7) return("EURAUD"); if (val == 😎 return("EURCAD"); if (val == 9) return("EURCHF"); if (val == 10) return("EURGBP"); if (val == 11) return("EURJPY"); if (val == 12) return("EURUSD"); if (val == 13) return("GBPCHF"); if (val == 14) return("GBPJPY"); if (val == 15) return("GBPUSD"); if (val == 16) return("NZDJPY"); if (val == 17) return("NZDUSD"); if (val == 18) return("USDCAD"); if (val == 19) return("USDCHF"); if (val == 20) return("USDJPY"); // These symbols were added 26Sep10 if (val == 22) return("AUDCHF"); if (val == 23) return("AUDDKK"); if (val == 24) return("AUDNOK"); if (val == 25) return("AUDSEK"); if (val == 26) return("CADCHF"); if (val == 27) return("CHFNOK"); if (val == 28) return("EURDKK"); if (val == 29) return("EURNZD"); if (val == 30) return("EURPLN"); if (val == 31) return("EURSEK"); if (val == 32) return("EURSGD"); if (val == 33) return("EURZAR"); if (val == 34) return("GBPAUD"); if (val == 35) return("GBPCAD"); if (val == 36) return("GBPNOK"); if (val == 37) return("GBPNZD"); if (val == 38) return("GBPSGD"); if (val == 39) return("NOKJPY"); if (val == 40) return("NZDCAD"); if (val == 41) return("NZDCHF"); if (val == 42) return("NZDGBP"); if (val == 43) return("SEKJPY"); if (val == 44) return("USDAED"); if (val == 45) return("USDBHD"); if (val == 46) return("USDDKK"); if (val == 47) return("USDEGP"); if (val == 48) return("USDHKD"); if (val == 49) return("USDJOD"); if (val == 50) return("USDKWD"); if (val == 51) return("USDMXN"); if (val == 52) return("USDNOK"); if (val == 53) return("USDPLN"); if (val == 54) return("USDQAR"); if (val == 55) return("USDSAR"); if (val == 56) return("USDSEK"); if (val == 57) return("USDSGD"); if (val == 58) return("USDTHB"); if (val == 59) return("USDZAR"); if (val == 60) return("XAGUSD"); if (val == 61) return("XAUUSD"); return("Unrecognized Pair"); } //+----------------------------- Include from /MetaTrader4/CustomFunctions/GreaterCount.mq4 -------------------------------------+ //+------------------------------------------------------------------+ bool sqIsGreaterCount(string indicatorIdentificationLeft,string indicatorIdentificationRight, int bars,bool NotStrict,int shift) { bool atLeastOnce = false; for(int i=0; i<bars; i++) { /// bars != Bars in mq4 double leftIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationLeft,shift+i), 5); /// precision = 5. It returns more acccurate backtest synchronisation double rightIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationRight,shift+i), 5); if(leftIndicator<rightIndicator){ return (false); } if(leftIndicator==rightIndicator && NotStrict == false){ return (false); } if(leftIndicator>rightIndicator){ atLeastOnce = true; } } return(atLeastOnce); } //+----------------------------- Include from /MetaTrader4/CustomFunctions/LowerCount.mq4 -------------------------------------+ //+------------------------------------------------------------------+ bool sqIsLowerCount(string indicatorIdentificationLeft,string indicatorIdentificationRight, int bars,bool NotStrict,int shift) { bool atLeastOnce = false; for(int i=0; i<bars; i++) { /// bars != Bars in mq4 double leftIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationLeft,shift+i), 5); /// precision = 5. It returns more acccurate backtest synchronisation double rightIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationRight,shift+i), 5); if(leftIndicator>rightIndicator){ return (false); } if(leftIndicator==rightIndicator && NotStrict == false){ return (false); } if(leftIndicator<rightIndicator){ atLeastOnce = true; } } return(atLeastOnce); } //+----------------------------- Include from /MetaTrader4/CustomFunctions/SessionOHLC.mq4 -------------------------------------+ double SessionOpen(string symbol, int tf, int startHours, int startMinutes, int daysAgo){ return getSessionPrice(symbol, tf, 1, startHours, startMinutes, startHours, startMinutes, daysAgo); } //+------------------------------------------------------------------+ double SessionHigh(string symbol, int tf, int startHours, int startMinutes, int endHours, int endMinutes, int daysAgo){ return getSessionPrice(symbol, tf, 2, startHours, startMinutes, endHours, endMinutes, daysAgo); } //+------------------------------------------------------------------+ double SessionLow(string symbol, int tf, int startHours, int startMinutes, int endHours, int endMinutes, int daysAgo){ return getSessionPrice(symbol, tf, 3, startHours, startMinutes, endHours, endMinutes, daysAgo); } //+------------------------------------------------------------------+ double SessionClose(string symbol, int tf, int endHours, int endMinutes, int daysAgo){ return getSessionPrice(symbol, tf, 4, endHours, endMinutes, endHours, endMinutes, daysAgo); } //+------------------------------------------------------------------+ double getSessionPrice(string symbol, int tf, int type, int startHours, int startMinutes, int endHours, int endMinutes, int daysAgo){ string correctedSymbol = correctSymbol(symbol); return iCustom(correctedSymbol, tf, "SqSessionOHLC", type, startHours, startMinutes, endHours, endMinutes, daysAgo, 0, 0); } //+----------------------------- Include from /MetaTrader4/CustomFunctions/SRPercRankAboveLevelXBars.mqh -------------------------------------+ //+------------------------------------------------------------------+ bool sqSRPercRankAboveLevelXBars(int mode,int lenght,int ATRPeriod,double Level, int bars,int shift) { bool atLeastOnce = false; for(int i=0; i<bars; i++) { /// bars != Bars in mq4 if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)<Level){ return (false); } if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)>Level){ atLeastOnce = true; } } return(atLeastOnce); } //+----------------------------- Include from /MetaTrader4/CustomFunctions/SRPercRankBelowLevelXBars.mqh -------------------------------------+ bool sqSRPercRankBelowLevelXBars(int mode,int lenght,int ATRPeriod,double Level, int bars,int shift) { bool atLeastOnce = false; for(int i=0; i<bars; i++) { /// bars != Bars in mq4 if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)>Level){ return (false); } if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)<Level){ atLeastOnce = true; } } return(atLeastOnce); } //+----------------------------- Include from /MetaTrader4/CustomFunctions/CustomFunctions.mq4 -------------------------------------+ //+------------------------------------------------------------------+ //+ Custom functions //+ //+ Here you can define your own custom functions that can be used //+ in Algo Wizard. //+ The functions can perform some action (for example draw on chart //+ or manipulate with orders) or they can return value that //+ can be used in comparison. //+ //+ Note! All the functions below must be in valid MQL code! //+ Contents of this file will be appended to your EA code. //+ //+------------------------------------------------------------------+ double exampleFunction(double value) { return(2 * value); } //+------------------------------------------------------------------+ Thousand thanks in advance
×
×
  • Create New...
us