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);
}
}
}
Last updated