Trying to code cumulative delta volume but... what's wrong here?

 

So I tried to code something from tradingview and make it happen in MQL4.

I updated this post to show new problem I have now.

The indicator doesn't render new candles when I press play. It only show past candles but not new one. I have no clue why. 

Then I need to get the cumulatif of sums. The first step is to get the average sums and the next step I have no clue. But now I tried to get the average sums but it give ridiculously large number when I'm only adding between -500 and +500 for each candles. And wierdly enough, my graphic show a big number only decreasing over time when it should be going up and down.


Below is the Mql4 code and below it there is the tradingview code which I want to copy.

//+------------------------------------------------------------------+
//|                                                  Heiken Ashi.mq4 |
//|                   Copyright 2006-2014, MetaQuotes Software Corp. |
//|                                              http://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright   "2006-2014, MetaQuotes Software Corp."
#property link        "http://www.mql4.com"
#property description "We recommend next chart settings (press F8 or select menu 'Charts'->'Properties...'):"
#property description " - on 'Color' Tab select 'Black' for 'Line Graph'"
#property description " - on 'Common' Tab disable 'Chart on Foreground' checkbox and select 'Line Chart' radiobutton"
#property strict

#property indicator_separate_window
#property indicator_buffers 23
#property indicator_color1 Red
#property indicator_color2 White
#property indicator_color3 Red
#property indicator_color4 White
#property indicator_width1 1
#property indicator_width2 1
#property indicator_width3 3
#property indicator_width4 3

//---
input color ExtColor1 = Red;    // Shadow of bear candlestick
input color ExtColor2 = White;  // Shadow of bull candlestick
input color ExtColor3 = Red;    // Bear candlestick body
input color ExtColor4 = White;  // Bull candlestick body

extern bool hacandle = true;

//--- buffers
double ExtHighBuffer[];
double ExtLowBuffer[];
double ExtOpenBuffer[];
double ExtCloseBuffer[];
double delta[], cumdelta[], tw[], bw[], body[], deltaup[], deltadown[], o[], h[], l[], c[], haclose[], haopen[], hahigh[], halow[], o_[], h_[], l_[], c_[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//|------------------------------------------------------------------|
void OnInit(void)
  {
   IndicatorShortName("Cumulative Delta Vol");
   IndicatorDigits(Digits);
//--- indicator lines
   SetIndexStyle(0,DRAW_HISTOGRAM,0,1,ExtColor1);
   SetIndexBuffer(0,ExtHighBuffer);
   SetIndexStyle(1,DRAW_HISTOGRAM,0,1,ExtColor2);
   SetIndexBuffer(1,ExtLowBuffer);
   SetIndexStyle(2,DRAW_HISTOGRAM,0,3,ExtColor3);
   SetIndexBuffer(2,ExtOpenBuffer);
   SetIndexStyle(3,DRAW_HISTOGRAM,0,3,ExtColor4);
   SetIndexBuffer(3,ExtCloseBuffer);
//---
   SetIndexLabel(0,"High");
   SetIndexLabel(1,"Low");
   SetIndexLabel(2,"Open");
   SetIndexLabel(3,"Close");
   SetIndexLabel(4,"TW");
   SetIndexLabel(5,"BW");
   SetIndexLabel(6,"Dody");
   SetIndexLabel(7,"Delta up");
   SetIndexLabel(8,"Delta down");
   SetIndexLabel(9,"Delta");
   SetIndexLabel(10,"Cum.Delta");
   SetIndexLabel(11,"High");
   SetIndexLabel(12,"Low");
   SetIndexLabel(13,"Open");
   SetIndexLabel(14,"Close");
   SetIndexLabel(15,"HA High");
   SetIndexLabel(16,"HA Low");
   SetIndexLabel(17,"HA Open");
   SetIndexLabel(18,"HA Close");
   SetIndexLabel(19,"High");
   SetIndexLabel(20,"Low");
   SetIndexLabel(21,"Open");
   SetIndexLabel(22,"Close");
   
   SetIndexDrawBegin(0,10);
   SetIndexDrawBegin(1,10);
   SetIndexDrawBegin(2,10);
   SetIndexDrawBegin(3,10);
//--- indicator buffers mapping
   SetIndexBuffer(0,ExtHighBuffer);
   SetIndexBuffer(1,ExtLowBuffer);
   SetIndexBuffer(2,ExtOpenBuffer);
   SetIndexBuffer(3,ExtCloseBuffer);
   SetIndexBuffer(4, tw);
   SetIndexBuffer(5, bw);
   SetIndexBuffer(6, body);
   SetIndexBuffer(7, deltaup);
   SetIndexBuffer(8, deltadown);
   SetIndexBuffer(9, delta);
   SetIndexBuffer(10, cumdelta);
   SetIndexBuffer(11, h);
   SetIndexBuffer(12, l);
   SetIndexBuffer(13, o);
   SetIndexBuffer(14, c);
   SetIndexBuffer(15, hahigh);
   SetIndexBuffer(16, halow);
   SetIndexBuffer(17, haopen);
   SetIndexBuffer(18, haclose);
   SetIndexBuffer(19, h_);
   SetIndexBuffer(20, l_);
   SetIndexBuffer(21, o_);
   SetIndexBuffer(22, c_);
//--- initialization done
  }
//+------------------------------------------------------------------+
//| Heiken Ashi                                                      |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   int    i,pos;
   
//---
   if(rates_total<=10)
      return(0);
//--- counting from 0 to rates_total
   ArraySetAsSeries(ExtHighBuffer,true);
   ArraySetAsSeries(ExtLowBuffer,true);
   ArraySetAsSeries(ExtOpenBuffer,true);
   ArraySetAsSeries(ExtCloseBuffer,true);
   ArraySetAsSeries(open,true);
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true);
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(tw,true);
   ArraySetAsSeries(bw,true);
   ArraySetAsSeries(body,true);
   ArraySetAsSeries(deltaup,true);
   ArraySetAsSeries(deltadown,true);
   ArraySetAsSeries(delta,true);
   ArraySetAsSeries(cumdelta,true);
   ArraySetAsSeries(h,true);
   ArraySetAsSeries(l,true);
   ArraySetAsSeries(o,true);
   ArraySetAsSeries(c,true);
   ArraySetAsSeries(h_,true);
   ArraySetAsSeries(l_,true);
   ArraySetAsSeries(o_,true);
   ArraySetAsSeries(c_,true);
   ArraySetAsSeries(haopen,true);
   ArraySetAsSeries(hahigh,true);
   ArraySetAsSeries(halow,true);
   ArraySetAsSeries(haclose,true);
//--- preliminary calculation
   if(prev_calculated>1)
      pos=prev_calculated-1;
   else
     {
      //--- set first candle
      ExtHighBuffer[0]=h_[0];
      ExtLowBuffer[0]=l_[0];
      ExtOpenBuffer[0]=o_[0];
      ExtCloseBuffer[0]=c_[0];
      cumdelta[0] = 0;
      //---
      pos=1;
     }
//--- main loop of calculations
   for(i=rates_total - 2; i > pos; i--)
     {
      
      tw[i] = High[i] - MathMax(Open[i], Close[i]);
      bw[i] = MathMin(Open[i], Close[i]) - Low[i];
      body[i] = MathAbs(Close[i] - Open[i]);
      
      deltaup[i] =  Volume[i] * _rate(Open[i] <= Close[i], i); 
      deltadown[i] = Volume[i] * _rate(Open[i] > Close[i], i);
      delta[i] = Close[i] >= Open[i] ? deltaup[i] : -deltadown[i];
      cumdelta[i] = Sum(delta);
      
      
      Print("cumdelta[i] ", cumdelta[i]); //Value return 1.
      Print("cumdelta[i+1] ", cumdelta[i+1]); //Value return infinite.
      //I want to get cumdelta of previous bars for o[i].
      o[i] = cumdelta[i+1];
      //Get max between cumdelta of current bars and previous bars.
      h[i] = MathMax(cumdelta[i], cumdelta[i+1]);
      l[i] = MathMin(cumdelta[i], cumdelta[i+1]);
      c[i] = cumdelta[i];
      haclose[i] = (o[i] + h[i] + l[i] + c[i]) / 4;
      haopen[i] = MathIsValidNumber(haopen[i+1]) ? (o[i] + c[i]) / 2 : (o[i+1] + c[i+1]) / 2;
      hahigh[i] = MathMax(h[i], MathMax(haopen[i], haclose[i]));
      halow[i] = MathMin(l[i],  MathMin(haopen[i], haclose[i]));
      
      c_[i] = hacandle ? haclose[i] : c[i];
      o_[i] = hacandle ? haopen[i] : o[i];
      h_[i] = hacandle ? hahigh[i] : h[i];
      l_[i] = hacandle ? halow[i] : l[i];
      
      ExtHighBuffer[i]=h_[i];
      ExtLowBuffer[i]=l_[i];
      ExtOpenBuffer[i]=o_[i];
      ExtCloseBuffer[i]=c_[i];
     }
//--- done
   return(rates_total);
  }
//+------------------------------------------------------------------+

double _rate(bool cond, int shift)
      {
         double ret = 0.5 * division((tw[shift] + bw[shift] + (cond ? 2 * body[shift] : 0)) , (tw[shift] + bw[shift] + body[shift]));
         ret = nz(ret) == 0 ? 0.5 : ret;
         return ret;
      }

double Sum(double &arr[])
{
   double sum = 0;
   for (int i = 0; i < ArraySize(arr); i++)
   sum +=arr[i];
   return sum / ArraySize(arr);
}

double nz(double v, double r=0.0){ if(v == EMPTY_VALUE) v = r; return r; }

double division(double numerator, double denominator)
{
   if (denominator == 0)
   {
      return(0);
   }
   else
   {
      return numerator/denominator;
   }
}
//Here is the tradingview code I'm trying to translate to MQL4:

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © LonesomeTheBlue
 
//@version=4
study("Cumulative Delta Volume", "CDV")
linestyle = input(defval = 'Candle', title = "Style", options = ['Candle', 'Line'])
hacandle = input(defval = true, title = "Heikin Ashi Candles?")

showema1 = input(defval = false, title = "EMA 1", inline = "ema1")
ema1len = input(defval = 50, title = "", minval = 1, inline = "ema1")
ema1col = input(defval = color.lime, title = "", inline = "ema1")
showema2 = input(defval = false, title = "EMA 2", inline = "ema2")
ema2len = input(defval = 200, title = "", minval = 1, inline = "ema2")
ema2col = input(defval = color.red, title = "", inline = "ema2")

tw = high - max(open, close) 
bw = min(open, close) - low 
body = abs(close - open) 

_rate(cond) =>
    ret = 0.5 * (tw + bw + (cond ? 2 * body : 0)) / (tw + bw + body) 
    ret := nz(ret) == 0 ? 0.5 : ret
    ret
    
deltaup =  volume * _rate(open <= close) 
deltadown = volume * _rate(open > close)
delta = close >= open ? deltaup : -deltadown
cumdelta = cum(delta)
plot(cumdelta)
float ctl = na
float o = na
float h = na
float l = na
float c = na
if linestyle == 'Candle'
    o := cumdelta[1]
    h := max(cumdelta, cumdelta[1])
    l := min(cumdelta, cumdelta[1])
    c := cumdelta
else
    ctl := cumdelta

//plot(ctl, title = "CDV Line", color = color.blue, linewidth = 2)

float haclose = na
float haopen = na
float hahigh = na
float halow = na
haclose := (o + h + l + c) / 4
haopen  := na(haopen[1]) ? (o + c) / 2 : (haopen[1] + haclose[1]) / 2
hahigh  := max(h, max(haopen, haclose))
halow   := min(l,  min(haopen, haclose))
 
c_ = hacandle ? haclose : c
o_ = hacandle ? haopen : o
h_ = hacandle ? hahigh : h
l_ = hacandle ? halow : l
 

Hey mate.

I haven't tested the code myself,

But there are already several things that pop out.

I am not a native English speaker, so I'll do my best to explain myself as clear as I can.


1)

I am not even sure how this code compiles,

But on your _rate function you have a comma sign instead of a division sign.

So-

double ret = 0.5 * division((tw + bw + (cond ? 2 * body : 0)) , (tw + bw + body));

Should become-

double ret = 0.5 * division((tw + bw + (cond ? 2 * body : 0)) / (tw + bw + body));


2)

From the original code it seems that cumdelta is a sum,

But you calculate its value as if it was an average

So-

cumdelta[i] = findSum(delta[i], ArraySize(delta))/ArraySize(delta);

Should become-

cumdelta[i] = findSum(delta[i], ArraySize(delta));


3)

Again, I am not sure how this code even compiles,

But your findSum function expects a pointer to an array as an input

int findSum(double &arr[], int size)

But you pass it an array element which is of type double

cumdelta[i] = findSum(delta[i], ArraySize(delta))/ArraySize(delta);


4)

My guess is that cumdelta[i+1] doesn't return infinite,

But it returns EMPTY_VALUE.

In your loop your are trying to use the value of cumdelta[i+1],

But its value had not been calculated yet.

Your loop first calculate the most recent candle ([0]),

And only then goes to calculate the candle before him ([1]),

And then the candle before him ([2]),

etc'

So you are trying to retrieve a value that is not yet calculated.

If you want to use the value of the previous candle calculation,

You should reverse the 'direction' of your loop to start calculating from the oldest candle, and then advancing from there, candle by candle, until it reaches the most recent one.


These are just several things that popped out as I looked at your code.

Again- I haven't tested it, but the above are issues that needed to be fixed.


If something in my explanation isn't clear enough,

Please let me know and I'll try to rephrase it in a more clear way.


Cheers.

 

Another big issue I've just noticed-

5)

MathIsValidNumber return type is type bool,

So your findSum function doesn't actually adds the value of the input array,

But it adds a boolean value, which is typecast as double, to the sum,

So essentially you are adding either 1 or 0 to the calculation.

I think you can skip using MathIsValidNumber in your calculation,

But if your still want to use it,

Then-

int findSum(double &arr[], int size)
{
   double sum = 0;
   for(int i=0; i<size; i++)
   {
      sum += MathIsValidNumber(arr[i]);
   }
return sum;
}

Should become-

int findSum(double &arr[], int size)
{
   double sum = 0;
   for(int i=0; i<size; i++)
   {
        if(MathIsValidNumber(arr[i])) {
                sum +=arr[i];
        }
   }
return sum;
}
 
AMI289 #:

Hey mate.

I haven't tested the code myself,

But there are already several things that pop out.

I am not a native English speaker, so I'll do my best to explain myself as clear as I can.


1)

I am not even sure how this code compiles,

But on your _rate function you have a comma sign instead of a division sign.

So-

Should become-


2)

From the original code it seems that cumdelta is a sum,

But you calculate its value as if it was an average

So-

Should become-


3)

Again, I am not sure how this code even compiles,

But your findSum function expects a pointer to an array as an input

But you pass it an array element which is of type double


4)

My guess is that cumdelta[i+1] doesn't return infinite,

But it returns EMPTY_VALUE.

In your loop your are trying to use the value of cumdelta[i+1],

But its value had not been calculated yet.

Your loop first calculate the most recent candle ([0]),

And only then goes to calculate the candle before him ([1]),

And then the candle before him ([2]),

etc'

So you are trying to retrieve a value that is not yet calculated.

If you want to use the value of the previous candle calculation,

You should reverse the 'direction' of your loop to start calculating from the oldest candle, and then advancing from there, candle by candle, until it reaches the most recent one.


These are just several things that popped out as I looked at your code.

Again- I haven't tested it, but the above are issues that needed to be fixed.


If something in my explanation isn't clear enough,

Please let me know and I'll try to rephrase it in a more clear way.


Cheers.

Thanks for reaching out. 


1) I have a function called division. That's why I have a comma sign, it take input 1 and divide by input 2 and check if input 2 is zero do avoid divide by zero.

2) You are right, I am doing an average like that. But I need to get a Cumulative of sums and the first step I think is getting the average. I don't know what's the next step. I might be wrong.

3) I'm now using the array as a normal variable but it doesn't do a sum.

double Sum(double arr)
{
   double sum = 0;
   sum +=arr;
   return sum;
}

When using an array and looping through it all, it just doesn't seem right with all the big numbers it give.

4) I reversed the direction of my loop and now it work better. Thanks a lot.

5) Fixed! Now it looks closer to a functionning indicator. All that's left is to calculate the cumulatif of sums (number 3). 


I found another problem, when I test the indicator, it doesn't render new candles. It only create candles in the past at start but not new one when I press play.

 
vetador #:

Thanks for reaching out. 


1) I have a function called division. That's why I have a comma sign, it take input 1 and divide by input 2 and check if input 2 is zero do avoid divide by zero.

2) You are right, I am doing an average like that. But I need to get a Cumulative of sums and the first step I think is getting the average. I don't know what's the next step. I might be wrong.

3) I'm now using the array as a normal variable but it doesn't do a sum.

When using an array and looping through it all, it just doesn't seem right with all the big numbers it give.

4) I reversed the direction of my loop and now it work better. Thanks a lot.

5) Fixed! Now it looks closer to a functionning indicator. All that's left is to calculate the cumulatif of sums (number 3). 


I found another problem, when I test the indicator, it doesn't render new candles. It only create candles in the past at start but not new one when I press play.

Oh, yeah,

My mistake.

I didn't notice that you have a function call in that line.

So you can ignore issue #1.


Regarding the rest-

I would leave findSum function the way it originally was,

And I would just pass the whole array, instead of a double value.

I see that you've edited your code and you've already done that.

Good job!


Just a little tip,

because you're summing the whole array each time,

Instead of making a loop that each tick will loop thru the whole array,

Just create another buffer, or a static variable,

And each calculation just add in the new value.

It will be much more 'resource friendly' and efficient.