Volume
//------------------------------------------------------------------------------
//
// Indicator Volume. 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.Dx;
namespace TigerTrade.Chart.Indicators.Custom
{
[DataContract(Name = "VolumeIndicator", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
[Indicator("X_Volume", "*Volume", false, Type = typeof(VolumeIndicator))]
internal sealed class VolumeIndicator : IndicatorBase
{
private XBrush _upBackBrush;
private XPen _upBackPen;
private XColor _upBackColor;
[DataMember(Name = "UpColor")]
[Category("Стиль"), DisplayName("Цвет при росте")]
public XColor UpColor
{
get => _upBackColor;
set
{
if (value == _upBackColor)
{
return;
}
_upBackColor = value;
_upBackBrush = new XBrush(_upBackColor);
_upBackPen = new XPen(_upBackBrush, 1);
OnPropertyChanged();
}
}
private XBrush _downBackBrush;
private XPen _downBackPen;
private XColor _downBackColor;
[DataMember(Name = "DownColor")]
[Category("Стиль"), DisplayName("Цвет при падении")]
public XColor DownColor
{
get => _downBackColor;
set
{
if (value == _downBackColor)
{
return;
}
_downBackColor = value;
_downBackBrush = new XBrush(_downBackColor);
_downBackPen = new XPen(_downBackBrush, 1);
OnPropertyChanged();
}
}
private bool _deltaColored;
[DataMember(Name = "DeltaColored")]
[Category("Параметры"), DisplayName("Раскраска по дельте")]
public bool DeltaColored
{
get => _deltaColored;
set
{
if (value == _deltaColored)
{
return;
}
_deltaColored = value;
OnPropertyChanged();
}
}
private IndicatorNullIntParam _maxVolumeParam;
[DataMember(Name = "MaxVolumeParam")]
public IndicatorNullIntParam MaxVolumeParam
{
get => _maxVolumeParam ?? (_maxVolumeParam = new IndicatorNullIntParam(null));
set => _maxVolumeParam = value;
}
[DefaultValue(null)]
[Category("Параметры"), DisplayName("Макс. объём")]
public int? MaxVolume
{
get => MaxVolumeParam.Get(SettingsLongKey);
set
{
if (!MaxVolumeParam.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 _filter1Brush;
private XPen _filter1Pen;
private XColor _filter1Color;
[DataMember(Name = "Filter1Color")]
[Category("Фильтр 1"), DisplayName("Цвет")]
public XColor Filter1Color
{
get => _filter1Color;
set
{
if (value == _filter1Color)
{
return;
}
_filter1Color = value;
_filter1Brush = new XBrush(_filter1Color);
_filter1Pen = new XPen(_filter1Brush, 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 _filter2Brush;
private XPen _filter2Pen;
private XColor _filter2Color;
[DataMember(Name = "Filter2Color")]
[Category("Фильтр 2"), DisplayName("Цвет")]
public XColor Filter2Color
{
get => _filter2Color;
set
{
if (value == _filter2Color)
{
return;
}
_filter2Color = value;
_filter2Brush = new XBrush(_filter2Color);
_filter2Pen = new XPen(_filter2Brush, 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 _filter3Brush;
private XPen _filter3Pen;
private XColor _filter3Color;
[DataMember(Name = "Filter3Color")]
[Category("Фильтр 3"), DisplayName("Цвет")]
public XColor Filter3Color
{
get => _filter3Color;
set
{
if (value == _filter3Color)
{
return;
}
_filter3Color = value;
_filter3Brush = new XBrush(_filter3Color);
_filter3Pen = new XPen(_filter3Brush, 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;
private double _max;
public VolumeIndicator()
{
UpColor = Color.FromArgb(255, 30, 144, 255);
DownColor = Color.FromArgb(255, 178, 34, 34);
DeltaColored = false;
Filter1Color = Colors.Orange;
Filter2Color = Colors.Orange;
Filter3Color = 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 volume = cluster.Volume;
if (Filter1Alert.IsActive && _filter1SignalIndex < index)
{
var min = Filter1Min ?? -1;
var max = Filter1Max ?? -1;
if (min >= 0 && volume >= min && (max < 0 || volume <= max))
{
_filter1SignalIndex = index;
AddAlert(Filter1Alert,
$"Volume: фильтр 1, значение {DataProvider.Symbol.FormatSizeFull(volume)}.");
}
}
if (Filter2Alert.IsActive && _filter2SignalIndex < index)
{
var min = Filter2Min ?? -1;
var max = Filter2Max ?? -1;
if (min >= 0 && volume >= min && (max < 0 || volume <= max))
{
_filter2SignalIndex = index;
AddAlert(Filter2Alert,
$"Volume: фильтр 2, значение {DataProvider.Symbol.FormatSizeFull(volume)}.");
}
}
if (Filter3Alert.IsActive && _filter3SignalIndex < index)
{
var min = Filter3Min ?? -1;
var max = Filter3Max ?? -1;
if (min >= 0 && volume >= min && (max < 0 || volume <= max))
{
_filter3SignalIndex = index;
AddAlert(Filter3Alert,
$"Volume: фильтр 3, значение {DataProvider.Symbol.FormatSizeFull(volume)}.");
}
}
}
public override bool GetMinMax(out double min, out double max)
{
min = 0.0;
max = 0.0;
if (Canvas.IsStock)
{
return false;
}
for (var i = 0; i < Canvas.Count; i++)
{
var index = Canvas.GetIndex(i);
var cluster = DataProvider.GetCluster(index);
if (cluster == null)
{
continue;
}
var volume = (double) cluster.Volume;
if (max < volume)
{
max = volume;
}
}
var maxVolume = MaxVolume ?? -1;
if (maxVolume >= 0 && max > maxVolume)
{
max = maxVolume;
}
return true;
}
private double GetMax()
{
var max = 0.0;
for (var i = 0; i < Canvas.Count; i++)
{
var index = Canvas.GetIndex(i);
var cluster = DataProvider.GetCluster(index);
if (cluster == null)
{
continue;
}
var volume = (double)cluster.Volume;
if (max < volume)
{
max = volume;
}
}
var maxVolume = MaxVolume ?? -1;
if (maxVolume >= 0 && max > maxVolume)
{
max = maxVolume;
}
return max;
}
public override void Render(DxVisualQueue visual)
{
if (Canvas.IsStock)
{
RenderOnMain(visual);
return;
}
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 maxVolume = MaxVolume ?? -1;
var maxPoint = GetY((double)maxVolume);
var zeroPoint = GetY(0.0);
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)
{
continue;
}
var x = Canvas.GetX(index);
var y = GetY(cluster.Volume);
if (maxVolume >= 0)
{
y = Math.Max(y, maxPoint);
}
var h = (int) zeroPoint - (int) y;
if (h < 0)
{
continue;
}
if (h < 1)
{
y = (int)zeroPoint - 1;
h = 1;
}
var isUp = DeltaColored ? cluster.Delta > 0 : cluster.IsUp;
XBrush filterBrush = null;
XPen filterPen = null;
if (min1 >= 0 && cluster.Volume >= min1 && (max1 < 0 || cluster.Volume <= max1))
{
filterBrush = _filter1Brush;
filterPen = _filter1Pen;
}
else if (min2 >= 0 && cluster.Volume >= min2 && (max2 < 0 || cluster.Volume <= max2))
{
filterBrush = _filter2Brush;
filterPen = _filter2Pen;
}
else if (min3 >= 0 && cluster.Volume >= min3 && (max3 < 0 || cluster.Volume <= max3))
{
filterBrush = _filter3Brush;
filterPen = _filter3Pen;
}
if (width > 1)
{
if (filterBrush != null)
{
visual.FillRectangle(filterBrush, new Rect(x - width / 2.0, y, width, h));
}
else
{
visual.FillRectangle(isUp
? _upBackBrush
: _downBackBrush, new Rect(x - width / 2.0, y, width, h));
}
}
else
{
if (filterPen != null)
{
visual.DrawLine(filterPen, new Point(x, y), new Point(x, y + h));
}
else
{
visual.DrawLine(isUp
? _upBackPen
: _downBackPen, new Point(x, y), new Point(x, y + h));
}
}
}
}
public void RenderOnMain(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 maxVolume = MaxVolume ?? -1;
var height = Canvas.Rect.Height * 0.2;
var minPoint = Canvas.Rect.Bottom - 2;
var maxPoint = minPoint - height;
var width = Math.Max(Canvas.ColumnWidth - 1, 1);
_max = GetMax();
for (var i = 0; i < Canvas.Count; i++)
{
var index = Canvas.GetIndex(i);
var cluster = DataProvider.GetCluster(index);
if (cluster == null)
{
continue;
}
var x = Canvas.GetX(index);
var y = minPoint - height * (double)cluster.Volume / _max;
if (maxVolume >= 0)
{
y = Math.Max(y, maxPoint);
}
var h = (int)minPoint - (int)y;
if (h < 0)
{
continue;
}
var isUp = DeltaColored ? cluster.Delta > 0 : cluster.IsUp;
XBrush filterBrush = null;
XPen filterPen = null;
if (min1 >= 0 && cluster.Volume >= min1 && (max1 < 0 || cluster.Volume <= max1))
{
filterBrush = _filter1Brush;
filterPen = _filter1Pen;
}
else if (min2 >= 0 && cluster.Volume >= min2 && (max2 < 0 || cluster.Volume <= max2))
{
filterBrush = _filter2Brush;
filterPen = _filter2Pen;
}
else if (min3 >= 0 && cluster.Volume >= min3 && (max3 < 0 || cluster.Volume <= max3))
{
filterBrush = _filter3Brush;
filterPen = _filter3Pen;
}
if (width > 1)
{
if (filterBrush != null)
{
visual.FillRectangle(filterBrush, new Rect(x - width / 2.0, y, width, h));
}
else
{
visual.FillRectangle(isUp
? _upBackBrush
: _downBackBrush, new Rect(x - width / 2.0, y, width, h));
}
}
else
{
if (filterPen != null)
{
visual.DrawLine(filterPen, new Point(x, y), new Point(x, y + h));
}
else
{
visual.DrawLine(isUp
? _upBackPen
: _downBackPen, new Point(x, y), new Point(x, y + h));
}
}
}
}
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.Volume);
if (Canvas.IsStock)
{
s = DataProvider.Symbol.FormatSizeShort(cluster.Volume);
}
info.Add(new IndicatorValueInfo(s,
new XBrush(cluster.IsUp ? _upBackColor : _downBackColor)));
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;
}
double? position = null;
if (Canvas.IsStock)
{
position = Canvas.Rect.Bottom -
Canvas.Rect.Height * 0.2 * (double)cluster.Volume / _max;
}
labels.Add(new IndicatorLabelInfo((double)cluster.Volume,
cluster.IsUp ? _upBackColor : _downBackColor, position));
}
public override bool CheckAlert(double value, int distance, ref int lastIndex, ref double lastValue)
{
if (Canvas == null || Canvas.IsStock)
{
return false;
}
if (DataProvider.Count == lastIndex && value == lastValue)
{
return false;
}
var cluster = DataProvider.GetCluster(DataProvider.Count - 1);
if (cluster == null)
{
return false;
}
if ((double)cluster.Volume < value - distance)
{
return false;
}
lastIndex = DataProvider.Count;
lastValue = value;
return true;
}
public override void ApplyColors(IChartTheme theme)
{
UpColor = theme.PaletteColor6;
DownColor = theme.PaletteColor7;
base.ApplyColors(theme);
}
public override void CopyTemplate(IndicatorBase indicator, bool style)
{
var i = (VolumeIndicator)indicator;
UpColor = i.UpColor;
DownColor = i.DownColor;
DeltaColored = i.DeltaColored;
MaxVolumeParam.Copy(i.MaxVolumeParam);
Filter1MinParam.Copy(i.Filter1MinParam);
Filter1MaxParam.Copy(i.Filter1MaxParam);
OnPropertyChanged(nameof(Filter1Min));
OnPropertyChanged(nameof(Filter1Max));
Filter1Color = i.Filter1Color;
Filter1Alert.Copy(i.Filter1Alert, !style);
OnPropertyChanged(nameof(Filter1Alert));
Filter2MinParam.Copy(i.Filter2MinParam);
Filter2MaxParam.Copy(i.Filter2MaxParam);
OnPropertyChanged(nameof(Filter2Min));
OnPropertyChanged(nameof(Filter2Max));
Filter2Color = i.Filter2Color;
Filter2Alert.Copy(i.Filter2Alert, !style);
OnPropertyChanged(nameof(Filter2Alert));
Filter3MinParam.Copy(i.Filter3MinParam);
Filter3MaxParam.Copy(i.Filter3MaxParam);
OnPropertyChanged(nameof(Filter3Min));
OnPropertyChanged(nameof(Filter3Max));
Filter3Color = i.Filter3Color;
Filter3Alert.Copy(i.Filter3Alert, !style);
OnPropertyChanged(nameof(Filter3Alert));
base.CopyTemplate(indicator, style);
}
}
}
Last updated