Indicator wrongly plots line into sub-window while calculations are correct

 

Hi All,

I'm experiencing quite strange behavior from the indicator I'm working on. While the calculations and the values in the indicator buffer are correct - the indicator itself plots absolutely fantastic values out of the blue.


The logs are showing that the buffer has values that are correct, however indicator plots them wrongly. The code is below if you'd like to try it out.

//+------------------------------------------------------------------+
//|                                                 Gap Analysis.mq5 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1

//--- plot Label1
#property indicator_label1  "Label1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

enum TradeDirectionType
  {
   DIRECTION_ONE_WAY = 0, // Trade same direction
   DIRECTION_COUNTER = 1  // Trade counter direction
  };

enum TradeOperation
  {
   OPERATION_UNDEFINED = -1, //Undefined
   OPERATION_BUY = 0,        // Buy
   OPERATION_SELL = 1        // Sell
  };

input string PairOne="EURUSD"; //First pair in the couple
input string PairTwo="USDCHF"; //Second pair in the couple
input double PairOneReferencePrice=1.09523;
input double PairTwoReferencePrice=0.96304;
input TradeDirectionType TradeDirection=DIRECTION_ONE_WAY;

//--- indicator buffers
//double         BuyGapBuffer[];
double         SellGapBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,SellGapBuffer,INDICATOR_DATA);
//SetIndexBuffer(1,BuyGapBuffer,INDICATOR_DATA);
//ArrayInitialize(BuyGapBuffer,0.0);
   ArrayInitialize(SellGapBuffer,0.0);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,      // size of the price[] array
                const int prev_calculated,  // number of available bars at the previous call
                const int begin,            // from what index in price[] authentic data start
                const double& price[])
  {
   int toCount=(int)MathMin(rates_total,rates_total-prev_calculated+1);

   for(int i=toCount-1; i>=0; --i)
     {
      //--- coloring the first line
      SellGapBuffer[i]=GetCurrentGap(i);
     }
   Print("First 5 entries: ", SellGapBuffer[0],", ",SellGapBuffer[1],", ",SellGapBuffer[2],", ",SellGapBuffer[3],", ",SellGapBuffer[4],", ",SellGapBuffer[5]);
   return(rates_total);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetCurrentGap(int shift)
  {
   double currentGap=GetFloatingProfit(OPERATION_SELL, PairOne, shift)+ GetFloatingProfit(OPERATION_SELL, PairTwo, shift);
   Print("Current gap: ", currentGap);
   return currentGap;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetFloatingProfit(TradeOperation operationType, string symbol, int shift)
  {
//spread+bid=ask
   double askCurrent =shift==0?SymbolInfoDouble(symbol,SYMBOL_ASK):iClose(symbol,PERIOD_CURRENT,shift)+iSpread(symbol, PERIOD_CURRENT,shift)*SymbolInfoDouble(symbol, SYMBOL_POINT);
   double bidCurrent = iClose(symbol,PERIOD_CURRENT,shift);

   Print("Time: ", iTime(symbol,PERIOD_CURRENT,shift)," Current ask: ", askCurrent, " Current bid: ", bidCurrent, "Shift: ", shift);

   switch(operationType)
     {
      case OPERATION_BUY:

         /////Print("[", __FUNCTION__, "]", " In the buy condition for symbol: ", symbol);

         if(StringFind(symbol, PairOne) > -1)
           {
            //Because USD is the quote currency - we don't have to invert rates. Straight calculation.
            //Print("[", __FUNCTION__, "]", " Current Bid: ", DoubleToString(bidCurrent, SymbolInfoInteger(symbol, SYMBOL_DIGITS)), " EURUSD base: ", DoubleToString(PairOneReferencePrice, SymbolInfoInteger(symbol, SYMBOL_DIGITS)), " Contract size: ", DoubleToString(SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE), 0));
            //Print("[", __FUNCTION__, "]", "EURUSD Gap: ", DoubleToString(bidCurrent - PairOneReferencePrice, SymbolInfoInteger(symbol, SYMBOL_DIGITS)));

            double profitAndLoss=(bidCurrent-PairOneReferencePrice) * SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);

            //Print("[", __FUNCTION__, "]", "EURUSD P/L: ", DoubleToString(profitAndLoss, 2));

            return profitAndLoss;
           }
         else
            if(StringFind(symbol, PairTwo) > -1)
              {
               //Because USD is the base currency - we have to invert the prices by using 1/Price to get profit/loss in the base currency
               Print("[", __FUNCTION__, "]", " Current Bid: ", DoubleToString(bidCurrent, SymbolInfoInteger(symbol, SYMBOL_DIGITS)), " USDCHF base: ", DoubleToString(PairTwoReferencePrice, SymbolInfoInteger(symbol, SYMBOL_DIGITS)), " Contract size: ", DoubleToString(SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE), 0));
               Print("[", __FUNCTION__, "]", "USDCHF Gap: ", DoubleToString(bidCurrent - PairTwoReferencePrice, SymbolInfoInteger(symbol, SYMBOL_DIGITS)));

               double profitAndLoss=(1/bidCurrent)*(bidCurrent-PairTwoReferencePrice) * SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);

               //Print("[", __FUNCTION__, "]", "USDCHF P/L: ", DoubleToString(profitAndLoss, 2));

               return profitAndLoss;
              }
         break;
      case OPERATION_SELL:

         Print("[", __FUNCTION__, "]", " In the sell condition for symbol", symbol);

         if(StringFind(symbol, PairOne) > -1)
           {
            //Because USD is the quote currency - we don't have to invert rates. Straight calculation.
            //Print("[", __FUNCTION__, "]", " Current Ask: ", DoubleToString(askCurrent, SymbolInfoInteger(symbol, SYMBOL_DIGITS)), " EURUSD base: ", DoubleToString(PairOneReferencePrice, SymbolInfoInteger(symbol, SYMBOL_DIGITS)), " Contract size: ", DoubleToString(SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE), 0));
            //Print("[", __FUNCTION__, "]", "EURUSD Gap: ", DoubleToString(askCurrent - PairOneReferencePrice, SymbolInfoInteger(symbol, SYMBOL_DIGITS)));

            double profitAndLoss=(PairOneReferencePrice-askCurrent) * SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);

            //Print("[", __FUNCTION__, "]", "EURUSD P/L: ", DoubleToString(profitAndLoss, 2));

            return profitAndLoss;
           }
         else
            if(StringFind(symbol, PairTwo) > -1)
              {
               //Because USD is the base currency - we have to invert the prices by using 1/Price to get profit/loss in the base currency
               //Print("[", __FUNCTION__, "]", " Current Ask: ", DoubleToString(askCurrent, SymbolInfoInteger(symbol, SYMBOL_DIGITS)), " USDCHF base: ", DoubleToString(PairTwoReferencePrice, SymbolInfoInteger(symbol, SYMBOL_DIGITS)), " Contract size: ", DoubleToString(SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE), 0));
               Print("[", __FUNCTION__, "]", "USDCHF Gap: ", DoubleToString(askCurrent - PairTwoReferencePrice, SymbolInfoInteger(symbol, SYMBOL_DIGITS)));

               double profinAndLoss=(1/askCurrent)*((PairTwoReferencePrice - askCurrent) * SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE));

               //Print("[", __FUNCTION__, "]", "USDCHF P/L: ", DoubleToString(profinAndLoss, 2));

               return profinAndLoss;
              }
         break;
      default:
         break;
     }
   return 0.0;
  }
//+------------------------------------------------------------------+
Documentation on MQL5: Constants, Enumerations and Structures / Indicator Constants / Indicators Lines
Documentation on MQL5: Constants, Enumerations and Structures / Indicator Constants / Indicators Lines
  • www.mql5.com
Indicators Lines - Indicator Constants - Constants, Enumerations and Structures - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,SellGapBuffer,INDICATOR_DATA);
   ArraySetAsSeries(SellGapBuffer,true);
 
Thank you  Ernst Van Der Merwe Indeed quite a silly mistake. Some times you just need another pair of eyes. Thanks again!