Table of Contents

Data series

A data series holds one value per bar and is drawn by the platform according to its type and settings. The kinds of series and what each one is for:

Series Element Used for
ValueDataSeries decimal Lines, histograms, points, arrows
RangeDataSeries RangeValue A filled area between two values
PaintbarsDataSeries Color? The color of each bar
CandleDataSeries Candle Candles drawn by the indicator
CandlePartSeries decimal A part of the chart candles (open, high, ...) as a series
IndicatorSeries decimal A series of another indicator as a source
PriceSelectionDataSeries List of PriceSelectionValue Marked price levels in bars and footprint cells
ObjectDataSeries object Any object linked to a bar

Create the series in the constructor and add them to DataSeries; the first series, DataSeries[0], is a ValueDataSeries created by the base class and can be replaced (DataSeries[0] = _mySeries). The element with the index of the bar is written in OnCalculate.

ValueDataSeries: numbers

A decimal per bar; every indicator has one from the start. Properties:

Methods: SetPointOfEndLine(bar) interrupts the line at a bar, RemovePointOfEndLine(bar) removes such a point, IsThisPointOfStartBar(bar) tells whether a line starts at the bar.

RangeDataSeries: ranges

Each element is a RangeValue with Upper and Lower; the area between them is filled with RangeColor. ScaleIt and Visible work as for the other series. Bollinger Bands with a filled band:

using System.Windows.Media;

using ATAS.Indicators;
using ATAS.Indicators.Technical;

namespace ATAS.Docs.Samples.ChartIndicators;

public class BollingerBandsIndicator : Indicator
{
    private readonly RangeDataSeries _band = new("BackGround");
    private readonly StdDev _dev = new();
    private readonly SMA _sma = new();
    private decimal _width;

    public int Period
    {
        get => _sma.Period;
        set
        {
            if (value <= 0)
                return;

            _sma.Period = _dev.Period = value;
            RecalculateValues();
        }
    }

    public decimal Width
    {
        get => _width;
        set
        {
            if (value <= 0)
                return;

            _width = value;
            RecalculateValues();
        }
    }

    public BollingerBandsIndicator()
    {
        ((ValueDataSeries)DataSeries[0]).Color = Colors.Green;

        DataSeries.Add(new ValueDataSeries("Up")
        {
            VisualType = VisualMode.Line
        });

        DataSeries.Add(new ValueDataSeries("Down")
        {
            VisualType = VisualMode.Line
        });

        DataSeries.Add(_band);
        Period = 10;
        Width = 1;
    }

    protected override void OnCalculate(int bar, decimal value)
    {
        var sma = _sma.Calculate(bar, value);
        var dev = _dev.Calculate(bar, value);

        this[bar] = sma;

        DataSeries[1][bar] = sma + dev * Width;
        DataSeries[2][bar] = sma - dev * Width;

        _band[bar].Upper = sma + dev * Width;
        _band[bar].Lower = sma - dev * Width;
    }
}

PaintbarsDataSeries: bar colors

Each element is a nullable color: System.Windows.Media.Color? in the classic ATAS, System.Drawing.Color? in ATAS X. A null element leaves the bar with its standard color. Visible toggles the series; HideChart hides the standard bars, for example when the indicator draws its own candles instead of them, as the Heiken Ashi below does:

using System;

using ATAS.Indicators;

namespace ATAS.Docs.Samples.ChartIndicators;

public class HeikenAshiIndicator : Indicator
{
    private readonly CandleDataSeries _candles = new("Heiken Ashi");
    private readonly PaintbarsDataSeries _bars = new("Bars") { IsHidden = true, HideChart = true };

    public HeikenAshiIndicator() : base(true)
    {
        DenyToChangePanel = true;
        DataSeries[0] = _bars;
        DataSeries.Add(_candles);
    }

    protected override void OnCalculate(int bar, decimal value)
    {
        var candle = GetCandle(bar);

        if (bar == 0)
        {
            _candles[bar] = new Candle
            {
                Close = candle.Close,
                High = candle.High,
                Low = candle.Low,
                Open = candle.Open
            };
        }
        else
        {
            var prevCandle = _candles[bar - 1];
            var close = (candle.Open + candle.Close + candle.High + candle.Low) * 0.25m;
            var open = (prevCandle.Open + prevCandle.Close) * 0.5m;
            var high = Math.Max(Math.Max(close, open), candle.High);
            var low = Math.Min(Math.Min(close, open), candle.Low);

            _candles[bar] = new Candle
            {
                Close = close,
                High = high,
                Low = low,
                Open = open,
            };
        }
    }
}

A filter that colors the bars whose volume (or ticks, delta, bid or ask volume) is within a range:

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Windows.Media;

using ATAS.Indicators;

namespace ATAS.Docs.Samples.ChartIndicators;

[DisplayName("Bar's volume filter")]
public class BarVolumeFilterIndicator : Indicator
{
    public enum VolumeType
    {
        Volume,
        Ticks,
        Delta,
        Bid,
        Ask
    }

    private readonly PaintbarsDataSeries _paintBars = new("Paint bars");

    private int _minFilter;
    private int _maxFilter = 100;
    private Color _color = Colors.Orange;
    private VolumeType _volumeType;

    [Display(Name = "Type", Order = 5)]
    public VolumeType Type
    {
        get => _volumeType;
        set
        {
            _volumeType = value;
            RecalculateValues();
        }
    }

    [Display(Name = "Minimum", Order = 10)]
    public int MinFilter
    {
        get => _minFilter;
        set
        {
            _minFilter = value;
            RecalculateValues();
        }
    }

    [Display(Name = "Maximum", Order = 20)]
    public int MaxFilter
    {
        get => _maxFilter;
        set
        {
            _maxFilter = value;
            RecalculateValues();
        }
    }

    [Display(Name = "Color", Order = 30)]
    public Color FilterColor
    {
        get => _color;
        set
        {
            _color = value;
            RecalculateValues();
        }
    }

    public BarVolumeFilterIndicator() : base(true)
    {
        DataSeries[0] = _paintBars;
        _paintBars.IsHidden = true;
        DenyToChangePanel = true;
    }

    protected override void OnCalculate(int bar, decimal value)
    {
        var candle = GetCandle(bar);

        var volume = Type switch
        {
            VolumeType.Volume => candle.Volume,
            VolumeType.Ticks => candle.Ticks,
            VolumeType.Delta => candle.Delta,
            VolumeType.Bid => candle.Bid,
            VolumeType.Ask => candle.Ask,
            _ => throw new ArgumentOutOfRangeException()
        };

        if (volume > _minFilter && volume <= _maxFilter)
            _paintBars[bar] = _color;
        else
            _paintBars[bar] = null;
    }
}

CandleDataSeries: candles

Each element is a Candle drawn by the platform. An inverted chart in a separate panel:

using ATAS.Indicators;

namespace ATAS.Docs.Samples.ChartIndicators;

public class ReversalChartIndicator : Indicator
{
    private readonly CandleDataSeries _reversalCandles = new("Candles");

    public ReversalChartIndicator()
    {
        ((ValueDataSeries)DataSeries[0]).VisualType = VisualMode.Hide;
        DataSeries.Add(_reversalCandles);
        Panel = IndicatorDataProvider.NewPanel;
    }

    protected override void OnCalculate(int bar, decimal value)
    {
        var candle = GetCandle(bar);
        _reversalCandles[bar].High = -candle.High;
        _reversalCandles[bar].Low = -candle.Low;
        _reversalCandles[bar].Open = -candle.Open;
        _reversalCandles[bar].Close = -candle.Close;
    }
}

CandlePartSeries

A decimal series derived from one part of the chart candles (IndicatorCandle created by an ICandleCreator). The part is a DataSeriesType: Open, High, Low, Close, Volume, HL2, HLC3, OHLC4, HLCC4 or Bars (for Bars the values are 0); any other value throws ArgumentOutOfRangeException in the constructor.

IndicatorSeries

A wrapper that exposes a series of another indicator through IDataSeries, so that one indicator serves as the data source of another (see Composite indicators).

PriceSelectionDataSeries: marked price levels

Each element is the list of PriceSelectionValue of the bar: the price levels to mark in the bar or in its footprint cells, as the built-in Cluster Search does. The example marks the cells whose volume exceeds a filter:

using System.Linq;

using ATAS.Indicators;

namespace ATAS.Docs.Samples.ChartIndicators;

public class ClusterSearchIndicator : Indicator
{
    private readonly PriceSelectionDataSeries _priceSelectionSeries = new("Clusters Selection");
    private int _filter = 10;

    public int Filter
    {
        get => _filter;
        set
        {
            _filter = value;
            RecalculateValues();
        }
    }

    public ClusterSearchIndicator()
    {
        DataSeries.Add(_priceSelectionSeries);
    }

    protected override void OnCalculate(int bar, decimal value)
    {
        var tickSize = InstrumentInfo?.TickSize ?? 0;

        if (tickSize <= 0)
            return;

        var candle = GetCandle(bar);

        for (var price = candle.High; price >= candle.Low; price -= tickSize)
        {
            var volumeInfo = candle.GetPriceVolumeInfo(price);

            if (volumeInfo == null)
                continue;

            if (volumeInfo.Volume > _filter)
            {
                var values = _priceSelectionSeries[bar];
                var priceSelection = values.FirstOrDefault(t => t.MinimumPrice == volumeInfo.Price);

                if (priceSelection == null)
                {
                    values.Add(new PriceSelectionValue(volumeInfo.Price)
                    {
                        VisualObject = ObjectType.Rectangle,
                        Size = 10
                    });
                }
            }
        }
    }
}

ObjectDataSeries: any object

Links any object to a bar; also a way to pass complex objects between indicators.