Table of Contents

Candles and footprint

Candles

GetCandle(bar) returns the IndicatorCandle of a bar. Bars are numbered from 0 to CurrentBar - 1, where CurrentBar is the number of loaded bars; the bar parameter of OnCalculate is always valid. An index below 0 or above CurrentBar - 1 throws an exception and interrupts the calculation.

Besides the open, high, low, close, the volume, the bid and ask volumes and the delta, a candle has:

  • LastTime: the time of the last trade of the bar;
  • MaxDelta, MinDelta: the largest and the smallest delta the bar had;
  • MaxOI, MinOI: the largest and the smallest open interest the bar had.
using ATAS.Indicators;

namespace ATAS.Docs.Samples.ChartIndicators.MarketData;

public class CandleValuesIndicator : Indicator
{
    protected override void OnCalculate(int bar, decimal value)
    {
        var candle = GetCandle(bar);

        var open = candle.Open;
        var close = candle.Close;
        var high = candle.High;
        var low = candle.Low;

        var volume = candle.Volume;
        var ask = candle.Ask;
        var bid = candle.Bid;
        var delta = candle.Delta;

        this[bar] = (high + low) / 2;
    }
}

On the current bar OnCalculate is called on every tick, so call GetCandle(bar) once per call and keep the result in a local variable (see Performance).

Footprint

The data of a bar at one price, a footprint cell, is a PriceVolumeInfo: the price, the volume, the bid and ask volumes, the number of ticks. A candle gives them several ways:

using ATAS.Indicators;

namespace ATAS.Docs.Samples.ChartIndicators.MarketData;

public class FootprintDataIndicator : Indicator
{
    protected override void OnCalculate(int bar, decimal value)
    {
        var candle = GetCandle(bar);

        // The level at one price
        var highData = candle.GetPriceVolumeInfo(candle.High);

        if (highData != null)
        {
            var highVolume = highData.Volume;
        }

        // The level with the maximum volume
        var maxVolumeData = candle.MaxVolumePriceInfo;

        if (maxVolumeData != null)
        {
            var maxVolume = maxVolumeData.Volume;
        }

        // Every level of the candle
        var positiveDeltaLevels = 0;

        foreach (var level in candle.GetAllPriceLevels())
        {
            if (level == null)
                continue;

            var price = level.Price;
            var volume = level.Volume;
            var delta = level.Ask - level.Bid;

            if (delta > 0)
                positiveDeltaLevels++;
        }

        this[bar] = positiveDeltaLevels;
    }
}

Iterating the cells of a candle is far heavier than reading the candle itself: do it only when necessary and cache the intermediate results.