Category Other  Published on 29/05/2015

Bid/Ask Volume

Description

(Version 1.1) Accumulates and displays the true bid and ask volume in monetary terms (currency units) for each bar/period and their difference in a convenient histogram plot. It features filters below and above which all volume is filtered out to calculate with only the high volume offers (the smart money in theory, as opposed to the "suckers").

Due to its nature having to collect the data first it does not provide a full backfill. However, it provides a backfill for self collected data with its new data saving feature. For this an automatically named text file in the current user's documents folder is created. The file can be manually named if necessary. It is best to leave the respective option empty in the settings.

Switching to another timeframe, reloading the chart or changing the volume settings occurs now with only minimal loss of collected data depending on the save setting. No more emotional meltdowns because the chart application disconnects from the server and restarts the indicator plot with the loss of all collected historical data.

To compare filter settings that are right for the broker, chosen currency pair and the time of day multiple instances of the indicator that access the same data file can be attached to the chart. In this case only one instance of the indicator should actually write to the file and collect data. Data writing must therefore be turned off in the other indicator's instances.

The interpretation of the plot is up to the user. Some people use it to identify high volume turns and impending directional change. Other people use the difference plot as direct signal. Or it may not yield anything at all and may only be used for educational purposes. This seems to be highly dependent on the type and quality of volume delivered from the broker.

Do not copy and paste the code into the editor and try to compile it yourself! The forum software introduces garbage symbols that lead to compiler errors. I don't post the code myself. The forum software automatically extracts the source code from the compiled file for online display. So it is safe to download as it is impossible to manipulate the source code.

This indicator does not work fully with ICMarkets due to their guaranteed volume policy that causes excessive flooding of the indicator's internal volume lists. Even though it is possible to filter this volume this still corrupts and excessively inflates the data file. It will work when the save is turned off and the hi-filter is set to a relatively low setting of 20 (million). In this case there is no backfill.

There is no limit to the amount of data that is collected in the file. That means that the file may one day have the size of hundreds of megabytes. If it gets too big for the user it may just be deleted so the algorithm will then start a new file.

The current location of the data file is: C:\users\yourusername\documents

 

Version 1.1 (28.5.2015)

  • Save feature added
  • Minor mistakes corrected
  • Volume low-filter added
  • Number of digits extended to two for CFDs

 


// This is version 1.1

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 BidAskVolume : 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; }

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

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

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

        private double LowFilterM;
        private double HighFilterM;
        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)
        {
        }
//--------------------------------------        
        protected override void Initialize()
        {
            _marketDepth = MarketData.GetMarketDepth(Symbol);
            _marketDepth.Updated += MarketDepthUpdated;

            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(AskVolumes[bidx]))
                                AskVolumes[bidx] = 0;
                            if (double.IsNaN(BidVolumes[bidx]))
                                BidVolumes[bidx] = 0;
                            switch (words[2])
                            {
                                case "A":
                                    AskVolumes[bidx] += (vol / 1000000);
                                    break;
                                case "B":
                                    BidVolumes[bidx] -= (vol / 1000000);
                                    break;
                            }
                            AskBidDifference[bidx] = AskVolumes[bidx] + BidVolumes[bidx];
                        } 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(BidVolumes[MarketSeries.Close.Count - 1]))
                BidVolumes[MarketSeries.Close.Count - 1] = 0;
            if (double.IsNaN(AskVolumes[MarketSeries.Close.Count - 1]))
                AskVolumes[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)
                        BidVolumes[MarketSeries.Close.Count - 1] -= (entry.Volume / 1000000);
                    if (idx != -1)
                    {
                        double DifferenceVolume = entry.Volume - PreviousBidList[idx].Volumen;
                        if (DifferenceVolume >= LowFilterM && DifferenceVolume < HighFilterM)
                            BidVolumes[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)
                        AskVolumes[MarketSeries.Close.Count - 1] += (entry.Volume / 1000000);
                    if (idx != -1)
                    {
                        double DifferenceVolume = entry.Volume - PreviousAskList[idx].Volumen;
                        if (DifferenceVolume >= LowFilterM && DifferenceVolume < HighFilterM)
                            AskVolumes[MarketSeries.Close.Count - 1] += (DifferenceVolume / 1000000);
                    }
                }
            }

            AskBidDifference[MarketSeries.Close.Count - 1] = AskVolumes[MarketSeries.Close.Count - 1] + BidVolumes[MarketSeries.Close.Count - 1];

            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: Bid-Ask Volume v1.1.algo
  • Rating: 5
  • Installs: 5358
Comments
Log in to add a comment.
MA
martinchocho2014 · 3 years ago

Hola, no logro hacer que funcione el indicador. No se si es que lo configuro mal. Yo lo descargue y lo instale pero no se si tengo que hacer algo más.

Muchas gracias

SE
secretgspot · 8 years ago

good stuff, looks like M.M. method

GD
GDPR-24_197320 · 8 years ago

tell me how  can i use indicator in robot ?

if LOG WRITE -  Crashed in OnStart with ArgumentException: Incorrect parameters count. Имя параметра: parameterValues

i use signal :    double ba1 = ba.AskBidDifference[ba.AskBidDifference.Count - 1];

robot compiled but not start

96
9600302 · 9 years ago

iburakbirer - June 02, 2015 @ 13:09

I'm finally done. It needs more refinement but you can go to

/algos/indicators/show/858

and download from there.

 

IB
iburakbirer · 9 years ago

@9600302 this is great news, I am really curious about what we'll find while testing the new version.

96
9600302 · 9 years ago

@iburakbirer

I'm done since yesterday with the implementation of the zigzag. However upon closer inspection of the zigzag output I realized that the zigzag needs to be filtered. And for that I need to write a filter. I'm also looking into using the fractals indicator. Due to the volatile nature of these indicators and their changing indication my accumulative volume indicator also needs to be able to rewrite its volume count. This needs time to implement.

 

96
9600302 · 9 years ago

I wrote:

I also generally tend to only mildly trust known indicators that have been used ad nauseam and have already been around for decades. Usually I find them to be useless and that's why they are put out for free for everybody's use.

I have to correct myself here. I don't mean my own indicators that I put out but generally the vast majority of the indicators that can be found on the net (that I have come across at least). They are usually free for a reason and have been deliberately placed in my understanding.

 

96
9600302 · 9 years ago

New version out

Added save feature for backfill of collected data and filter for very high volume.

 

@iburakbirer - May 27, 2015 @ 14:15

I read your post. I may have a solution for these problems but for now I start with the implementation of either a type of zig-zag or other reversal indication. The question is if it makes sense to use another means of detection of reversals in order to have the volume indicator showing a reversal too that it should do on its own in the first place.

Either way it quite possibly will only show a reversal AFTER it already happened.

But I understand the direction where this is going. It also already results in a lot of work for me.

I have a completely different understanding of the "market". What we see at these typical "brokers" is not the real volume that causes a hypothetical (at best) "overpowering" of a previous move that results in a subsequent reversal. That happens at Reuters and EBS. These are out of reach. We only see the wholesale volume of a selection of banks and mostly market makers plus the useless volume of the algorithmic trading of smaller entities. The implications should be obvious. I already have trouble to see something useful in as simple as my volume plot no matter what filter settings I use.

I also generally tend to only mildly trust known indicators that have been used ad nauseam and have already been around for decades. Usually I find them to be useless and that's why they are put out for free for everybody's use.

But the general idea of something like this may yield a good outcome.

IB
iburakbirer · 9 years ago

@9600302 great to hear from you, i would like to share some of my experience with you, (in search of the holy grail :D ) 

I always wanted to know the exact point of reversal, just like every other trader (even 1 without one pip missing), and to find this i gave up making profit for a while and start seeking for it. For some of my trades (about %10 at the moment) i find the exact tops even on 5 min charts just with having an avera rsi of GBPUSD and EURUSD. It really show me the way for many times. But of course there should be more to find the perfect solution.

In my search i also noticed that zigzag reversal just not about bigger bearish power or bigger bullish power. First the zig must be ready for the zag and this happens when the total power is in the balance but balance starts to turn to other side and right on that exact moment  if a bigger power comes it reverses. Bigger powers always come inside a zigzag wave but if the zig is not ready and not balanced yet it is just a fake signal which costs some other guy who did the sell or buy. So this might be a filtering method of volume spikes. (?) We wont know unless we try it :)

On range bars and renko bars this balancing zig and balanced zag theory was more obvious but not exact. So there is still sth we need to figure also for this filter.

And for the collecting data part seeing big money is important but it should be adaptive to the zigzags reversal points volume. I mean if we look for the money bigger than 20m for example there might be many reversals that just needs 3m volume and reverse power. Maybe an adaptive bell curve "c" area could help this and a's would be the needed power (again another question mark)

After figuring the basics then USD couples and against usd couple ask bid volumes it will give us the direction i believe. 

That what i got for now,
Best regars,

96
9600302 · 9 years ago

@iburakbirer

I admit that these are fascinating ideas.

I will see what I can do.

IB
iburakbirer · 9 years ago

This is purely amazing! I have an idea about your amazing work. Would you like to try to collect data not just for a bar but for a zigzag wave? So it would show every zigzag waves true power. With the current version i believe it can be the ultimate reversal indicator.

And the other idea could be this;
- Collect all the major USD, GBP, EUR, JPY pairs ask bid volumes and show them in a total for given periods.
USD: 850M 
EUR: 460M 
GBP: 690M 
JPY: 410M etc

Don't you think this would give the perfect real time sentiment? Thanks for the amazing indicator again. 

 

96
9600302 · 9 years ago

@Iwori

That is nice to hear. Thank you and good luck with this indicator. :-)

Iwori's avatar
Iwori · 9 years ago

Thank you very much. I see the big Shark :)