Histogram Indicator Code
//------------------------------------------------------------------------------ // // Histogram. Copyright (c) 2019 Ilya Smirnov. 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); } } }