Category Other  Published on 03/06/2015

Accumulative Bid/Ask Volume (ZigZag)

Description

(v 1.01) This is the Accumulative Bid/Ask Volume (ZigZag Edition).

To operate it successfully please download and install the ZigZag indicator from here: /algos/indicators/show/157

If you are using my other Bid/Ask Volume indicator you must turn off the "Write to file" option on one of them otherwise two indicators will write to the same data file leading to corruption and/or twice the volume.

 

02.06.2015 - Version 1.01

  • Corrected a flaw where once the repaint is triggered it would do so for the whole duration of that bar

 

Note that the actual ZigZag indicator line in the example image is not part of the volume indicator's plot. It is applied to the chart only for demonstrational purposes. The ZigZag is still needed for the indicator's inner workings. It can also be applied for guidance in finding reasonable settings.

 

 


//#reference: ZigZag.algo
// This is version 1.01

using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Collections.Generic;
using cAlgo.API;
namespace cAlgo.Indicators
{
    public class Previouslist
    {
        public double Preis { get; set; }
        public double Volumen { get; set; }
    }

    [Indicator("Bid/Ask Volumes (in Millions)", IsOverlay = false, AccessRights = AccessRights.FileSystem, ScalePrecision = 2)]
    public class AccumulativeBidAskVolume : Indicator
    {
        [Parameter("Minimum Volume (Millions)", DefaultValue = 10.0, MinValue = 0.0)]
        public double LowFilter { get; set; }

        [Parameter("Maximum Volume (Millions)", DefaultValue = 999.0, MinValue = 1.0)]
        public double HighFilter { get; set; }

        [Parameter("Read from file", DefaultValue = true)]
        public bool ReadFromFile { get; set; }

        [Parameter("Write to file", DefaultValue = true)]
        public bool WriteToFile { get; set; }

        [Parameter("Write interval (seconds)", DefaultValue = 60, MinValue = 20)]
        public int WriteInterval { get; set; }

        [Parameter("Filename (none=Auto)", DefaultValue = "")]
        public string FileName { get; set; }

        [Parameter("ZigZag Depth", DefaultValue = 12, MinValue = 0)]
        public int Depth { get; set; }

        [Parameter("ZigZag Deviation", DefaultValue = 5, MinValue = 0)]
        public int Deviation { get; set; }

        [Parameter("ZigZag Backstep", DefaultValue = 3, MinValue = 0)]
        public int BackStep { get; set; }

        [Output("Bid Volumes", PlotType = PlotType.Histogram, Color = Colors.Red, Thickness = 5)]
        public IndicatorDataSeries AccBidVolume { get; set; }

        [Output("Ask Volumes", PlotType = PlotType.Histogram, Color = Colors.Blue, Thickness = 5)]
        public IndicatorDataSeries AccAskVolume { get; set; }

        [Output("Ask-Bid Difference", PlotType = PlotType.Histogram, Color = Colors.White, Thickness = 5)]
        public IndicatorDataSeries AccAskBidDifference { get; set; }

        private double LowFilterM;
        private double HighFilterM;
        private int LastResultIndex;
        private double addPrevAccAskVolume;
        private double addPrevAccBidVolume;
        private bool DoneRewrite = false;
        private IndicatorDataSeries BidVolume;
        private IndicatorDataSeries AskVolume;
        ZigZag zigzag;
        private MarketDepth _marketDepth;
        private List<Previouslist> PreviousBidList = new List<Previouslist>();
        private List<Previouslist> PreviousAskList = new List<Previouslist>();
        private StringBuilder Table = new StringBuilder();
        private string fname;
        private char[] Delimiters = 
        {
            ',',
            ','
        };

        private int BarsAgo(DateTime time)
        {
            for (int i = MarketSeries.OpenTime.Count - 1; i > 0; i--)
            {
                if (MarketSeries.OpenTime[i] <= time)
                    return MarketSeries.OpenTime.Count - 1 - i;
            }
            return -1;
        }

//--------------------------------------
        public override void Calculate(int index)
        {
            if (!double.IsNaN(zigzag.Result[index]))
                LastResultIndex = index;
            if (index - Depth == LastResultIndex && !DoneRewrite)
            {
                for (int i = LastResultIndex + 1; i < index; i++)
                {
                    if (i == LastResultIndex + 1)
                    {
                        AccBidVolume[i] = BidVolume[i];
                        AccAskVolume[i] = AskVolume[i];
                        AccAskBidDifference[i] = AccAskVolume[i] + AccBidVolume[i];
                    }
                    else
                    {
                        if (double.IsNaN(AccBidVolume[i - 1]))
                            addPrevAccBidVolume = 0;
                        else
                            addPrevAccBidVolume = AccBidVolume[i - 1];
                        if (double.IsNaN(AccAskVolume[i - 1]))
                            addPrevAccAskVolume = 0;
                        else
                            addPrevAccAskVolume = AccAskVolume[i - 1];

                        AccBidVolume[i] = BidVolume[i] + addPrevAccBidVolume;
                        AccAskVolume[i] = AskVolume[i] + addPrevAccAskVolume;
                        AccAskBidDifference[i] = AccAskVolume[i] + AccBidVolume[i];
                    }
                }
                DoneRewrite = true;
            }
            if (index - Depth != LastResultIndex)
                DoneRewrite = false;
            if (double.IsNaN(AccBidVolume[index - 1]))
                addPrevAccBidVolume = 0;
            else
                addPrevAccBidVolume = AccBidVolume[index - 1];
            if (double.IsNaN(AccAskVolume[index - 1]))
                addPrevAccAskVolume = 0;
            else
                addPrevAccAskVolume = AccAskVolume[index - 1];

            AccBidVolume[index] = BidVolume[index] + addPrevAccBidVolume;
            AccAskVolume[index] = AskVolume[index] + addPrevAccAskVolume;
            AccAskBidDifference[index] = AccAskVolume[index] + AccBidVolume[index];
        }

//--------------------------------------

        protected override void Initialize()
        {
            _marketDepth = MarketData.GetMarketDepth(Symbol);
            _marketDepth.Updated += MarketDepthUpdated;

            BidVolume = CreateDataSeries();
            AskVolume = CreateDataSeries();

            zigzag = Indicators.GetIndicator<ZigZag>(Depth, Deviation, BackStep);

            foreach (var entry in _marketDepth.BidEntries)
            {
                PreviousBidList.Add(new Previouslist 
                {
                    Preis = entry.Price,
                    Volumen = entry.Volume
                });
            }

            foreach (var entry in _marketDepth.AskEntries)
            {
                PreviousAskList.Add(new Previouslist 
                {
                    Preis = entry.Price,
                    Volumen = entry.Volume
                });
            }

            LowFilterM = LowFilter * 1000000;
            HighFilterM = HighFilter * 1000000;
            fname = string.Format("{0}{1}{2}{3}", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "\\", FileName == "" ? Symbol.Code : FileName, ".csv");
            if (ReadFromFile && System.IO.File.Exists(fname) == true)
            {
                using (StreamReader Fstream = new StreamReader(fname))
                {
                    string line;
                    while ((line = Fstream.ReadLine()) != null)
                    {
                        try
                        {
                            string[] words = line.Split(Delimiters);
                            double vol = Convert.ToDouble(words[1]);
                            if (vol >= HighFilterM || vol < LowFilterM)
                                continue;
                            int bago = BarsAgo(Convert.ToDateTime(words[0]));
                            if (bago == -1)
                                continue;
                            int bidx = MarketSeries.Close.Count - 1 - bago;
                            if (double.IsNaN(AskVolume[bidx]))
                                AskVolume[bidx] = 0;
                            if (double.IsNaN(BidVolume[bidx]))
                                BidVolume[bidx] = 0;
                            switch (words[2])
                            {
                                case "A":
                                    AskVolume[bidx] += (vol / 1000000);
                                    break;
                                case "B":
                                    BidVolume[bidx] -= (vol / 1000000);
                                    break;
                            }
                        } catch
                        {
                            continue;
                        }
                    }
                }
            }
            if (WriteToFile)
            {
                if (System.IO.File.Exists(fname) == false)
                    System.IO.File.WriteAllText(fname, "");
                Timer.Start(WriteInterval);
            }
        }
//--------------------------------------

        protected override void OnTimer()
        {
            if (Table.Length != 0)
            {
                using (StreamWriter Swrite = File.AppendText(fname))
                {
                    Swrite.Write(Table.ToString());
                }
                Table.Clear();
            }
        }

//--------------------------------------

        void MarketDepthUpdated()
        {
            if (double.IsNaN(BidVolume[MarketSeries.Close.Count - 1]))
                BidVolume[MarketSeries.Close.Count - 1] = 0;
            if (double.IsNaN(AskVolume[MarketSeries.Close.Count - 1]))
                AskVolume[MarketSeries.Close.Count - 1] = 0;

            foreach (var entry in _marketDepth.BidEntries)
            {
                int idx = 0;
                if (WriteToFile)
                {
                    idx = PreviousBidList.FindIndex(r => r.Preis.Equals(entry.Price));
                    if (idx == -1)
                        Table.AppendLine(string.Format("{0},{1},{2}", Time, entry.Volume, "B"));
                    else
                    {
                        double DifferenceVolume = entry.Volume - PreviousBidList[idx].Volumen;
                        if (DifferenceVolume > 0)
                            Table.AppendLine(string.Format("{0},{1},{2}", Time, entry.Volume - PreviousBidList[idx].Volumen, "B"));
                    }
                }
                if (entry.Volume >= LowFilterM)
                {
                    if (!WriteToFile)
                    {
                        idx = PreviousBidList.FindIndex(r => r.Preis.Equals(entry.Price));
                    }
                    if (idx == -1 && entry.Volume < HighFilterM)
                        BidVolume[MarketSeries.Close.Count - 1] -= (entry.Volume / 1000000);
                    if (idx != -1)
                    {
                        double DifferenceVolume = entry.Volume - PreviousBidList[idx].Volumen;
                        if (DifferenceVolume >= LowFilterM && DifferenceVolume < HighFilterM)
                            BidVolume[MarketSeries.Close.Count - 1] -= (DifferenceVolume / 1000000);
                    }
                }
            }

            foreach (var entry in _marketDepth.AskEntries)
            {
                int idx = 0;
                if (WriteToFile)
                {
                    idx = PreviousAskList.FindIndex(r => r.Preis.Equals(entry.Price));
                    if (idx == -1)
                        Table.AppendLine(string.Format("{0},{1},{2}", Time, entry.Volume, "A"));
                    else
                    {
                        double DifferenceVolume = entry.Volume - PreviousAskList[idx].Volumen;
                        if (DifferenceVolume > 0)
                            Table.AppendLine(string.Format("{0},{1},{2}", Time, entry.Volume - PreviousAskList[idx].Volumen, "A"));
                    }
                }

                if (entry.Volume >= LowFilterM)
                {
                    if (!WriteToFile)
                    {
                        idx = PreviousAskList.FindIndex(r => r.Preis.Equals(entry.Price));
                    }
                    if (idx == -1 && entry.Volume < HighFilterM)
                        AskVolume[MarketSeries.Close.Count - 1] += (entry.Volume / 1000000);
                    if (idx != -1)
                    {
                        double DifferenceVolume = entry.Volume - PreviousAskList[idx].Volumen;
                        if (DifferenceVolume >= LowFilterM && DifferenceVolume < HighFilterM)
                            AskVolume[MarketSeries.Close.Count - 1] += (DifferenceVolume / 1000000);
                    }
                }
            }


            PreviousBidList.Clear();
            foreach (var entry in _marketDepth.BidEntries)
            {
                PreviousBidList.Add(new Previouslist 
                {
                    Preis = entry.Price,
                    Volumen = entry.Volume
                });
            }

            PreviousAskList.Clear();
            foreach (var entry in _marketDepth.AskEntries)
            {
                PreviousAskList.Add(new Previouslist 
                {
                    Preis = entry.Price,
                    Volumen = entry.Volume
                });
            }
        }
    }
}


96
9600302

Joined on 19.03.2015

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: Accumulative Bid-Ask Volume (zigzag version) v1.01.algo
  • Rating: 0
  • Installs: 4015
  • Modified: 13/10/2021 09:54
Comments
Log in to add a comment.
VO
Voids · 9 years ago

Hi,

I have a zig zag wave with cumulative value indicator in mq4, but sadly I can't convert it to calgo using 2calgo.com. May I ask for your help to convert that indicator?

Thank you.

96
9600302 · 9 years ago

@iburakbirer

But I still would like to know, how that strategy looks like that you say you have discovered.

Where would possible entry and exits be?

Please also explain what a "balancing wave" is and what it actually means in the context of positioning yourself correctly.

 

96
9600302 · 9 years ago

OK, I think I understand now when I looked at your image again.

That would mean a continuously resetting volume count whenever there is a confirmed zigzag high/low (which I implemented) but also a retroactive change over two zigzag high/low periods. That is going to be very difficult to implement. As I said the zigzag is not what it seems on the chart. I now even think the current implementation is buggy as it still contains all the temporary high/low values but these are still somehow ignored anyway. I tried to understand the algorithm's internals but must say that I failed.

 

96
9600302 · 9 years ago

iburakbirer - June 04, 2015 @ 12:15

Good that you can find something useful in it.

How would the strategy look like? 

But i think the trader should see the wave until the reverse zigzag is seen. So the delta divergences will be more obvious i guess?

Can you explain that a little more?

 

IB
iburakbirer · 9 years ago

Hi @9600302

Here is my preliminary test notes;

First of all that showed me we might me in the right road. I just started testing and i found a strategy based on following delta divergences inside a zigzag wave. As its cumulative now (thanks to you) a trader can see that the cumulative delta is not moving while more buyers and sellers coming. That might be the key to that balancing wave thing which we talked before.

I just started testing but i see that when a zigzag wave stops the cumulative volumes also seperates as it should in a normal situation. But i think the trader should see the wave until the reverse zigzag is seen. So the delta divergences will be more obvious i guess? What do you think,

To sum up my offer is not to seperate data until the reverse zigzag is seen.

I used 8millions filter and 34 bars zigzag for my test. Here is a screenshot
http://pepperstone.ctrader.com/c/mFmyn
Best, 

96
9600302 · 9 years ago

Upon further inspection I noticed that my volume plot is not in sync with the ZigZag line on the chart. It leaves much to be desired. This is due to the ZigZag filter I had to implement, which still doesn't produce a useful result from the ZigZag.

I consider it now as strictly beta and unfinished. There is not one single ZigZag indicator that produces a useful result. It looks like they all have the same problem: They all repaint (which is not the biggest problem because my accumulated volume repaints, too) and the output array is full of garbage and remnants of old calculations.

I'm giving up on this one for now. There is no way I can make it work without programming a better and more useful zigzag indicator.

Don't install if you need perfect results.