# Histogram

```
//------------------------------------------------------------------------------
//
// Индикатор Histogram. 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.Base.Enums;
using TigerTrade.Chart.Data;
using TigerTrade.Chart.Indicators.Common;
using TigerTrade.Chart.Indicators.Enums;
using TigerTrade.Core.UI.Converters;
using TigerTrade.Core.Utils.Time;
using TigerTrade.Dx;
 
namespace TigerTrade.Chart.Indicators.Custom
{
    [DataContract(Name = "HistogramPeriodType", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    [TypeConverter(typeof(EnumDescriptionTypeConverter))]
    public enum HistogramPeriodType
    {
        [EnumMember(Value = "Minute"), Description("Минута")]
        Minute,
        [EnumMember(Value = "Hour"), Description("Час")]
        Hour,
        [EnumMember(Value = "Day"), Description("День")]
        Day,
        [EnumMember(Value = "Week"), Description("Неделя")]
        Week,
        [EnumMember(Value = "Month"), Description("Месяц")]
        Month,
        [EnumMember(Value = "AllBars"), Description("Все бары")]
        AllBars,
        [EnumMember(Value = "CustomDate"), Description("Свой интервал")]
        CustomDate
    }
 
    [DataContract(Name = "HistogramViewType", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    [TypeConverter(typeof(EnumDescriptionTypeConverter))]
    public enum HistogramViewType
    {
        [EnumMember(Value = "Volume"), Description("Volume")]
        Volume,
        [EnumMember(Value = "Trades"), Description("Trades")]
        Trades,
        [EnumMember(Value = "Delta"), Description("Delta")]
        Delta,
        [EnumMember(Value = "BidAsk"), Description("Bid x Ask")]
        BidAsk,
    }
 
    [DataContract(Name = "HistogramCellViewType", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    [TypeConverter(typeof(EnumDescriptionTypeConverter))]
    public enum HistogramCellViewType
    {
        [EnumMember(Value = "Solid"), Description("Без отступов")]
        Solid,
        [EnumMember(Value = "Bars"), Description("С отступами")]
        Bars,
        [EnumMember(Value = "BorderedBars"), Description("С границей")]
        BorderedBars
    }
 
    [DataContract(Name = "HistogramIndicator", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    [Indicator("Z_Histogram", "*Histogram", true, Type = typeof(HistogramIndicator))]
    internal sealed class HistogramIndicator : IndicatorBase
    {
        private HistogramPeriodType _periodType;
 
        [DataMember(Name = "PeriodType")]
        [Category("Период"), DisplayName("Интервал")]
        public HistogramPeriodType PeriodType
        {
            get => _periodType;
            set
            {
                if (value == _periodType)
                {
                    return;
                }
 
                _periodType = value;
 
                _periodValue = _periodType == HistogramPeriodType.Minute ? 15 : 1;
 
                Clear();
 
                OnPropertyChanged();
                OnPropertyChanged(nameof(PeriodValue));
                OnPropertyChanged(nameof(PeriodRevers));
                OnPropertyChanged(nameof(StartDate));
                OnPropertyChanged(nameof(EndDate));
            }
        }
 
        private int _periodValue;
 
        [DataMember(Name = "PeriodValue")]
        [Category("Период"), DisplayName("Значение")]
        public int PeriodValue
        {
            get => _periodValue;
            set
            {
                value = Math.Max(1, value);
 
                if (value == _periodValue)
                {
                    return;
                }
 
                _periodValue = value;
 
                Clear();
 
                OnPropertyChanged();
            }
        }
 
        private bool _periodRevers;
 
        [DataMember(Name = "PeriodRevers")]
        [Category("Период"), DisplayName("От последнего бара")]
        public bool PeriodRevers
        {
            get => _periodRevers;
            set
            {
                if (value == _periodRevers)
                {
                    return;
                }
 
                _periodRevers = value;
 
                Clear();
 
                OnPropertyChanged();
            }
        }
 
        private DateTime? _startDate;
 
        [DataMember(Name = "StartDate")]
        [Category("Период"), DisplayName("Начальная дата")]
        public DateTime? StartDate
        {
            get => _startDate;
            set
            {
                if (value.Equals(_startDate))
                {
                    return;
                }
 
                _startDate = value;
 
                Clear();
 
                OnPropertyChanged();
            }
        }
 
        private DateTime? _endDate;
 
        [DataMember(Name = "EndDate")]
        [Category("Период"), DisplayName("Конечная дата")]
        public DateTime? EndDate
        {
            get => _endDate;
            set
            {
                if (value.Equals(_endDate))
                {
                    return;
                }
 
                _endDate = value;
 
                Clear();
 
                OnPropertyChanged();
            }
        }
 
        private HistogramViewType _histogramViewType;
 
        [DataMember(Name = "HistogramViewType"), DefaultValue(HistogramViewType.Volume)]
        [Category("Параметры"), DisplayName("Вид гистограммы")]
        public HistogramViewType HistogramViewType
        {
            get => _histogramViewType;
            set
            {
                if (value == _histogramViewType)
                {
                    return;
                }
 
                _histogramViewType = value;
 
                OnPropertyChanged();
            }
        }
 
        private HistogramCellViewType _histogramCellViewType;
 
        [DataMember(Name = "HistogramCellViewType"), DefaultValue(HistogramCellViewType.Solid)]
        [Category("Параметры"), DisplayName("Вид ячейки")]
        public HistogramCellViewType HistogramCellViewType
        {
            get => _histogramCellViewType;
            set
            {
                if (value == _histogramCellViewType)
                {
                    return;
                }
 
                _histogramCellViewType = value;
 
                OnPropertyChanged();
            }
        }
 
        private bool _histogramGradient;
 
        [DataMember(Name = "HistogramGradient"), DefaultValue(true)]
        [Category("Параметры"), DisplayName("Градиент")]
        public bool HistogramGradient
        {
            get => _histogramGradient;
            set
            {
                if (value == _histogramGradient)
                {
                    return;
                }
 
                _histogramGradient = value;
 
                OnPropertyChanged();
            }
        }
 
        private bool _histogramShowValues;
 
        [DataMember(Name = "HistogramShowValues"), DefaultValue(true)]
        [Category("Параметры"), DisplayName("Отображать значения")]
        public bool HistogramShowValues
        {
            get => _histogramShowValues;
            set
            {
                if (value == _histogramShowValues)
                {
                    return;
                }
 
                _histogramShowValues = value;
 
                OnPropertyChanged();
            }
        }
 
        private bool _histogramMinimizeValues;
 
        [DataMember(Name = "HistogramMinimizeValues")]
        [Category("Параметры"), DisplayName("Минимизировать значения")]
        public bool HistogramMinimizeValues
        {
            get => _histogramMinimizeValues;
            set
            {
                if (value == _histogramMinimizeValues)
                {
                    return;
                }
 
                _histogramMinimizeValues = value;
 
                OnPropertyChanged();
            }
        }
 
        private IndicatorIntParam _histogramRoundValueParam;
 
        [DataMember(Name = "HistogramRoundValuesParam")]
        public IndicatorIntParam HistogramRoundValuesParam
        {
            get => _histogramRoundValueParam ?? (_histogramRoundValueParam = new IndicatorIntParam(0));
            set => _histogramRoundValueParam = value;
        }
 
        [DefaultValue(0)]
        [Category("Параметры"), DisplayName("Округлять значения")]
        public int HistogramRoundValues
        {
            get => HistogramRoundValuesParam.Get(SettingsLongKey);
            set
            {
                if (!HistogramRoundValuesParam.Set(SettingsLongKey, value, -4, 4))
                {
                    return;
                }
 
                OnPropertyChanged();
            }
        }
 
        private bool _histogramShowValueArea;
 
        [DataMember(Name = "HistogramShowValueArea"), DefaultValue(true)]
        [Category("Параметры"), DisplayName("Отображать Value Area")]
        public bool HistogramShowValueArea
        {
            get => _histogramShowValueArea;
            set
            {
                if (value == _histogramShowValueArea)
                {
                    return;
                }
 
                _histogramShowValueArea = value;
 
                OnPropertyChanged();
            }
        }
 
        private bool _histogramExtendValueArea;
 
        [DataMember(Name = "HistogramExtendValueArea"), DefaultValue(false)]
        [Category("Параметры"), DisplayName("Продлить Value Area")]
        public bool HistogramExtendValueArea
        {
            get => _histogramExtendValueArea;
            set
            {
                if (value == _histogramExtendValueArea)
                {
                    return;
                }
 
                _histogramExtendValueArea = value;
 
                OnPropertyChanged();
            }
        }
 
        private int _histogramValueAreaPercent;
 
        [DataMember(Name = "HistogramValueAreaPercent")]
        [Category("Параметры"), DisplayName("ValueArea %")]
        public int HistogramValueAreaPercent
        {
            get => _histogramValueAreaPercent;
            set
            {
                value = Math.Max(0, Math.Min(100, value));
 
                if (value == 0)
                {
                    value = 70;
                }
 
                if (value == _histogramValueAreaPercent)
                {
                    return;
                }
 
                _histogramValueAreaPercent = value;
 
                Clear();
 
                OnPropertyChanged();
            }
        }
 
        private bool _histogramShowPoc;
 
        [DataMember(Name = "HistogramShowPoc"), DefaultValue(true)]
        [Category("Параметры"), DisplayName("Отображать POC")]
        public bool HistogramShowPoc
        {
            get => _histogramShowPoc;
            set
            {
                if (value == _histogramShowPoc)
                {
                    return;
                }
 
                _histogramShowPoc = value;
 
                OnPropertyChanged();
            }
        }
 
        private bool _histogramExtendPoc;
 
        [DataMember(Name = "HistogramExtendPoc"), DefaultValue(false)]
        [Category("Параметры"), DisplayName("Продлить POC")]
        public bool HistogramExtendPoc
        {
            get => _histogramExtendPoc;
            set
            {
                if (value == _histogramExtendPoc)
                {
                    return;
                }
 
                _histogramExtendPoc = value;
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _volumeBrush;
 
        private XColor _volumeColor;
 
        [DataMember(Name = "VolumeColor")]
        [Category("Стиль"), DisplayName("Volume")]
        public XColor VolumeColor
        {
            get => _volumeColor;
            set
            {
                if (value == _volumeColor)
                {
                    return;
                }
 
                _volumeColor = value;
 
                _volumeBrush = new XBrush(_volumeColor);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _tradesBrush;
 
        private XColor _tradesColor;
 
        [DataMember(Name = "TradesColor")]
        [Category("Стиль"), DisplayName("Trades")]
        public XColor TradesColor
        {
            get => _tradesColor;
            set
            {
                if (value == _tradesColor)
                {
                    return;
                }
 
                _tradesColor = value;
 
                _tradesBrush = new XBrush(_tradesColor);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _deltaPlusBrush;
 
        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);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _deltaMinusBrush;
 
        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);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _bidBrush;
 
        private XColor _bidColor;
 
        [DataMember(Name = "BidColor")]
        [Category("Стиль"), DisplayName("Bid")]
        public XColor BidColor
        {
            get => _bidColor;
            set
            {
                if (value == _bidColor)
                {
                    return;
                }
 
                _bidColor = value;
 
                _bidBrush = new XBrush(_bidColor);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _askBrush;
 
        private XColor _askColor;
 
        [DataMember(Name = "AskColor")]
        [Category("Стиль"), DisplayName("Ask")]
        public XColor AskColor
        {
            get => _askColor;
            set
            {
                if (value == _askColor)
                {
                    return;
                }
 
                _askColor = value;
 
                _askBrush = new XBrush(_askColor);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _valueAreaBrush;
 
        private XColor _valueAreaColor;
 
        [DataMember(Name = "ValueAreaColor")]
        [Category("Стиль"), DisplayName("Value Area")]
        public XColor ValueAreaColor
        {
            get => _valueAreaColor;
            set
            {
                if (value == _valueAreaColor)
                {
                    return;
                }
 
                _valueAreaColor = value;
 
                _valueAreaBrush = new XBrush(_valueAreaColor);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _maximumBrush;
 
        private XColor _maximumColor;
 
        [DataMember(Name = "MaximumColor")]
        [Category("Стиль"), DisplayName("POC")]
        public XColor MaximumColor
        {
            get => _maximumColor;
            set
            {
                if (value == _maximumColor)
                {
                    return;
                }
 
                _maximumColor = value;
 
                _maximumBrush = new XBrush(_maximumColor);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _cellBorderBrush;
 
        private XPen _cellBorderPen;
 
        private XColor _cellBorderColor;
 
        [DataMember(Name = "CellBorderColor")]
        [Category("Стиль"), DisplayName("Граница ячейки")]
        public XColor CellBorderColor
        {
            get => _cellBorderColor;
            set
            {
                if (value == _cellBorderColor)
                {
                    return;
                }
 
                _cellBorderColor = value;
 
                _cellBorderBrush = new XBrush(_cellBorderColor);
                _cellBorderPen = new XPen(_cellBorderBrush, 1);
 
                OnPropertyChanged();
            }
        }
 
        private XBrush _textBrush;
 
        private XColor _textColor;
 
        [DataMember(Name = "TextColor")]
        [Category("Стиль"), DisplayName("Текст")]
        public XColor TextColor
        {
            get => _textColor;
            set
            {
                if (value == _textColor)
                {
                    return;
                }
 
                _textColor = value;
 
                _textBrush = new XBrush(_textColor);
 
                OnPropertyChanged();
            }
        }
 
        [Browsable(false)]
        public override bool ShowIndicatorValues => false;
 
        [Browsable(false)]
        public override IndicatorCalculation Calculation => IndicatorCalculation.OnEachTick;
 
        private List<IndicatorLabelInfo> _labels;
 
        private long _lastSequense;
 
        private RawCluster _histogram;
 
        public HistogramIndicator()
        {
            ShowIndicatorTitle = false;
 
            PeriodType = HistogramPeriodType.Day;
            PeriodValue = 1;
 
            HistogramViewType = HistogramViewType.Volume;
            HistogramCellViewType = HistogramCellViewType.Solid;
 
            HistogramGradient = true;
            HistogramShowValues = true;
            HistogramMinimizeValues = false;
            HistogramShowValueArea = true;
            HistogramValueAreaPercent = 70;
            HistogramExtendValueArea = false;
            HistogramShowPoc = true;
            HistogramExtendPoc = false;
 
            VolumeColor = Color.FromArgb(255, 70, 130, 180);
            TradesColor = Color.FromArgb(255, 70, 130, 180);
            DeltaPlusColor = Color.FromArgb(255, 46, 139, 87);
            DeltaMinusColor = Color.FromArgb(255, 178, 34, 34);
            BidColor = Color.FromArgb(255, 178, 34, 34);
            AskColor = Color.FromArgb(255, 70, 130, 180);
            ValueAreaColor = Color.FromArgb(255, 128, 128, 128);
            MaximumColor = Color.FromArgb(255, 178, 34, 34);
            CellBorderColor = Color.FromArgb(255, 127, 127, 127);
            TextColor = Color.FromArgb(255, 255, 255, 255);
        }
 
        protected override void Execute()
        {
            if (_labels == null)
            {
                _labels = new List<IndicatorLabelInfo>();
            }
 
            if (_histogram == null)
            {
                _histogram = new RawCluster(DateTime.MinValue);
            }
 
            if (ClearData)
            {
                Clear();
            }
 
            if (PeriodType == HistogramPeriodType.CustomDate)
            {
                if (_lastSequense == -1)
                {
                    _histogram = new RawCluster(DateTime.MinValue);
 
                    for (var i = 0; i < DataProvider.Count; i++)
                    {
                        var cluster = DataProvider.GetRawCluster(i);
 
                        if (cluster.Time < StartDate || cluster.Time > EndDate)
                        {
                            continue;
                        }
 
                        _histogram.AddCluster(cluster);
                    }
 
                    _lastSequense = 1;
                }
                else
                {
                    var ticks = DataProvider.GetRawTicks();
 
                    foreach (var tick in ticks)
                    {
                        _histogram.AddTick(tick, DataProvider.Scale);
                    }
                }
 
                _histogram.UpdateData();
 
                return;
            }
 
            if (PeriodRevers && PeriodType != HistogramPeriodType.AllBars)
            {
                if (_lastSequense != DataProvider.Count)
                {
                    var interval = GetTimeSeconds();
 
                    var lastBar = DataProvider.GetRawCluster(DataProvider.Count - 1);
 
                    var startTime = lastBar?.OpenTime ?? TimeHelper.GetCurrTime(DataProvider.Symbol.Exchange);
 
                    startTime = startTime.AddSeconds(-interval);
 
                    _histogram = new RawCluster(DateTime.MinValue);
 
                    for (var i = 0; i < DataProvider.Count; i++)
                    {
                        var cluster = DataProvider.GetRawCluster(i);
 
                        if (cluster.Time < startTime)
                        {
                            continue;
                        }
 
                        _histogram.AddCluster(cluster);
                    }
 
                    _lastSequense = DataProvider.Count;
                }
                else
                {
                    var ticks = DataProvider.GetRawTicks();
 
                    foreach (var tick in ticks)
                    {
                        _histogram.AddTick(tick, DataProvider.Scale);
                    }
                }
 
                _histogram.UpdateData();
 
                return;
            }
 
            var timeOffset = TimeHelper.GetSessionOffset(DataProvider.Symbol.Exchange);
 
            var lastCluster = DataProvider.GetRawCluster(DataProvider.Count - 1);
 
            if (lastCluster == null)
            {
                return;
            }
 
            var currSequence = GetSequence(lastCluster.Time, timeOffset);
 
            if (_lastSequense != currSequence)
            {
                _histogram = new RawCluster(DateTime.MinValue);
 
                _lastSequense = currSequence;
 
                for (var i = DataProvider.Count - 1; i >= 0; i--)
                {
                    var cluster = DataProvider.GetRawCluster(i);
 
                    var newSequence = GetSequence(cluster.Time, timeOffset);
 
                    if (_lastSequense != newSequence)
                    {
                        break;
                    }
 
                    _histogram.AddCluster(cluster);
                }
            }
            else
            {
                var ticks = DataProvider.GetRawTicks();
 
                foreach (var tick in ticks)
                {
                    _histogram.AddTick(tick, DataProvider.Scale);
                }
            }
 
            _histogram.UpdateData();
        }
 
        private int GetSequence(DateTime date, double offset)
        {
            var cycleBase = ChartPeriodType.Hour;
 
            switch (PeriodType)
            {
                case HistogramPeriodType.Minute:
 
                    cycleBase = ChartPeriodType.Minute;
 
                    break;
 
                case HistogramPeriodType.Hour:
 
                    cycleBase = ChartPeriodType.Hour;
 
                    break;
 
                case HistogramPeriodType.Day:
 
                    cycleBase = ChartPeriodType.Day;
 
                    break;
 
                case HistogramPeriodType.Week:
 
                    cycleBase = ChartPeriodType.Week;
 
                    break;
 
                case HistogramPeriodType.Month:
 
                    cycleBase = ChartPeriodType.Month;
 
                    break;
 
                case HistogramPeriodType.AllBars:
 
                    return 0;
            }
 
            return DataProvider.Period.GetSequence(cycleBase, PeriodValue, date, offset);
        }
 
        public int GetTimeSeconds()
        {
            switch (PeriodType)
            {
                case HistogramPeriodType.Minute:
 
                    return PeriodValue * 60;
 
                case HistogramPeriodType.Hour:
 
                    return PeriodValue * 60 * 60;
 
                case HistogramPeriodType.Day:
 
                    return PeriodValue * 60 * 60 * 24;
 
                case HistogramPeriodType.Week:
 
                    return PeriodValue * 60 * 60 * 24 * 7;
 
                case HistogramPeriodType.Month:
 
                    return PeriodValue * 60 * 60 * 24 * 30;
 
                default:
 
                    return 0;
            }
        }
 
        private void Clear()
        {
            _lastSequense = -1;
        }
 
        public override void Render(DxVisualQueue visual)
        {
            _labels.Clear();
 
            if (_histogram == null)
            {
                return;
            }
 
            var dp = DataProvider;
            var step = dp.Step;
            var symbol = dp.Symbol;
 
            var rect = Canvas.Rect;
 
            var width = rect.Width * 0.2;
 
            var heightCorrect = HistogramCellViewType == HistogramCellViewType.Bars ||
                                HistogramCellViewType == HistogramCellViewType.BorderedBars
                ? -1
                : 0;
 
            var height = Math.Max(GetY(0.0) - GetY(dp.Step), 1);
 
            var fontSize = Math.Min(height + heightCorrect - 2, 18) * 96.0 / 72.0;
 
            fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
 
            var textFont = new XFont(Canvas.ChartFont.Name, fontSize);
 
            var minPrice = (long)(Canvas.MinY / step) - 1;
            var maxPrice = (long)(Canvas.MaxY / step) + 1;
 
            if (maxPrice - minPrice > 100000)
            {
                return;
            }
 
            var valueArea = HistogramShowValueArea ? _histogram.GetValueArea(HistogramValueAreaPercent) : null;
 
            maxPrice = Math.Min(_histogram.High, maxPrice + 1);
            minPrice = Math.Max(_histogram.Low, minPrice - 1);
 
            var prevY = (int)GetY(maxPrice * step + step / 2.0);
 
            var roundValues = HistogramRoundValues;
 
            var maxValues = _histogram.MaxValues;
 
            for (var price = maxPrice; price >= minPrice; price--)
            {
                var currY = (int)GetY(price * step - step / 2.0);
 
                var currHeight = Math.Max((currY - prevY) + heightCorrect, 1);
 
                var y = prevY;
 
                prevY = currY;
 
                var item = _histogram.GetItem(price);
 
                if (item == null)
                {
                    continue;
                }
 
                var barWidth = 0.0;
                var valueText = "";
 
                switch (HistogramViewType)
                {
                    case HistogramViewType.Volume:
                        {
                            barWidth = width / maxValues.MaxVolume * item.Volume;
 
                            var fillBrush = HistogramGradient
                                ? new XBrush(VolumeColor.ChangeOpacity(item.Volume, maxValues.MaxVolume,
                                    Canvas.Theme.ChartBackColor))
                                : _volumeBrush;
 
                            var fillRect = new Rect(rect.Left, y, barWidth, currHeight);
 
                            visual.FillRectangle(fillBrush, fillRect);
 
                            valueText = symbol.FormatRawSize(item.Volume, roundValues, HistogramMinimizeValues);
 
                            break;
                        }
 
                    case HistogramViewType.Trades:
                        {
                            barWidth = width / maxValues.MaxTrades * item.Trades;
 
                            var fillBrush = HistogramGradient
                                ? new XBrush(TradesColor.ChangeOpacity(item.Trades, maxValues.MaxTrades,
                                    Canvas.Theme.ChartBackColor))
                                : _tradesBrush;
 
                            var fillRect = new Rect(rect.Left, y, barWidth, currHeight);
 
                            visual.FillRectangle(fillBrush, fillRect);
 
                            valueText = symbol.FormatTrades(item.Trades, roundValues, HistogramMinimizeValues);
 
                            break;
                        }
                    case HistogramViewType.Delta:
                        {
                            var maxDelta = Math.Max(maxValues.MaxDelta, -maxValues.MinDelta);
 
                            barWidth = width / maxDelta * Math.Abs(item.Delta);
 
                            var fillBrush = item.Delta > 0
                                ? (HistogramGradient
                                    ? new XBrush(DeltaPlusColor.ChangeOpacity(item.Delta, maxDelta,
                                        Canvas.Theme.ChartBackColor))
                                    : _deltaPlusBrush)
                                : (HistogramGradient
                                    ? new XBrush(DeltaMinusColor.ChangeOpacity(-item.Delta, maxDelta,
                                        Canvas.Theme.ChartBackColor))
                                    : _deltaMinusBrush);
 
                            var fillRect = new Rect(rect.Left, y, barWidth, currHeight);
 
                            visual.FillRectangle(fillBrush, fillRect);
 
                            valueText = symbol.FormatRawSize(item.Delta, roundValues, HistogramMinimizeValues);
 
                            break;
                        }
                    case HistogramViewType.BidAsk:
                        {
                            barWidth = width / maxValues.MaxVolume * item.Volume;
 
                            var redWidth = barWidth / item.Volume * item.Bid;
 
                            var bidBrush = HistogramGradient
                                ? new XBrush(BidColor.ChangeOpacity(item.Bid,
                                    Math.Max(maxValues.MaxBid, maxValues.MaxAsk), Canvas.Theme.ChartBackColor))
                                : _bidBrush;
 
                            var bidRect = new Rect(rect.Left, y, redWidth, currHeight);
 
                            var askBrush = HistogramGradient
                                ? new XBrush(AskColor.ChangeOpacity(item.Ask,
                                    Math.Max(maxValues.MaxBid, maxValues.MaxAsk), Canvas.Theme.ChartBackColor))
                                : _askBrush;
 
                            var askRect = new Rect(rect.Left + redWidth, y, barWidth - redWidth, currHeight);
 
                            visual.FillRectangle(bidBrush, bidRect);
                            visual.FillRectangle(askBrush, askRect);
 
                            valueText = symbol.FormatRawSize(item.Volume, roundValues, HistogramMinimizeValues);
 
                            break;
                        }
                }
 
                if (HistogramCellViewType == HistogramCellViewType.BorderedBars &&
                    height + heightCorrect > 3)
                {
                    visual.DrawRectangle(_cellBorderPen,
                        new Rect(rect.Left - 1, y, barWidth, currHeight - 1));
                }
 
                if (price == maxValues.Poc && HistogramShowPoc)
                {
                    var pocRect = new Rect(rect.Left, y, width, currHeight);
 
                    if (HistogramExtendPoc)
                    {
                        visual.DrawLine(new XPen(_maximumBrush, 3),
                            new Point(rect.Left, y + currHeight / 2),
                            new Point(rect.Right, y + currHeight / 2));
 
                        _labels.Add(new IndicatorLabelInfo(price * step, MaximumColor));
                    }
                    else
                    {
                        visual.DrawLine(new XPen(_maximumBrush, 3),
                            new Point(rect.Left, y + currHeight / 2),
                            new Point(rect.Left + width, y + currHeight / 2));
                    }
 
                    var pocTextSize = Canvas.ChartFontBold.GetSize("POC");
 
                    visual.DrawString("POC", Canvas.ChartFontBold, _maximumBrush,
                        pocRect.Right - pocTextSize.Width, pocRect.Top - pocTextSize.Height - 4);
                }
                else if (valueArea != null && price == valueArea.Vah)
                {
                    var vahRect = new Rect(rect.Left, y, width, currHeight);
 
                    if (HistogramExtendValueArea)
                    {
                        visual.DrawLine(new XPen(_valueAreaBrush, 3),
                            new Point(rect.Left, y + currHeight / 2),
                            new Point(rect.Right, y + currHeight / 2));
 
                        _labels.Add(new IndicatorLabelInfo(price * step, ValueAreaColor));
                    }
                    else
                    {
                        visual.DrawLine(new XPen(_valueAreaBrush, 3),
                            new Point(rect.Left, y + currHeight / 2),
                            new Point(rect.Left + width, y + currHeight / 2));
                    }
 
                    var vahTextSize = Canvas.ChartFontBold.GetSize("VAH");
 
                    visual.DrawString("VAH", Canvas.ChartFontBold, _valueAreaBrush,
                        vahRect.Right - vahTextSize.Width, vahRect.Top - vahTextSize.Height - 4);
                }
                else if (valueArea != null && price == valueArea.Val)
                {
                    var valRect = new Rect(rect.Left, y, width, currHeight);
 
                    if (HistogramExtendValueArea)
                    {
                        visual.DrawLine(new XPen(_valueAreaBrush, 3),
                            new Point(rect.Left, y + currHeight / 2),
                            new Point(rect.Right, y + currHeight / 2));
 
                        _labels.Add(new IndicatorLabelInfo(price * step, ValueAreaColor));
                    }
                    else
                    {
                        visual.DrawLine(new XPen(_valueAreaBrush, 3),
                            new Point(rect.Left, y + currHeight / 2),
                            new Point(rect.Left + width, y + currHeight / 2));
                    }
 
                    var valTextSize = Canvas.ChartFontBold.GetSize("VAL");
 
                    visual.DrawString("VAL", Canvas.ChartFontBold, _valueAreaBrush,
                        valRect.Right - valTextSize.Width, valRect.Top - valTextSize.Height - 4);
                }
 
                if (HistogramShowValues && height > 7 && y > 15)
                {
                    visual.DrawString(valueText, textFont, _textBrush,
                        new Rect(rect.Left + 2, y, width, currHeight));
                }
            }
        }
 
        public override void GetLabels(ref List<IndicatorLabelInfo> labels)
        {
            labels.AddRange(_labels);
        }
 
        public override void CopyTemplate(IndicatorBase indicator, bool style)
        {
            var i = (HistogramIndicator)indicator;
 
            PeriodType = i.PeriodType;
            PeriodValue = i.PeriodValue;
            PeriodRevers = i.PeriodRevers;
            StartDate = i.StartDate;
            EndDate = i.EndDate;
 
            HistogramViewType = i.HistogramViewType;
            HistogramCellViewType = i.HistogramCellViewType;
            HistogramGradient = i.HistogramGradient;
            HistogramShowValues = i.HistogramShowValues;
            HistogramMinimizeValues = i.HistogramMinimizeValues;
            HistogramShowValueArea = i.HistogramShowValueArea;
            HistogramExtendValueArea = i.HistogramExtendValueArea;
            HistogramValueAreaPercent = i.HistogramValueAreaPercent;
            HistogramShowPoc = i.HistogramShowPoc;
            HistogramExtendPoc = i.HistogramExtendPoc;
 
            HistogramRoundValuesParam.Copy(i.HistogramRoundValuesParam);
 
            VolumeColor = i.VolumeColor;
            TradesColor = i.TradesColor;
            DeltaPlusColor = i.DeltaPlusColor;
            DeltaMinusColor = i.DeltaMinusColor;
            BidColor = i.BidColor;
            AskColor = i.AskColor;
            ValueAreaColor = i.ValueAreaColor;
            MaximumColor = i.MaximumColor;
            CellBorderColor = i.CellBorderColor;
            TextColor = i.TextColor;
 
            base.CopyTemplate(indicator, style);
        }
 
        public override bool GetPropertyVisibility(string propertyName)
        {
            switch (propertyName)
            {
                case nameof(StartDate):
                case nameof(EndDate):
 
                    return PeriodType == HistogramPeriodType.CustomDate;
 
                case nameof(PeriodValue):
 
                    return PeriodType != HistogramPeriodType.CustomDate && PeriodType != HistogramPeriodType.AllBars;
 
                case nameof(PeriodRevers):
 
                    return PeriodType != HistogramPeriodType.CustomDate && PeriodType != HistogramPeriodType.AllBars;
 
            }
 
            return base.GetPropertyVisibility(propertyName);
        }
    }
}
```


---

# 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/razrabotka-dlya-tiger.trade-windows/primery-indikatorov/histogram.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.
