# Delta

```
//------------------------------------------------------------------------------
//
// Indicator Delta. Copyright (c) 2023 Tiger Trade Capital AG. All rights reserved.
//
//------------------------------------------------------------------------------
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Media;
using TigerTrade.Chart.Alerts;
using TigerTrade.Chart.Base;
using TigerTrade.Chart.Indicators.Common;
using TigerTrade.Chart.Indicators.Enums;
using TigerTrade.Core.UI.Converters;
using TigerTrade.Dx;
 
namespace TigerTrade.Chart.Indicators.Custom
{
    [TypeConverter(typeof(EnumDescriptionTypeConverter))]
    [DataContract(Name = "DeltaViewType", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    public enum DeltaViewType
    {
        [EnumMember(Value = "Columns"), Description("Колонки")]
        Columns,
        [EnumMember(Value = "Candles"), Description("Свечи")]
        Candles
    }
 
    [DataContract(Name = "DeltaIndicator", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    [Indicator("X_Delta", "*Delta", false, Type = typeof(DeltaIndicator))]
    internal sealed class DeltaIndicator : IndicatorBase
    {
        private XBrush _deltaPlusBrush;
 
        private XPen _deltaPlusPen;
 
        private XColor _deltaPlusColor;
 
        [DataMember(Name = "DeltaPlusColor")]
        [Category("Стиль"), DisplayName("Delta+")]
        public XColor DeltaPlusColor
        {
            get => _deltaPlusColor;
            set
            {
                if (value == _deltaPlusColor)
                {
                    return;
                }
 
                _deltaPlusColor = value;
 
                _deltaPlusBrush = new XBrush(_deltaPlusColor);
 
                _deltaPlusPen = new XPen(_deltaPlusBrush, 1);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _deltaMinusBrush;
 
        private XPen _deltaMinusPen;
 
        private XColor _deltaMinusColor;
 
        [DataMember(Name = "DeltaMinusColor")]
        [Category("Стиль"), DisplayName("Delta-")]
        public XColor DeltaMinusColor
        {
            get => _deltaMinusColor;
            set
            {
                if (value == _deltaMinusColor)
                {
                    return;
                }
 
                _deltaMinusColor = value;
 
                _deltaMinusBrush = new XBrush(_deltaMinusColor);
 
                _deltaMinusPen = new XPen(_deltaMinusBrush, 1);
 
                OnPropertyChanged();
            }
        }
 
        private DeltaViewType _type;
 
        [DataMember(Name = "DeltaType"), DefaultValue(DeltaViewType.Columns)]
        [Category("Параметры"), DisplayName("Тип")]
        public DeltaViewType Type
        {
            get => _type;
            set
            {
                if (value == _type)
                {
                    return;
                }
 
                _type = value;
 
                OnPropertyChanged();
            }
        }
 
        private bool _minimize;
 
        [DataMember(Name = "Minimize"), DefaultValue(false)]
        [Category("Параметры"), DisplayName("Минимизировать")]
        public bool Minimize
        {
            get => _minimize;
            set
            {
                if (value == _minimize)
                {
                    return;
                }
 
                _minimize = value;
 
                OnPropertyChanged();
            }
        }
 
        private IndicatorNullIntParam _maxDeltaParam;
 
        [DataMember(Name = "MaxDeltaParam")]
        public IndicatorNullIntParam MaxDeltaParam
        {
            get => _maxDeltaParam ?? (_maxDeltaParam = new IndicatorNullIntParam(null));
            set => _maxDeltaParam = value;
        }
 
        [DefaultValue(null)]
        [Category("Параметры"), DisplayName("Макс. дельта")]
        public int? MaxDelta
        {
            get => MaxDeltaParam.Get(SettingsLongKey);
            set
            {
                if (!MaxDeltaParam.Set(SettingsLongKey, value, 0))
                {
                    return;
                }
 
                OnPropertyChanged();
            }
        }
 
        private IndicatorNullIntParam _filter1MinParam;
 
        [DataMember(Name = "Filter1MinParam")]
        public IndicatorNullIntParam Filter1MinParam
        {
            get => _filter1MinParam ?? (_filter1MinParam = new IndicatorNullIntParam(null));
            set => _filter1MinParam = value;
        }
 
        [DefaultValue(null)]
        [Category("Фильтр 1"), DisplayName("Минимум")]
        public int? Filter1Min
        {
            get => Filter1MinParam.Get(SettingsLongKey);
            set
            {
                if (!Filter1MinParam.Set(SettingsLongKey, value, 0))
                {
                    return;
                }
 
                OnPropertyChanged();
            }
        }
 
        private IndicatorNullIntParam _filter1MaxParam;
 
        [DataMember(Name = "Filter1MaxParam")]
        public IndicatorNullIntParam Filter1MaxParam
        {
            get => _filter1MaxParam ?? (_filter1MaxParam = new IndicatorNullIntParam(null));
            set => _filter1MaxParam = value;
        }
 
        [DefaultValue(null)]
        [Category("Фильтр 1"), DisplayName("Максимум")]
        public int? Filter1Max
        {
            get => Filter1MaxParam.Get(SettingsLongKey);
            set
            {
                if (!Filter1MaxParam.Set(SettingsLongKey, value, 0))
                {
                    return;
                }
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _filter1PlusBrush;
 
        private XPen _filter1PlusPen;
 
        private XColor _filter1PlusColor;
 
        [DataMember(Name = "Filter1PlusColor")]
        [Category("Фильтр 1"), DisplayName("Цвет+")]
        public XColor Filter1PlusColor
        {
            get => _filter1PlusColor;
            set
            {
                if (value == _filter1PlusColor)
                {
                    return;
                }
 
                _filter1PlusColor = value;
 
                _filter1PlusBrush = new XBrush(_filter1PlusColor);
                _filter1PlusPen = new XPen(_filter1PlusBrush, 1);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _filter1MinusBrush;
 
        private XPen _filter1MinusPen;
 
        private XColor _filter1MinusColor;
 
        [DataMember(Name = "Filter1MinusColor")]
        [Category("Фильтр 1"), DisplayName("Цвет-")]
        public XColor Filter1MinusColor
        {
            get => _filter1MinusColor;
            set
            {
                if (value == _filter1MinusColor)
                {
                    return;
                }
 
                _filter1MinusColor = value;
 
                _filter1MinusBrush = new XBrush(_filter1MinusColor);
                _filter1MinusPen = new XPen(_filter1MinusBrush, 1);
 
                OnPropertyChanged();
            }
        }
 
        private ChartAlertSettings _filter1Alert;
 
        [DataMember(Name = "Filter1Alert")]
        [Category("Фильтр 1"), DisplayName("Оповещение")]
        public ChartAlertSettings Filter1Alert
        {
            get => _filter1Alert ?? (_filter1Alert = new ChartAlertSettings());
            set
            {
                if (Equals(value, _filter1Alert))
                {
                    return;
                }
 
                _filter1Alert = value;
 
                OnPropertyChanged();
            }
        }
 
        private IndicatorNullIntParam _filter2MinParam;
 
        [DataMember(Name = "Filter2MinParam")]
        public IndicatorNullIntParam Filter2MinParam
        {
            get => _filter2MinParam ?? (_filter2MinParam = new IndicatorNullIntParam(null));
            set => _filter2MinParam = value;
        }
 
        [DefaultValue(null)]
        [Category("Фильтр 2"), DisplayName("Минимум")]
        public int? Filter2Min
        {
            get => Filter2MinParam.Get(SettingsLongKey);
            set
            {
                if (!Filter2MinParam.Set(SettingsLongKey, value, 0))
                {
                    return;
                }
 
                OnPropertyChanged();
            }
        }
 
        private IndicatorNullIntParam _filter2MaxParam;
 
        [DataMember(Name = "Filter2MaxParam")]
        public IndicatorNullIntParam Filter2MaxParam
        {
            get => _filter2MaxParam ?? (_filter2MaxParam = new IndicatorNullIntParam(null));
            set => _filter2MaxParam = value;
        }
 
        [DefaultValue(null)]
        [Category("Фильтр 2"), DisplayName("Максимум")]
        public int? Filter2Max
        {
            get => Filter2MaxParam.Get(SettingsLongKey);
            set
            {
                if (!Filter2MaxParam.Set(SettingsLongKey, value, 0))
                {
                    return;
                }
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _filter2PlusBrush;
 
        private XPen _filter2PlusPen;
 
        private XColor _filter2PlusColor;
 
        [DataMember(Name = "Filter2PlusColor")]
        [Category("Фильтр 2"), DisplayName("Цвет+")]
        public XColor Filter2PlusColor
        {
            get => _filter2PlusColor;
            set
            {
                if (value == _filter2PlusColor)
                {
                    return;
                }
 
                _filter2PlusColor = value;
 
                _filter2PlusBrush = new XBrush(_filter2PlusColor);
                _filter2PlusPen = new XPen(_filter2PlusBrush, 1);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _filter2MinusBrush;
 
        private XPen _filter2MinusPen;
 
        private XColor _filter2MinusColor;
 
        [DataMember(Name = "Filter2MinusColor")]
        [Category("Фильтр 2"), DisplayName("Цвет-")]
        public XColor Filter2MinusColor
        {
            get => _filter2MinusColor;
            set
            {
                if (value == _filter2MinusColor)
                {
                    return;
                }
 
                _filter2MinusColor = value;
 
                _filter2MinusBrush = new XBrush(_filter2MinusColor);
                _filter2MinusPen = new XPen(_filter2MinusBrush, 1);
 
                OnPropertyChanged();
            }
        }
 
        private ChartAlertSettings _filter2Alert;
 
        [DataMember(Name = "Filter2Alert")]
        [Category("Фильтр 2"), DisplayName("Оповещение")]
        public ChartAlertSettings Filter2Alert
        {
            get => _filter2Alert ?? (_filter2Alert = new ChartAlertSettings());
            set
            {
                if (Equals(value, _filter2Alert))
                {
                    return;
                }
 
                _filter2Alert = value;
 
                OnPropertyChanged();
            }
        }
 
        private IndicatorNullIntParam _filter3MinParam;
 
        [DataMember(Name = "Filter3MinParam")]
        public IndicatorNullIntParam Filter3MinParam
        {
            get => _filter3MinParam ?? (_filter3MinParam = new IndicatorNullIntParam(null));
            set => _filter3MinParam = value;
        }
 
        [DefaultValue(null)]
        [Category("Фильтр 3"), DisplayName("Минимум")]
        public int? Filter3Min
        {
            get => Filter3MinParam.Get(SettingsLongKey);
            set
            {
                if (!Filter3MinParam.Set(SettingsLongKey, value, 0))
                {
                    return;
                }
 
                OnPropertyChanged();
            }
        }
 
        private IndicatorNullIntParam _filter3MaxParam;
 
        [DataMember(Name = "Filter3MaxParam")]
        public IndicatorNullIntParam Filter3MaxParam
        {
            get => _filter3MaxParam ?? (_filter3MaxParam = new IndicatorNullIntParam(null));
            set => _filter3MaxParam = value;
        }
 
        [DefaultValue(null)]
        [Category("Фильтр 3"), DisplayName("Максимум")]
        public int? Filter3Max
        {
            get => Filter3MaxParam.Get(SettingsLongKey);
            set
            {
                if (!Filter3MaxParam.Set(SettingsLongKey, value, 0))
                {
                    return;
                }
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _filter3PlusBrush;
 
        private XPen _filter3PlusPen;
 
        private XColor _filter3PlusColor;
 
        [DataMember(Name = "Filter3PlusColor")]
        [Category("Фильтр 3"), DisplayName("Цвет+")]
        public XColor Filter3PlusColor
        {
            get => _filter3PlusColor;
            set
            {
                if (value == _filter3PlusColor)
                {
                    return;
                }
 
                _filter3PlusColor = value;
 
                _filter3PlusBrush = new XBrush(_filter3PlusColor);
                _filter3PlusPen = new XPen(_filter3PlusBrush, 1);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _filter3MinusBrush;
 
        private XPen _filter3MinusPen;
 
        private XColor _filter3MinusColor;
 
        [DataMember(Name = "Filter3MinusColor")]
        [Category("Фильтр 3"), DisplayName("Цвет-")]
        public XColor Filter3MinusColor
        {
            get => _filter3MinusColor;
            set
            {
                if (value == _filter3MinusColor)
                {
                    return;
                }
 
                _filter3MinusColor = value;
 
                _filter3MinusBrush = new XBrush(_filter3MinusColor);
                _filter3MinusPen = new XPen(_filter3MinusBrush, 1);
 
                OnPropertyChanged();
            }
        }
 
        private ChartAlertSettings _filter3Alert;
 
        [DataMember(Name = "Filter3Alert")]
        [Category("Фильтр 3"), DisplayName("Оповещение")]
        public ChartAlertSettings Filter3Alert
        {
            get => _filter3Alert ?? (_filter3Alert = new ChartAlertSettings());
            set
            {
                if (Equals(value, _filter3Alert))
                {
                    return;
                }
 
                _filter3Alert = value;
 
                OnPropertyChanged();
            }
        }
 
        [Browsable(false)]
        public override IndicatorCalculation Calculation => IndicatorCalculation.OnEachTick;
 
        public override bool IntegerValues => true;
 
        private int _filter1SignalIndex;
        private int _filter2SignalIndex;
        private int _filter3SignalIndex;
 
        public DeltaIndicator()
        {
            DeltaPlusColor = Color.FromArgb(255, 30, 144, 255);
            DeltaMinusColor = Color.FromArgb(255, 178, 34, 34);
 
            Type = DeltaViewType.Columns;
 
            Minimize = false;
 
            Filter1PlusColor = Colors.Orange;
            Filter1MinusColor = Colors.Orange;
 
            Filter2PlusColor = Colors.Orange;
            Filter2MinusColor = Colors.Orange;
 
            Filter3PlusColor = Colors.Orange;
            Filter3MinusColor = Colors.Orange;
 
            _filter1SignalIndex = -1;
            _filter2SignalIndex = -1;
            _filter3SignalIndex = -1;
        }
 
        protected override void Execute()
        {
            if (ClearData)
            {
                _filter1SignalIndex = -1;
                _filter2SignalIndex = -1;
                _filter3SignalIndex = -1;
            }
 
            var index = DataProvider.Count;
 
            var cluster = DataProvider.GetCluster(index - 1);
 
            if (cluster == null)
            {
                return;
            }
 
            var realDelta = cluster.Delta;
            var absDelta = Math.Abs(realDelta);
 
            if (Filter1Alert.IsActive && _filter1SignalIndex < index)
            {
                var min = Filter1Min ?? -1;
                var max = Filter1Max ?? -1;
 
                if (min >= 0 && absDelta >= min && (max < 0 || absDelta <= max))
                {
                    _filter1SignalIndex = index;
 
                    AddAlert(Filter1Alert,
                        $"Delta: фильтр 1, значение {DataProvider.Symbol.FormatSizeFull(realDelta)}.");
                }
            }
 
            if (Filter2Alert.IsActive && _filter2SignalIndex < index)
            {
                var min = Filter2Min ?? -1;
                var max = Filter2Max ?? -1;
 
                if (min >= 0 && absDelta >= min && (max < 0 || absDelta <= max))
                {
                    _filter2SignalIndex = index;
 
                    AddAlert(Filter2Alert,
                        $"Delta: фильтр 2, значение {DataProvider.Symbol.FormatSizeFull(realDelta)}.");
                }
            }
 
            if (Filter3Alert.IsActive && _filter3SignalIndex < index)
            {
                var min = Filter3Min ?? -1;
                var max = Filter3Max ?? -1;
 
                if (min >= 0 && absDelta >= min && (max < 0 || absDelta <= max))
                {
                    _filter3SignalIndex = index;
 
                    AddAlert(Filter3Alert,
                        $"Delta: фильтр 3, значение {DataProvider.Symbol.FormatSizeFull(realDelta)}.");
                }
            }
        }
 
        public override bool GetMinMax(out double min, out double max)
        {
            min = double.MaxValue;
            max = double.MinValue;
 
            if (Type == DeltaViewType.Candles)
            {
                for (var i = 0; i < Canvas.Count; i++)
                {
                    var index = Canvas.GetIndex(i);
 
                    var cluster = DataProvider.GetCluster(index);
 
                    if (cluster == null || cluster.Delta == 0)
                    {
                        continue;
                    }
 
                    var deltaHigh = (double)cluster.DeltaHigh;
                    var deltaLow = (double)cluster.DeltaLow;
 
                    if (Minimize && cluster.Delta < 0)
                    {
                        max = Math.Max(max, -deltaLow);
                        min = Math.Min(min, -deltaHigh);
 
                    }
                    else
                    {
                        min = Math.Min(min, deltaLow);
                        max = Math.Max(max, deltaHigh);
                    }
                }
            }
            else
            {
                for (var i = 0; i < Canvas.Count; i++)
                {
                    var index = Canvas.GetIndex(i);
 
                    var cluster = DataProvider.GetCluster(index);
 
                    if (cluster == null || cluster.Delta == 0)
                    {
                        continue;
                    }
 
                    var delta = (double)cluster.Delta;
 
                    if (Minimize)
                    {
                        max = Math.Max(max, Math.Abs(delta));
                    }
                    else
                    {
                        min = Math.Min(min, delta);
                        max = Math.Max(max, delta);
                    }
                }
 
                if (Minimize)
                {
                    min = 0.0;
                }
            }
 
            var maxDelta = MaxDelta ?? -1;
 
            if (maxDelta >= 0 && max > maxDelta)
            {
                max = maxDelta;
            }
 
            if (maxDelta >= 0 && min < -maxDelta)
            {
                min = -maxDelta;
            }
 
            return true;
        }
 
        public override void Render(DxVisualQueue visual)
        {
            var min1 = Filter1Min ?? -1;
            var max1 = Filter1Max ?? -1;
            var min2 = Filter2Min ?? -1;
            var max2 = Filter2Max ?? -1;
            var min3 = Filter3Min ?? -1;
            var max3 = Filter3Max ?? -1;
 
            var maxDelta = MaxDelta ?? -1;
            var maxPoint = (int)GetY((double)maxDelta);
            var minPoint = (int)GetY((double)-maxDelta);
 
            var zeroPoint = (int)GetY(0.0);
 
            switch (Type)
            {
                case DeltaViewType.Candles:
                    {
                        var width = (int)(Canvas.ColumnWidth * Canvas.ColumnPercent + 0.4);
                        var halfWith = Math.Max((int)(width / 2.0), 1.0);
 
                        var openY = zeroPoint;
 
                        for (var i = 0; i < Canvas.Count; i++)
                        {
                            var index = Canvas.GetIndex(i);
 
                            var cluster = DataProvider.GetCluster(index);
 
                            if (cluster == null || cluster.Delta == 0)
                            {
                                continue;
                            }
 
                            var delta = cluster.Delta;
 
                            var isUp = delta > 0;
 
                            var centerX = (int)Canvas.GetX(index);
                            var highY = (int)GetY(cluster.DeltaHigh);
                            var lowY = (int)GetY(cluster.DeltaLow);
                            var closeY = (int)GetY(delta);
 
                            if (Minimize && delta < 0)
                            {
                                highY = (int) GetY(-cluster.DeltaLow);
                                lowY = (int) GetY(-cluster.DeltaHigh);
                                closeY = (int) GetY(-delta);
                            }
 
                            if (maxDelta >= 0)
                            {
                                if (delta > 0 || Minimize)
                                {
                                    closeY = Math.Max(closeY, maxPoint);
                                    highY = Math.Max(highY, maxPoint);
                                    lowY = Math.Min(lowY, minPoint);
                                }
                                else
                                {
                                    closeY = Math.Min(closeY, minPoint);
                                    highY = Math.Max(highY, maxPoint);
                                    lowY = Math.Min(lowY, minPoint);
                                }
                            }
 
                            var topY = Math.Min(openY, closeY);
                            var bottomY = Math.Max(openY, closeY);
 
                            var height = bottomY - topY;
 
                            var backBrush = isUp ? _deltaPlusBrush : _deltaMinusBrush;
                            var backPen = isUp ? _deltaPlusPen : _deltaMinusPen;
 
                            var absDelta = Math.Abs(delta);
 
                            if (min1 >= 0 && absDelta >= min1 && (max1 < 0 || absDelta <= max1))
                            {
                                if (delta > 0)
                                {
                                    backBrush = _filter1PlusBrush;
                                    backPen = _filter1PlusPen;
                                }
                                else
                                {
                                    backBrush = _filter1MinusBrush;
                                    backPen = _filter1MinusPen;
                                }
                            }
                            else if (min2 >= 0 && absDelta >= min2 && (max2 < 0 || absDelta <= max2))
                            {
                                if (delta > 0)
                                {
                                    backBrush = _filter2PlusBrush;
                                    backPen = _filter2PlusPen;
                                }
                                else
                                {
                                    backBrush = _filter2MinusBrush;
                                    backPen = _filter2MinusPen;
                                }
                            }
                            else if (min3 >= 0 && absDelta >= min3 && (max3 < 0 || absDelta <= max3))
                            {
                                if (delta > 0)
                                {
                                    backBrush = _filter3PlusBrush;
                                    backPen = _filter3PlusPen;
                                }
                                else
                                {
                                    backBrush = _filter3MinusBrush;
                                    backPen = _filter3MinusPen;
                                }
                            }
 
                            if (height == 0 || width <= 1)
                            {
                                if (highY == lowY)
                                {
                                    lowY++;
                                }
 
                                visual.DrawLine(backPen,
                                        new Point(centerX, highY),
                                        new Point(centerX, lowY));
                            }
                            else
                            {
                                visual.DrawLine(backPen,
                                    new Point(centerX, highY),
                                    new Point(centerX, topY));
 
                                visual.DrawLine(backPen,
                                    new Point(centerX, bottomY),
                                    new Point(centerX, lowY));
                            }
 
                            if (width > 1)
                            {
                                if (height == 0)
                                {
                                    visual.DrawLine(backPen,
                                        new Point(centerX - halfWith, topY),
                                        new Point(centerX + halfWith + 1, topY));
                                }
                                else
                                {
                                    visual.FillRectangle(backBrush,
                                        new Rect(centerX - halfWith, topY, halfWith*2 + 1, height));
                                }
                            }
                        }
                    }
 
                    break;
 
                case DeltaViewType.Columns:
                    {
                        var width = Math.Max(Canvas.ColumnWidth - 1, 1);
 
                        for (var i = 0; i < Canvas.Count; i++)
                        {
                            var index = Canvas.GetIndex(i);
 
                            var cluster = DataProvider.GetCluster(index);
 
                            if (cluster == null || cluster.Delta == 0)
                            {
                                continue;
                            }
 
                            var delta = cluster.Delta;
 
                            var x = Canvas.GetX(index);
                            var y = GetY(Minimize ? Math.Abs(delta) : delta);
 
                            if (maxDelta >= 0)
                            {
                                if (Minimize)
                                {
                                    y = Math.Max(y, maxPoint);
                                }
                                else
                                {
                                    y = delta > 0 ? Math.Max(y, maxPoint) : Math.Min(y, minPoint);
                                }
                            }
 
                            var h = zeroPoint - (int)y;
 
                            if (h < 0.0)
                            {
                                y += h;
                                h = -h;
                            }
 
                            if (Minimize || delta > 0)
                            {
                                if (h < 1)
                                {
                                    y = zeroPoint - 1;
                                    h = 1;
                                }
                            }
                            else
                            {
                                if (h < 1)
                                {
                                    y = zeroPoint;
                                    h = 1;
                                }
                            }
 
                            var isUp = delta > 0;
 
                            XBrush filterBrush = null;
                            XPen filterPen = null;
 
                            var absDelta = Math.Abs(delta);
 
                            if (min1 >= 0 && absDelta >= min1 && (max1 < 0 || absDelta <= max1))
                            {
                                if (delta > 0)
                                {
                                    filterBrush = _filter1PlusBrush;
                                    filterPen = _filter1PlusPen;
                                }
                                else
                                {
                                    filterBrush = _filter1MinusBrush;
                                    filterPen = _filter1MinusPen;
                                }
                            }
                            else if (min2 >= 0 && absDelta >= min2 && (max2 < 0 || absDelta <= max2))
                            {
                                if (delta > 0)
                                {
                                    filterBrush = _filter2PlusBrush;
                                    filterPen = _filter2PlusPen;
                                }
                                else
                                {
                                    filterBrush = _filter2MinusBrush;
                                    filterPen = _filter2MinusPen;
                                }
                            }
                            else if (min3 >= 0 && absDelta >= min3 && (max3 < 0 || absDelta <= max3))
                            {
                                if (delta > 0)
                                {
                                    filterBrush = _filter3PlusBrush;
                                    filterPen = _filter3PlusPen;
                                }
                                else
                                {
                                    filterBrush = _filter3MinusBrush;
                                    filterPen = _filter3MinusPen;
                                }
                            }
 
                            if (width > 1.0)
                            {
                                var rect = new Rect(x - width / 2.0, y, width, h);
 
                                if (filterBrush != null)
                                {
                                    visual.FillRectangle(filterBrush, rect);
                                }
                                else
                                {
                                    visual.FillRectangle(isUp ? _deltaPlusBrush : _deltaMinusBrush, rect);
                                }
                            }
                            else
                            {
                                if (filterBrush != null)
                                {
                                    visual.DrawLine(filterPen, x, y, x, y + h);
                                }
                                else
                                {
                                    visual.DrawLine(isUp ? _deltaPlusPen : _deltaMinusPen, x, y, x, y + h);
                                }
                            }
                        }
                    }
                    break;
            }
        }
 
        public override List<IndicatorValueInfo> GetValues(int cursorPos)
        {
            var info = new List<IndicatorValueInfo>();
 
            var cluster = DataProvider.GetCluster(cursorPos);
 
            if (cluster == null)
            {
                return info;
            }
 
            var s = Canvas.FormatValue((double)cluster.Delta);
 
            info.Add(new IndicatorValueInfo(s, Canvas.Theme.ChartFontBrush));
 
            return info;
        }
 
        public override void GetLabels(ref List<IndicatorLabelInfo> labels)
        {
            if (DataProvider.Count <= Canvas.Start)
            {
                return;
            }
 
            var cluster = DataProvider.GetCluster(DataProvider.Count - 1 - Canvas.Start);
 
            if (cluster == null)
            {
                return;
            }
 
            var delta = Minimize ? Math.Abs(cluster.Delta) : cluster.Delta;
 
            labels.Add(new IndicatorLabelInfo((double)delta, cluster.Delta > 0 ? _deltaPlusColor : _deltaMinusColor));
        }
 
        public override bool CheckAlert(double value, int distance, ref int lastIndex, ref double lastValue)
        {
            if (DataProvider.Count == lastIndex && value == lastValue)
            {
                return false;
            }
 
            var cluster = DataProvider.GetCluster(DataProvider.Count - 1);
 
            if (cluster == null)
            {
                return false;
            }
 
            var result = false;
 
            var delta = (double)cluster.Delta;
 
            if (value > 0 && delta >= value - distance)
            {
                result = true;
            }
            else if (value < 0 && delta <= value + distance)
            {
                result = true;
            }
 
            if (result == false)
            {
                return false;
            }
 
            lastIndex = DataProvider.Count;
            lastValue = value;
 
            return true;
        }
 
        public override void ApplyColors(IChartTheme theme)
        {
            DeltaPlusColor = theme.PaletteColor6;
            DeltaMinusColor = theme.PaletteColor7;
 
            base.ApplyColors(theme);
        }
 
        public override void CopyTemplate(IndicatorBase indicator, bool style)
        {
            var i = (DeltaIndicator)indicator;
 
            DeltaPlusColor = i.DeltaPlusColor;
            DeltaMinusColor = i.DeltaMinusColor;
 
            Type = i.Type;
            Minimize = i.Minimize;
 
            MaxDeltaParam.Copy(i.MaxDeltaParam);
 
            Filter1MinParam.Copy(i.Filter1MinParam);
            Filter1MaxParam.Copy(i.Filter1MaxParam);
 
            OnPropertyChanged(nameof(Filter1Min));
            OnPropertyChanged(nameof(Filter1Max));
 
            Filter1PlusColor = i.Filter1PlusColor;
            Filter1MinusColor = i.Filter1MinusColor;
 
            Filter1Alert.Copy(i.Filter1Alert, !style);
 
            OnPropertyChanged(nameof(Filter1Alert));
 
            Filter2MinParam.Copy(i.Filter2MinParam);
            Filter2MaxParam.Copy(i.Filter2MaxParam);
 
            OnPropertyChanged(nameof(Filter2Min));
            OnPropertyChanged(nameof(Filter2Max));
 
            Filter2PlusColor = i.Filter2PlusColor;
            Filter2MinusColor = i.Filter2MinusColor;
 
            Filter2Alert.Copy(i.Filter2Alert, !style);
 
            OnPropertyChanged(nameof(Filter2Alert));
 
            Filter3MinParam.Copy(i.Filter3MinParam);
            Filter3MaxParam.Copy(i.Filter3MaxParam);
 
            OnPropertyChanged(nameof(Filter3Min));
            OnPropertyChanged(nameof(Filter3Max));
 
            Filter3PlusColor = i.Filter3PlusColor;
            Filter3MinusColor = i.Filter3MinusColor;
 
            Filter3Alert.Copy(i.Filter3Alert, !style);
 
            OnPropertyChanged(nameof(Filter3Alert));
 
            base.CopyTemplate(indicator, style);
        }
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://support.tiger.com/english/development-for-tiger.trade-windows/indicator-examples/delta.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
