Volume Profile
//------------------------------------------------------------------------------
//
// Графический объект VolumeProfile. 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;
using TigerTrade.Chart.Data;
using TigerTrade.Chart.Objects.Common;
using TigerTrade.Core.UI.Converters;
using TigerTrade.Dx;
using TigerTrade.Dx.Enums;
namespace TigerTrade.Chart.Objects.Custom
{
[TypeConverter(typeof(EnumDescriptionTypeConverter))]
[DataContract(Name = "VolumeProfileType", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Objects.Custom")]
public enum VolumeProfileType
{
[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
}
[TypeConverter(typeof(EnumDescriptionTypeConverter))]
[DataContract(Name = "VolumeProfileMaximumType", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Objects.Custom")]
public enum VolumeProfileMaximumType
{
[EnumMember(Value = "Volume"), Description("Volume")]
Volume,
[EnumMember(Value = "Trades"), Description("Trades")]
Trades,
[EnumMember(Value = "Delta"), Description("Delta")]
Delta,
[EnumMember(Value = "DeltaPlus"), Description("Delta+")]
DeltaPlus,
[EnumMember(Value = "DeltaMinus"), Description("Delta-")]
DeltaMinus,
[EnumMember(Value = "Bid"), Description("Bid")]
Bid,
[EnumMember(Value = "Ask"), Description("Ask")]
Ask
}
[DataContract(Name = "VolumeProfileObject", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Objects.Custom")]
[ChartObject("X_VolumeProfile", "Профиль объёма", 2, Type = typeof(VolumeProfileObject))]
public sealed class VolumeProfileObject : ObjectBase
{
private VolumeProfileType _profileType;
[DataMember(Name = "ProfileType")]
[Category("Профиль"), DisplayName("Тип")]
public VolumeProfileType ProfileType
{
get => _profileType;
set
{
if (value == _profileType)
{
return;
}
_profileType = value;
OnPropertyChanged();
}
}
private XBrush _profileBrush;
private XColor _profileColor;
[DataMember(Name = "ProfileColor")]
[Category("Профиль"), DisplayName("Цвет")]
public XColor ProfileColor
{
get => _profileColor;
set
{
if (value == _profileColor)
{
return;
}
_profileColor = value;
_profileBrush = new XBrush(_profileColor);
OnPropertyChanged();
}
}
private XBrush _profile2Brush;
private XColor _profile2Color;
[DataMember(Name = "Profile2Color")]
[Category("Профиль"), DisplayName("Цвет 2")]
public XColor Profile2Color
{
get => _profile2Color;
set
{
if (value == _profile2Color)
{
return;
}
_profile2Color = value;
_profile2Brush = new XBrush(_profile2Color);
OnPropertyChanged();
}
}
private bool _extendProfile;
[DataMember(Name = "ExtendProfile")]
[Category("Профиль"), DisplayName("Расширить")]
public bool ExtendProfile
{
get => _extendProfile;
set
{
if (value == _extendProfile)
{
return;
}
_extendProfile = value;
OnPropertyChanged();
}
}
private bool _showCumValue;
[DataMember(Name = "ShowCumValue")]
[Category("Профиль"), DisplayName("Отобр. общ. знач.")]
public bool ShowCumValue
{
get => _showCumValue;
set
{
if (value == _showCumValue)
{
return;
}
_showCumValue = value;
OnPropertyChanged();
}
}
private bool _showValues;
[DataMember(Name = "ShowValues")]
[Category("Значения"), DisplayName("Отображать")]
public bool ShowValues
{
get => _showValues;
set
{
if (value == _showValues)
{
return;
}
_showValues = value;
OnPropertyChanged();
}
}
private bool _minimizeValues;
[DataMember(Name = "MinimizeValues")]
[Category("Значения"), DisplayName("Минимизировать")]
public bool MinimizeValues
{
get => _minimizeValues;
set
{
if (value == _minimizeValues)
{
return;
}
_minimizeValues = value;
OnPropertyChanged();
}
}
private int _roundValues;
[DefaultValue(0)]
[DataMember(Name = "RoundValues")]
[Category("Значения"), DisplayName("Округлять")]
public int RoundValues
{
get => _roundValues;
set
{
value = Math.Max(-4, Math.Min(4, value));
if (value == _roundValues)
{
return;
}
_roundValues = value;
OnPropertyChanged();
}
}
private XBrush _valuesBrush;
private XColor _valuesColor;
[DataMember(Name = "ValuesColor")]
[Category("Значения"), DisplayName("Цвет")]
public XColor ValuesColor
{
get => _valuesColor;
set
{
if (value == _valuesColor)
{
return;
}
_valuesColor = value;
_valuesBrush = new XBrush(_valuesColor);
OnPropertyChanged();
}
}
private VolumeProfileMaximumType _maximumType;
[DataMember(Name = "MaximumType")]
[Category("Максимум"), DisplayName("Тип")]
public VolumeProfileMaximumType MaximumType
{
get => _maximumType;
set
{
if (value == _maximumType)
{
return;
}
_maximumType = value;
OnPropertyChanged();
}
}
private bool _showMaximum;
[DataMember(Name = "ShowMaximum")]
[Category("Максимум"), DisplayName("Отображать")]
public bool ShowMaximum
{
get => _showMaximum;
set
{
if (value == _showMaximum)
{
return;
}
_showMaximum = value;
OnPropertyChanged();
}
}
private bool _showMaximumValue;
[DataMember(Name = "ShowMaximumValue")]
[Category("Максимум"), DisplayName("Значение")]
public bool ShowMaximumValue
{
get => _showMaximumValue;
set
{
if (value == _showMaximumValue)
{
return;
}
_showMaximumValue = value;
OnPropertyChanged();
}
}
private bool _extendMaximum;
[DataMember(Name = "ExtendMaximum")]
[Category("Максимум"), DisplayName("Продлить")]
public bool ExtendMaximum
{
get => _extendMaximum;
set
{
if (value == _extendMaximum)
{
return;
}
_extendMaximum = value;
OnPropertyChanged();
}
}
private XBrush _maximumBrush;
private XColor _maximumColor;
[DataMember(Name = "MaximumColor")]
[Category("Максимум"), DisplayName("Цвет")]
public XColor MaximumColor
{
get => _maximumColor;
set
{
if (value == _maximumColor)
{
return;
}
_maximumColor = value;
_maximumBrush = new XBrush(_maximumColor);
OnPropertyChanged();
}
}
private bool _showValueArea;
[DataMember(Name = "ShowValueArea")]
[Category("Value Area"), DisplayName("Отображать")]
public bool ShowValueArea
{
get => _showValueArea;
set
{
if (value == _showValueArea)
{
return;
}
_showValueArea = value;
OnPropertyChanged();
}
}
private bool _extendValueArea;
[DataMember(Name = "ExtendValueArea")]
[Category("Value Area"), DisplayName("Продлить")]
public bool ExtendValueArea
{
get => _extendValueArea;
set
{
if (value == _extendValueArea)
{
return;
}
_extendValueArea = value;
OnPropertyChanged();
}
}
private int _valueAreaPercent;
[DataMember(Name = "ValueAreaPercent")]
[Category("Value Area"), DisplayName("ValueArea %")]
public int ValueAreaPercent
{
get => _valueAreaPercent;
set
{
value = Math.Max(0, Math.Min(100, value));
if (value == 0)
{
value = 70;
}
if (value == _valueAreaPercent)
{
return;
}
_valueAreaPercent = value;
OnPropertyChanged();
}
}
private XBrush _valueAreaBrush;
private XColor _valueAreaColor;
[DataMember(Name = "ValueAreaColor")]
[Category("Value Area"), DisplayName("Цвет")]
public XColor ValueAreaColor
{
get => _valueAreaColor;
set
{
if (value == _valueAreaColor)
{
return;
}
_valueAreaColor = value;
_valueAreaBrush = new XBrush(_valueAreaColor);
OnPropertyChanged();
}
}
private bool _enableFilter;
[DataMember(Name = "EnableFilter")]
[Category("Фильтр"), DisplayName("Включить")]
public bool EnableFilter
{
get => _enableFilter;
set
{
if (value == _enableFilter)
{
return;
}
_enableFilter = value;
OnPropertyChanged();
}
}
private int _filterMin;
[DataMember(Name = "FilterMin")]
[Category("Фильтр"), DisplayName("Минимум")]
public int FilterMin
{
get => _filterMin;
set
{
value = Math.Max(0, value);
if (value == _filterMin)
{
return;
}
_filterMin = value;
OnPropertyChanged();
}
}
private int _filterMax;
[DataMember(Name = "FilterMax")]
[Category("Фильтр"), DisplayName("Максимум")]
public int FilterMax
{
get => _filterMax;
set
{
value = Math.Max(0, value);
if (value == _filterMax)
{
return;
}
_filterMax = value;
OnPropertyChanged();
}
}
private XBrush _filterBrush;
private XColor _filterColor;
[DataMember(Name = "FilterColor")]
[Category("Фильтр"), DisplayName("Цвет")]
public XColor FilterColor
{
get => _filterColor;
set
{
if (value == _filterColor)
{
return;
}
_filterColor = value;
_filterBrush = new XBrush(_filterColor);
OnPropertyChanged();
}
}
private bool _drawBorder;
[DataMember(Name = "DrawBorder")]
[Category("Граница"), DisplayName("Граница")]
public bool DrawBorder
{
get => _drawBorder;
set
{
if (value == _drawBorder)
{
return;
}
_drawBorder = value;
OnPropertyChanged();
}
}
private XBrush _lineBrush;
private XPen _linePen;
private XColor _lineColor;
[DataMember(Name = "LineColor")]
[Category("Граница"), DisplayName("Цвет линии")]
public XColor LineColor
{
get => _lineColor;
set
{
if (value == _lineColor)
{
return;
}
_lineColor = value;
_lineBrush = new XBrush(_lineColor);
_linePen = new XPen(_lineBrush, LineWidth, LineStyle);
OnPropertyChanged();
}
}
private int _lineWidth;
[DataMember(Name = "LineWidth")]
[Category("Граница"), DisplayName("Толщина линии")]
public int LineWidth
{
get => _lineWidth;
set
{
value = Math.Max(1, Math.Min(10, value));
if (value == _lineWidth)
{
return;
}
_lineWidth = value;
_linePen = new XPen(_lineBrush, _lineWidth, LineStyle);
OnPropertyChanged();
}
}
private XDashStyle _lineStyle;
[DataMember(Name = "LineStyle")]
[Category("Граница"), DisplayName("Стиль линии")]
public XDashStyle LineStyle
{
get => _lineStyle;
set
{
if (value == _lineStyle)
{
return;
}
_lineStyle = value;
_linePen = new XPen(_lineBrush, LineWidth, _lineStyle);
OnPropertyChanged();
}
}
private bool _drawBack;
[DataMember(Name = "DrawBack")]
[Category("Фон"), DisplayName("Фон")]
public bool DrawBack
{
get => _drawBack;
set
{
if (value == _drawBack)
{
return;
}
_drawBack = value;
OnPropertyChanged();
}
}
private XBrush _backBrush;
private XColor _backColor;
[DataMember(Name = "BackColor")]
[Category("Фон"), DisplayName("Цвет фона")]
public XColor BackColor
{
get => _backColor;
set
{
if (value == _backColor)
{
return;
}
_backColor = value;
_backBrush = new XBrush(_backColor);
OnPropertyChanged();
}
}
protected override int PenWidth => LineWidth;
private bool _isObjectInArea;
public class RectangleInfo
{
public Point ControlPoint1;
public Point ControlPoint2;
public Point ExtraPoint1;
public Point ExtraPoint2;
public Rect Rectangle;
}
private RectangleInfo _rectInfo;
public VolumeProfileObject()
{
ProfileType = VolumeProfileType.Volume;
ProfileColor = Color.FromArgb(127, 70, 130, 180);
Profile2Color = Color.FromArgb(127, 178, 34, 34);
ExtendProfile = false;
ShowCumValue = false;
ShowValues = false;
MinimizeValues = false;
ValuesColor = Color.FromArgb(255, 255, 255, 255);
MaximumType = VolumeProfileMaximumType.Volume;
ShowMaximum = true;
ShowMaximumValue = true;
ExtendMaximum = false;
MaximumColor = Color.FromArgb(127, 178, 34, 34);
ShowValueArea = true;
ExtendValueArea = false;
ValueAreaPercent = 70;
ValueAreaColor = Color.FromArgb(127, 128, 128, 128);
EnableFilter = false;
FilterMin = 0;
FilterMax = 0;
FilterColor = Color.FromArgb(127, 46, 139, 87);
DrawBorder = true;
LineColor = Colors.Black;
LineWidth = 1;
LineStyle = XDashStyle.Solid;
DrawBack = true;
BackColor = Color.FromArgb(30, 0, 0, 0);
}
protected override void Prepare()
{
var point1 = ToPoint(ControlPoints[0]);
var point2 = ToPoint(ControlPoints[1]);
var ep1 = ToPoint(ExtraPoints[0]);
var ep2 = ToPoint(ExtraPoints[1]);
var w = Canvas.ColumnWidth / 2.0;
var h = Canvas.StepHeight / 2.0;
if (point1.X > point2.X)
{
point1.X += w;
point2.X -= w;
}
else
{
point1.X -= w;
point2.X += w;
}
if (point1.Y > point2.Y)
{
point1.Y += h;
point2.Y -= h;
}
else
{
point1.Y -= h;
point2.Y += h;
}
if (ep1.X > ep2.X)
{
ep1.X += w;
ep2.X -= w;
}
else
{
ep1.X -= w;
ep2.X += w;
}
if (ep1.Y > ep2.Y)
{
ep1.Y += h;
ep2.Y -= h;
}
else
{
ep1.Y -= h;
ep2.Y += h;
}
_rectInfo = new RectangleInfo
{
ControlPoint1 = point1,
ControlPoint2 = point2,
ExtraPoint1 = ep1,
ExtraPoint2 = ep2,
Rectangle = new Rect(point1, point2)
};
_isObjectInArea = Canvas.Rect.IntersectsWith(_rectInfo.Rectangle);
}
protected override void Draw(DxVisualQueue visual, ref List<ObjectLabelInfo> labels)
{
if (!ExtendProfile)
{
if (DrawBack)
{
visual.FillRectangle(_backBrush, _rectInfo.Rectangle);
}
if (DrawBorder)
{
visual.DrawRectangle(_linePen, _rectInfo.Rectangle);
}
}
if (!Canvas.IsStock)
{
return;
}
var index1 = 0;
var index2 = 1;
if (ControlPoints[0].X > ControlPoints[1].X)
{
index1 = 1;
index2 = 0;
}
var bar1 = Canvas.DateToIndex(ControlPoints[index1].X, 0);
var bar2 = Canvas.DateToIndex(ControlPoints[index2].X, 0);
var step = DataProvider.Step;
var maxPrice = (long)(Math.Max(ControlPoints[0].Y, ControlPoints[1].Y) / step);
var minPrice = (long)(Math.Min(ControlPoints[0].Y, ControlPoints[1].Y) / step);
var profile = new RawCluster(DateTime.MinValue);
if (ExtendProfile)
{
for (var i = bar1; i <= bar2; i++)
{
var cluster = DataProvider.GetRawCluster(i);
if (cluster == null)
{
continue;
}
foreach (var item in cluster.Items)
{
profile.AddItem(item);
}
maxPrice = Math.Max(maxPrice, cluster.High);
minPrice = Math.Min(minPrice, cluster.Low);
}
}
else
{
for (var i = bar1; i <= bar2; i++)
{
var cluster = DataProvider.GetRawCluster(i);
if (cluster == null)
{
continue;
}
foreach (var item in cluster.Items)
{
if (item.Price >= minPrice && item.Price <= maxPrice)
{
profile.AddItem(item);
}
}
}
}
profile.UpdateData();
if (profile.Volume <= 0)
{
return;
}
var valueArea = ShowValueArea ? profile.GetValueArea(ValueAreaPercent) : null;
var p1 = ToPoint(ControlPoints[index1]);
var p2 = ToPoint(ControlPoints[index2]);
switch (ProfileType)
{
case VolumeProfileType.Volume:
DrawVolume(visual, profile, valueArea, p1, p2, ref labels);
break;
case VolumeProfileType.Trades:
DrawTrades(visual, profile, valueArea, p1, p2, ref labels);
break;
case VolumeProfileType.Delta:
DrawDelta(visual, profile, valueArea, p1, p2, ref labels);
break;
case VolumeProfileType.BidAsk:
DrawBidAsk(visual, profile, valueArea, p1, p2, ref labels);
break;
}
if (ShowCumValue)
{
DrawValues(visual, profile);
}
}
private void DrawValues(DxVisualQueue visual, IRawCluster profile)
{
var symbol = DataProvider.Symbol;
var mainRect = _rectInfo.Rectangle;
var height = Canvas.ChartFont.GetHeight();
var rect = new Rect(new Point(mainRect.Left + 2, mainRect.Bottom + 4),
new Point(mainRect.Right - 2, mainRect.Bottom + height + 4));
switch (ProfileType)
{
case VolumeProfileType.Volume:
var volumeText = symbol.FormatRawSize(profile.Volume, RoundValues, MinimizeValues);
visual.DrawString($"V: {volumeText}", Canvas.ChartFont, _valuesBrush, rect, XTextAlignment.Right);
break;
case VolumeProfileType.Trades:
var tradesText = symbol.FormatTrades(profile.Trades, RoundValues, MinimizeValues);
visual.DrawString($"T: {tradesText}", Canvas.ChartFont, _valuesBrush, rect, XTextAlignment.Right);
break;
case VolumeProfileType.Delta:
var deltaText = symbol.FormatRawSize(profile.Delta, RoundValues, MinimizeValues);
visual.DrawString($"D: {deltaText}", Canvas.ChartFont, _valuesBrush, rect, XTextAlignment.Right);
break;
case VolumeProfileType.BidAsk:
var bidText = symbol.FormatRawSize(profile.Bid, RoundValues, MinimizeValues);
var askText = symbol.FormatRawSize(profile.Ask, RoundValues, MinimizeValues);
visual.DrawString($"B: {bidText} A: {askText}", Canvas.ChartFont, _valuesBrush, rect,
XTextAlignment.Right);
break;
}
}
private bool CheckMaximum(IRawClusterItem item, IRawClusterMaxValues maxValues)
{
switch (MaximumType)
{
case VolumeProfileMaximumType.Volume:
return item.Volume == maxValues.MaxVolume;
case VolumeProfileMaximumType.Trades:
return item.Trades == maxValues.MaxTrades;
case VolumeProfileMaximumType.Delta:
return Math.Abs(item.Delta) ==
Math.Max(Math.Abs(maxValues.MaxDelta), Math.Abs(maxValues.MinDelta));
case VolumeProfileMaximumType.DeltaPlus:
return item.Delta > 0 && item.Delta == maxValues.MaxDelta;
case VolumeProfileMaximumType.DeltaMinus:
return item.Delta < 0 && item.Delta == maxValues.MinDelta;
case VolumeProfileMaximumType.Bid:
return item.Bid == maxValues.MaxBid;
case VolumeProfileMaximumType.Ask:
return item.Ask == maxValues.MaxAsk;
}
return false;
}
private string FormatMaximum(IRawClusterItem item)
{
switch (MaximumType)
{
case VolumeProfileMaximumType.Volume:
return DataProvider.Symbol.FormatRawSize(item.Volume, RoundValues, MinimizeValues);
case VolumeProfileMaximumType.Trades:
return DataProvider.Symbol.FormatTrades(item.Trades, RoundValues, MinimizeValues);
case VolumeProfileMaximumType.Delta:
case VolumeProfileMaximumType.DeltaPlus:
case VolumeProfileMaximumType.DeltaMinus:
return DataProvider.Symbol.FormatRawSize(item.Delta, RoundValues, MinimizeValues);
case VolumeProfileMaximumType.Bid:
return DataProvider.Symbol.FormatRawSize(item.Bid, RoundValues, MinimizeValues);
case VolumeProfileMaximumType.Ask:
return DataProvider.Symbol.FormatRawSize(item.Ask, RoundValues, MinimizeValues);
}
return "";
}
private void DrawVolume(DxVisualQueue visual, IRawCluster profile, IRawClusterValueArea valueArea,
Point p1, Point p2, ref List<ObjectLabelInfo> labels)
{
var colorRects = new List<Tuple<Rect, XBrush>>();
var colorRects2 = new List<Tuple<Rect, XBrush>>();
var valueRects = new List<Tuple<Rect, string>>();
var valueRects2 = new List<Tuple<Rect, string>>();
var step = DataProvider.Step;
var symbol = DataProvider.Symbol;
var height = Math.Max(Canvas.StepHeight, 1);
var fontSize = Math.Min(height - 2, 18) * 96 / 72;
fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
var dist = Math.Max(p2.X - p1.X + Canvas.ColumnWidth - LineWidth, 0);
var left = p1.X - Canvas.ColumnWidth / 2.0 + Math.Ceiling(LineWidth / 2.0);
if (ExtendProfile)
{
if (DrawBack)
{
visual.FillRectangle(_backBrush,
new Rect(new Point(left, Canvas.Rect.Top), new Point(left + dist, Canvas.Rect.Bottom)));
}
if (DrawBorder)
{
visual.DrawLine(_linePen, new Point(left, Canvas.Rect.Top),
new Point(left, Canvas.Rect.Bottom));
visual.DrawLine(_linePen, new Point(left + dist, Canvas.Rect.Top),
new Point(left + dist, Canvas.Rect.Bottom));
}
}
if (profile.High - profile.Low > 100000)
{
return;
}
var maxValues = profile.MaxValues;
var roundValues = RoundValues;
var prevX = (int)left;
var prevY = (int)GetY((profile.High + .5) * step);
var points = new List<Point>
{
new Point(prevX, prevY)
};
for (var j = profile.High; j >= profile.Low; j--)
{
var item = profile.GetItem(j) ?? new RawClusterItem(j);
var width = item.Volume > 0 ? Math.Min(dist / maxValues.MaxVolume * item.Volume, dist) : 0;
var currX = (int)(left + width);
var currY = (int)GetY((j - .5) * step);
var currHeight = Math.Max(currY - prevY, height);
if (currY <= prevY && points.Count > 2)
{
if (currX > prevX)
{
points[points.Count - 2] = new Point(currX, points[points.Count - 2].Y);
points[points.Count - 1] = new Point(currX, points[points.Count - 1].Y);
prevX = currX;
}
}
else
{
points.Add(new Point(currX, prevY));
points.Add(new Point(currX, currY));
prevX = currX;
}
prevY = currY;
var topY = points[points.Count - 2].Y;
if (ShowMaximum && CheckMaximum(item, maxValues))
{
colorRects2.Add(
new Tuple<Rect, XBrush>(
ExtendMaximum
? new Rect(new Point(left, topY),
new Point(Canvas.Rect.Right + 1, topY + currHeight))
: new Rect(left, topY, dist, currHeight), _maximumBrush));
if (ExtendMaximum)
{
labels.Add(new ObjectLabelInfo(j * step, MaximumColor));
}
if (ShowMaximumValue)
{
var h = Canvas.ChartFont.GetHeight();
valueRects2.Add(new Tuple<Rect, string>(
new Rect(left + 2, topY - h - 2, Math.Max(dist - 4, 1), h),
FormatMaximum(item)));
}
}
else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
{
colorRects2.Add(
new Tuple<Rect, XBrush>(
ExtendValueArea
? new Rect(new Point(left, topY), new Point(Canvas.Rect.Right + 1, topY + currHeight))
: new Rect(left, topY, dist, currHeight), _valueAreaBrush));
if (ExtendValueArea)
{
labels.Add(new ObjectLabelInfo(j * step, ValueAreaColor));
}
}
else if (EnableFilter && item.Volume >= symbol.CorrectSizeFilter(FilterMin) &&
(FilterMax == 0 || item.Volume <= symbol.CorrectSizeFilter(FilterMax)))
{
if (colorRects.Count > 0)
{
var lastRect = colorRects[colorRects.Count - 1].Item1;
if ((int)lastRect.Y == (int)topY)
{
if (width > lastRect.Width)
{
colorRects[colorRects.Count - 1] =
new Tuple<Rect, XBrush>(new Rect(left, topY, width, lastRect.Height), _filterBrush);
}
}
else
{
colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight),
_filterBrush));
}
}
else
{
colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight), _filterBrush));
}
}
if (ShowValues && height > 7 && item.Volume > 0)
{
valueRects.Add(new Tuple<Rect, string>(new Rect(left + 2, topY, dist, height),
symbol.FormatRawSize(item.Volume, roundValues, MinimizeValues)));
}
}
points.Add(new Point(left, prevY));
visual.FillPolygon(_profileBrush, points.ToArray());
foreach (var colorRect in colorRects)
{
visual.FillRectangle(colorRect.Item2, colorRect.Item1);
}
foreach (var colorRect in colorRects2)
{
visual.FillRectangle(colorRect.Item2, colorRect.Item1);
}
foreach (var valueRect in valueRects)
{
visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
}
foreach (var valueRect in valueRects2)
{
visual.DrawString(valueRect.Item2, Canvas.ChartFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
}
}
private void DrawTrades(DxVisualQueue visual, IRawCluster profile, IRawClusterValueArea valueArea,
Point p1, Point p2, ref List<ObjectLabelInfo> labels)
{
var colorRects = new List<Tuple<Rect, XBrush>>();
var colorRects2 = new List<Tuple<Rect, XBrush>>();
var valueRects = new List<Tuple<Rect, string>>();
var valueRects2 = new List<Tuple<Rect, string>>();
var step = DataProvider.Step;
var symbol = DataProvider.Symbol;
var height = Math.Max(Canvas.StepHeight, 1);
var fontSize = Math.Min(height - 2, 18) * 96 / 72;
fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
var dist = p2.X - p1.X + Canvas.ColumnWidth - LineWidth;
var left = p1.X - Canvas.ColumnWidth / 2.0 + Math.Ceiling(LineWidth / 2.0);
if (ExtendProfile)
{
if (DrawBack)
{
visual.FillRectangle(_backBrush,
new Rect(new Point(left, Canvas.Rect.Top), new Point(left + dist, Canvas.Rect.Bottom)));
}
if (DrawBorder)
{
visual.DrawLine(_linePen, new Point(left, Canvas.Rect.Top),
new Point(left, Canvas.Rect.Bottom));
visual.DrawLine(_linePen, new Point(left + dist, Canvas.Rect.Top),
new Point(left + dist, Canvas.Rect.Bottom));
}
}
if (profile.High - profile.Low > 10000)
{
return;
}
var maxValues = profile.MaxValues;
var roundValues = RoundValues;
var prevX = (int)left;
var prevY = (int)GetY((profile.High + .5) * step);
var points = new List<Point>
{
new Point(prevX, prevY)
};
for (var j = profile.High; j >= profile.Low; j--)
{
var item = profile.GetItem(j) ?? new RawClusterItem(j);
var width = item.Trades > 0 ? Math.Min(dist / maxValues.MaxTrades * item.Trades, dist) : 0;
var currX = (int)(left + width);
var currY = (int)GetY((j - .5) * step);
var currHeight = Math.Max(currY - prevY, height);
if (currY <= prevY && points.Count > 2)
{
if (currX > prevX)
{
points[points.Count - 2] = new Point(currX, points[points.Count - 2].Y);
points[points.Count - 1] = new Point(currX, points[points.Count - 1].Y);
prevX = currX;
}
}
else
{
points.Add(new Point(currX, prevY));
points.Add(new Point(currX, currY));
prevX = currX;
}
prevY = currY;
var topY = points[points.Count - 2].Y;
if (ShowMaximum && CheckMaximum(item, maxValues))
{
colorRects2.Add(
new Tuple<Rect, XBrush>(
ExtendMaximum
? new Rect(new Point(left, topY),
new Point(Canvas.Rect.Right + 1, topY + currHeight))
: new Rect(left, topY, dist, currHeight), _maximumBrush));
if (ExtendMaximum)
{
labels.Add(new ObjectLabelInfo(j * step, MaximumColor));
}
if (ShowMaximumValue)
{
var h = Canvas.ChartFont.GetHeight();
valueRects2.Add(new Tuple<Rect, string>(
new Rect(left + 2, topY - h - 2, Math.Max(dist - 4, 1), h),
FormatMaximum(item)));
}
}
else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
{
colorRects2.Add(
new Tuple<Rect, XBrush>(
ExtendValueArea
? new Rect(new Point(left, topY), new Point(Canvas.Rect.Right + 1, topY + currHeight))
: new Rect(left, topY, dist, currHeight), _valueAreaBrush));
if (ExtendValueArea)
{
labels.Add(new ObjectLabelInfo(j * step, ValueAreaColor));
}
}
else if (EnableFilter && item.Trades >= FilterMin &&
(FilterMax == 0 || item.Trades <= FilterMax))
{
if (colorRects.Count > 0)
{
var lastRect = colorRects[colorRects.Count - 1].Item1;
if ((int)lastRect.Y == (int)topY)
{
if (width > lastRect.Width)
{
colorRects[colorRects.Count - 1] =
new Tuple<Rect, XBrush>(new Rect(left, topY, width, lastRect.Height), _filterBrush);
}
}
else
{
colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight),
_filterBrush));
}
}
else
{
colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight), _filterBrush));
}
}
if (ShowValues && height > 7 && item.Trades > 0)
{
valueRects.Add(new Tuple<Rect, string>(new Rect(left + 2, topY, dist, height),
symbol.FormatTrades(item.Trades, roundValues, MinimizeValues)));
}
}
points.Add(new Point(left, prevY));
visual.FillPolygon(_profileBrush, points.ToArray());
foreach (var colorRect in colorRects)
{
visual.FillRectangle(colorRect.Item2, colorRect.Item1);
}
foreach (var colorRect in colorRects2)
{
visual.FillRectangle(colorRect.Item2, colorRect.Item1);
}
foreach (var valueRect in valueRects)
{
visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
}
foreach (var valueRect in valueRects2)
{
visual.DrawString(valueRect.Item2, Canvas.ChartFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
}
}
private void DrawDelta(DxVisualQueue visual, IRawCluster profile, IRawClusterValueArea valueArea,
Point p1, Point p2, ref List<ObjectLabelInfo> labels)
{
var colorRects = new List<Tuple<Rect, XBrush>>();
var colorRectsLeft = new List<Tuple<Rect, XBrush>>();
var colorRectsRight = new List<Tuple<Rect, XBrush>>();
var valueLeftRects = new List<Tuple<Rect, string>>();
var valueRightRects = new List<Tuple<Rect, string>>();
var valueRects2 = new List<Tuple<Rect, string>>();
var step = DataProvider.Step;
var symbol = DataProvider.Symbol;
var height = Math.Max(Canvas.StepHeight, 1);
var fontSize = Math.Min(height - 2, 18) * 96 / 72;
fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
var dist = p2.X - p1.X + Canvas.ColumnWidth - LineWidth;
var left = p1.X - Canvas.ColumnWidth / 2.0 + Math.Ceiling(LineWidth / 2.0);
if (ExtendProfile)
{
if (DrawBack)
{
visual.FillRectangle(_backBrush,
new Rect(new Point(left, Canvas.Rect.Top), new Point(left + dist, Canvas.Rect.Bottom)));
}
if (DrawBorder)
{
visual.DrawLine(_linePen, new Point(left, Canvas.Rect.Top),
new Point(left, Canvas.Rect.Bottom));
visual.DrawLine(_linePen, new Point(left + dist, Canvas.Rect.Top),
new Point(left + dist, Canvas.Rect.Bottom));
}
}
if (profile.High - profile.Low > 10000)
{
return;
}
var maxValues = profile.MaxValues;
var roundValues = RoundValues;
var center = left + dist / 2.0;
var prevX = (int)center;
var prevY = (int)GetY((profile.High + .5) * step);
var pointsRight = new List<Point>
{
new Point(prevX, prevY)
};
for (var j = profile.High; j >= profile.Low; j--)
{
var item = profile.GetItem(j) ?? new RawClusterItem(j);
var width = item.Delta > 0
? Math.Min(dist / Math.Max(Math.Abs(maxValues.MinDelta), Math.Abs(maxValues.MaxDelta)) *
Math.Abs(item.Delta), dist) / 2.0
: 0;
var currX = (int)(center + width);
var currY = (int)GetY((j - .5) * step);
var currHeight = Math.Max(currY - prevY, height);
if (currY <= prevY && pointsRight.Count > 2)
{
if (currX > prevX)
{
pointsRight[pointsRight.Count - 2] = new Point(currX, pointsRight[pointsRight.Count - 2].Y);
pointsRight[pointsRight.Count - 1] = new Point(currX, pointsRight[pointsRight.Count - 1].Y);
prevX = currX;
}
}
else
{
pointsRight.Add(new Point(currX, prevY));
pointsRight.Add(new Point(currX, currY));
prevX = currX;
}
prevY = currY;
var topY = pointsRight[pointsRight.Count - 2].Y;
if (ShowMaximum && CheckMaximum(item, maxValues))
{
colorRects.Add(
new Tuple<Rect, XBrush>(
ExtendMaximum
? new Rect(new Point(left, topY),
new Point(Canvas.Rect.Right + 1, topY + currHeight))
: new Rect(left, topY, dist, currHeight), _maximumBrush));
if (ExtendMaximum)
{
labels.Add(new ObjectLabelInfo(j * step, MaximumColor));
}
if (ShowMaximumValue)
{
var h = Canvas.ChartFont.GetHeight();
valueRects2.Add(new Tuple<Rect, string>(
new Rect(left + 2, topY - h - 2, Math.Max(dist - 4, 1), h),
FormatMaximum(item)));
}
}
else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
{
colorRects.Add(
new Tuple<Rect, XBrush>(
ExtendValueArea
? new Rect(new Point(left, topY), new Point(Canvas.Rect.Right + 1, topY + currHeight))
: new Rect(left, topY, dist, currHeight), _valueAreaBrush));
if (ExtendValueArea)
{
labels.Add(new ObjectLabelInfo(j * step, ValueAreaColor));
}
}
else if (EnableFilter)
{
if (item.Delta > 0 && item.Delta >= symbol.CorrectSizeFilter(FilterMin) &&
(FilterMax == 0 || item.Delta <= symbol.CorrectSizeFilter(FilterMax)))
{
if (colorRectsRight.Count > 0)
{
var lastRect = colorRectsRight[colorRectsRight.Count - 1].Item1;
if ((int)lastRect.Y == (int)topY)
{
if (width > lastRect.Width)
{
colorRectsRight[colorRectsRight.Count - 1] =
new Tuple<Rect, XBrush>(new Rect(center, topY, width, lastRect.Height), _filterBrush);
}
}
else
{
colorRectsRight.Add(new Tuple<Rect, XBrush>(new Rect(center, topY, width, currHeight),
_filterBrush));
}
}
else
{
colorRectsRight.Add(new Tuple<Rect, XBrush>(new Rect(center, topY, width, currHeight), _filterBrush));
}
}
}
if (ShowValues && height > 7 && item.Delta > 0)
{
valueRightRects.Add(new Tuple<Rect, string>(new Rect(center + 2, topY, dist / 2.0, height),
symbol.FormatRawSize(item.Delta, roundValues, MinimizeValues)));
}
}
pointsRight.Add(new Point(center, prevY));
prevX = (int)center;
prevY = (int)GetY((profile.High + .5) * step);
var pointsLeft = new List<Point>
{
new Point(prevX, prevY)
};
for (var j = profile.High; j >= profile.Low; j--)
{
var item = profile.GetItem(j) ?? new RawClusterItem(j);
var width = item.Delta < 0
? Math.Min(dist / Math.Max(Math.Abs(maxValues.MinDelta), Math.Abs(maxValues.MaxDelta)) *
Math.Abs(item.Delta), dist) / 2.0
: 0;
var currX = (int)(center - width);
var currY = (int)GetY((j - .5) * step);
var currHeight = Math.Max(currY - prevY, height);
if (currY <= prevY && pointsLeft.Count > 2)
{
if (currX < prevX)
{
pointsLeft[pointsLeft.Count - 2] = new Point(currX, pointsLeft[pointsLeft.Count - 2].Y);
pointsLeft[pointsLeft.Count - 1] = new Point(currX, pointsLeft[pointsLeft.Count - 1].Y);
prevX = currX;
}
}
else
{
pointsLeft.Add(new Point(currX, prevY));
pointsLeft.Add(new Point(currX, currY));
prevX = currX;
}
prevY = currY;
var topY = pointsLeft[pointsLeft.Count - 2].Y;
if (ShowMaximum && CheckMaximum(item, maxValues))
{
}
else if (EnableFilter)
{
if (item.Delta < 0 && -item.Delta >= symbol.CorrectSizeFilter(FilterMin) &&
(FilterMax == 0 || -item.Delta <= symbol.CorrectSizeFilter(FilterMax)))
{
if (colorRectsLeft.Count > 0)
{
var lastRect = colorRectsLeft[colorRectsLeft.Count - 1].Item1;
if ((int)lastRect.Y == (int)topY)
{
if (width > lastRect.Width)
{
colorRectsLeft[colorRectsLeft.Count - 1] =
new Tuple<Rect, XBrush>(new Rect(center - width, topY, width, lastRect.Height), _filterBrush);
}
}
else
{
colorRectsLeft.Add(new Tuple<Rect, XBrush>(new Rect(center - width, topY, width, currHeight),
_filterBrush));
}
}
else
{
colorRectsLeft.Add(new Tuple<Rect, XBrush>(new Rect(center - width, topY, width, currHeight), _filterBrush));
}
}
}
if (ShowValues && height > 7 && item.Delta < 0)
{
valueLeftRects.Add(new Tuple<Rect, string>(new Rect(left, topY, dist / 2.0 - 2, height),
symbol.FormatRawSize(item.Delta, roundValues, MinimizeValues)));
}
}
pointsLeft.Add(new Point(center, prevY));
visual.FillPolygon(_profile2Brush, pointsLeft.ToArray());
visual.FillPolygon(_profileBrush, pointsRight.ToArray());
foreach (var colorRect in colorRectsLeft)
{
visual.FillRectangle(colorRect.Item2, colorRect.Item1);
}
foreach (var colorRect in colorRectsRight)
{
visual.FillRectangle(colorRect.Item2, colorRect.Item1);
}
foreach (var colorRect in colorRects)
{
visual.FillRectangle(colorRect.Item2, colorRect.Item1);
}
foreach (var valueRect in valueLeftRects)
{
visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
}
foreach (var valueRect in valueRightRects)
{
visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
}
foreach (var valueRect in valueRects2)
{
visual.DrawString(valueRect.Item2, Canvas.ChartFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
}
}
private void DrawBidAsk(DxVisualQueue visual, IRawCluster profile, IRawClusterValueArea valueArea,
Point p1, Point p2, ref List<ObjectLabelInfo> labels)
{
var colorRects = new List<Tuple<Rect, XBrush>>();
var colorRectsLeft = new List<Tuple<Rect, XBrush>>();
var colorRectsRight = new List<Tuple<Rect, XBrush>>();
var valueLeftRects = new List<Tuple<Rect, string>>();
var valueRightRects = new List<Tuple<Rect, string>>();
var valueRects2 = new List<Tuple<Rect, string>>();
var step = DataProvider.Step;
var symbol = DataProvider.Symbol;
var height = Math.Max(Canvas.StepHeight, 1);
var fontSize = Math.Min(height - 2, 18) * 96 / 72;
fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
var dist = p2.X - p1.X + Canvas.ColumnWidth - LineWidth;
var left = p1.X - Canvas.ColumnWidth / 2.0 + Math.Ceiling(LineWidth / 2.0);
if (ExtendProfile)
{
if (DrawBack)
{
visual.FillRectangle(_backBrush,
new Rect(new Point(left, Canvas.Rect.Top), new Point(left + dist, Canvas.Rect.Bottom)));
}
if (DrawBorder)
{
visual.DrawLine(_linePen, new Point(left, Canvas.Rect.Top),
new Point(left, Canvas.Rect.Bottom));
visual.DrawLine(_linePen, new Point(left + dist, Canvas.Rect.Top),
new Point(left + dist, Canvas.Rect.Bottom));
}
}
if (profile.High - profile.Low > 10000)
{
return;
}
var maxValues = profile.MaxValues;
var roundValues = RoundValues;
var center = Math.Floor(left + dist / 2.0);
var prevX = (int)center;
var prevY = (int)GetY((profile.High + .5) * step);
var pointsRight = new List<Point>
{
new Point(prevX, prevY)
};
for (var j = profile.High; j >= profile.Low; j--)
{
var item = profile.GetItem(j) ?? new RawClusterItem(j);
var askWidth =
(int)(Math.Min(dist / Math.Max(maxValues.MaxBid, maxValues.MaxAsk) * item.Ask, dist) / 2.0);
var currX = (int)(center + askWidth);
var currY = (int)GetY((j - .5) * step);
var currHeight = Math.Max(currY - prevY, height);
if (currY <= prevY && pointsRight.Count > 2)
{
if (currX > prevX)
{
pointsRight[pointsRight.Count - 2] = new Point(currX, pointsRight[pointsRight.Count - 2].Y);
pointsRight[pointsRight.Count - 1] = new Point(currX, pointsRight[pointsRight.Count - 1].Y);
prevX = currX;
}
}
else
{
pointsRight.Add(new Point(currX, prevY));
pointsRight.Add(new Point(currX, currY));
prevX = currX;
}
prevY = currY;
var topY = pointsRight[pointsRight.Count - 2].Y;
if (ShowMaximum && CheckMaximum(item, maxValues))
{
colorRects.Add(
new Tuple<Rect, XBrush>(
ExtendMaximum
? new Rect(new Point(left, topY),
new Point(Canvas.Rect.Right + 1, topY + currHeight))
: new Rect(left, topY, dist, currHeight), _maximumBrush));
if (ExtendMaximum)
{
labels.Add(new ObjectLabelInfo(j * step, MaximumColor));
}
if (ShowMaximumValue)
{
var h = Canvas.ChartFont.GetHeight();
valueRects2.Add(new Tuple<Rect, string>(
new Rect(left + 2, topY - h - 2, Math.Max(dist - 4, 1), h),
FormatMaximum(item)));
}
}
else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
{
colorRects.Add(
new Tuple<Rect, XBrush>(
ExtendValueArea
? new Rect(new Point(left, topY), new Point(Canvas.Rect.Right + 1, topY + currHeight))
: new Rect(left, topY, dist, currHeight), _valueAreaBrush));
if (ExtendValueArea)
{
labels.Add(new ObjectLabelInfo(j * step, ValueAreaColor));
}
}
else if (EnableFilter)
{
if (item.Ask >= symbol.CorrectSizeFilter(FilterMin) &&
(FilterMax == 0 || item.Ask <= symbol.CorrectSizeFilter(FilterMax)))
{
if (colorRectsRight.Count > 0)
{
var lastRect = colorRectsRight[colorRectsRight.Count - 1].Item1;
if ((int)lastRect.Y == (int)topY)
{
if (askWidth > lastRect.Width)
{
colorRectsRight[colorRectsRight.Count - 1] =
new Tuple<Rect, XBrush>(new Rect(center, topY, askWidth, lastRect.Height),
_filterBrush);
}
}
else
{
colorRectsRight.Add(
new Tuple<Rect, XBrush>(new Rect(center, topY, askWidth, currHeight),
_filterBrush));
}
}
else
{
colorRectsRight.Add(new Tuple<Rect, XBrush>(new Rect(center, topY, askWidth, currHeight),
_filterBrush));
}
}
}
if (ShowValues && height > 7 && item.Ask > 0)
{
valueRightRects.Add(new Tuple<Rect, string>(new Rect(center + 2, topY, dist / 2.0, height),
symbol.FormatRawSize(item.Ask, roundValues, MinimizeValues)));
}
}
pointsRight.Add(new Point(center, prevY));
prevX = (int)center;
prevY = (int)GetY((profile.High + .5) * step);
var pointsLeft = new List<Point>
{
new Point(prevX, prevY)
};
for (var j = profile.High; j >= profile.Low; j--)
{
var item = profile.GetItem(j) ?? new RawClusterItem(j);
var bidWidth =
(int)(Math.Min(dist / Math.Max(maxValues.MaxBid, maxValues.MaxAsk) * item.Bid, dist) / 2.0);
var currX = (int)(center - bidWidth);
var currY = (int)GetY((j - .5) * step);
var currHeight = Math.Max(currY - prevY, height);
if (currY <= prevY && pointsLeft.Count > 2)
{
if (currX < prevX)
{
pointsLeft[pointsLeft.Count - 2] = new Point(currX, pointsLeft[pointsLeft.Count - 2].Y);
pointsLeft[pointsLeft.Count - 1] = new Point(currX, pointsLeft[pointsLeft.Count - 1].Y);
prevX = currX;
}
}
else
{
pointsLeft.Add(new Point(currX, prevY));
pointsLeft.Add(new Point(currX, currY));
prevX = currX;
}
prevY = currY;
var topY = pointsLeft[pointsLeft.Count - 2].Y;
if (ShowMaximum && CheckMaximum(item, maxValues))
{
}
else if (EnableFilter)
{
if (item.Bid >= symbol.CorrectSizeFilter(FilterMin) &&
(FilterMax == 0 || item.Bid <= symbol.CorrectSizeFilter(FilterMax)))
{
if (colorRectsLeft.Count > 0)
{
var lastRect = colorRectsLeft[colorRectsLeft.Count - 1].Item1;
if ((int)lastRect.Y == (int)topY)
{
if (bidWidth > lastRect.Width)
{
colorRectsLeft[colorRectsLeft.Count - 1] =
new Tuple<Rect, XBrush>(
new Rect(center - bidWidth, topY, bidWidth, lastRect.Height), _filterBrush);
}
}
else
{
colorRectsLeft.Add(new Tuple<Rect, XBrush>(
new Rect(center - bidWidth, topY, bidWidth, currHeight), _filterBrush));
}
}
else
{
colorRectsLeft.Add(
new Tuple<Rect, XBrush>(new Rect(center - bidWidth, topY, bidWidth, currHeight),
_filterBrush));
}
}
}
if (ShowValues && height > 7 && item.Bid > 0)
{
valueLeftRects.Add(new Tuple<Rect, string>(new Rect(left, topY, dist / 2.0 - 2, height),
symbol.FormatRawSize(item.Bid, roundValues, MinimizeValues)));
}
}
pointsLeft.Add(new Point(center, prevY));
visual.FillPolygon(_profile2Brush, pointsLeft.ToArray());
visual.FillPolygon(_profileBrush, pointsRight.ToArray());
foreach (var colorRect in colorRectsLeft)
{
visual.FillRectangle(colorRect.Item2, colorRect.Item1);
}
foreach (var colorRect in colorRectsRight)
{
visual.FillRectangle(colorRect.Item2, colorRect.Item1);
}
foreach (var colorRect in colorRects)
{
visual.FillRectangle(colorRect.Item2, colorRect.Item1);
}
foreach (var valueRect in valueLeftRects)
{
visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
}
foreach (var valueRect in valueRightRects)
{
visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
}
foreach (var valueRect in valueRects2)
{
visual.DrawString(valueRect.Item2, Canvas.ChartFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
}
}
public override void DrawControlPoints(DxVisualQueue visual)
{
if (_rectInfo == null)
{
return;
}
DrawControlPoint(visual, _rectInfo.ControlPoint1);
DrawControlPoint(visual, _rectInfo.ControlPoint2);
DrawControlPoint(visual, _rectInfo.ExtraPoint1);
DrawControlPoint(visual, _rectInfo.ExtraPoint2);
}
public override int GetControlPoint(int x, int y)
{
if (Canvas == null || _rectInfo == null)
{
return -1;
}
var points = new[] { _rectInfo.ControlPoint1, _rectInfo.ControlPoint2 };
for (var i = 0; i < points.Length; i++)
{
var distX = points[i].X - x;
var distY = points[i].Y - y;
if (distX * distX + distY * distY < 9.0 + PenWidth / 2.0)
{
return i;
}
}
return -1;
}
public override int GetExtraPoint(int x, int y)
{
if (Canvas == null || _rectInfo == null)
{
return -1;
}
var points = new[] { _rectInfo.ExtraPoint1, _rectInfo.ExtraPoint2 };
for (var i = 0; i < points.Length; i++)
{
var distX = points[i].X - x;
var distY = points[i].Y - y;
if (distX * distX + distY * distY < 9.0 + PenWidth / 2.0)
{
return i;
}
}
return -1;
}
protected override bool IsObjectInArea()
{
return _isObjectInArea;
}
protected override bool InObject(int x, int y)
{
if (_rectInfo == null)
{
return false;
}
return _rectInfo.Rectangle != Rect.Empty && _rectInfo.Rectangle.Contains(x, y);
}
protected override int GetMinDist(int x, int y)
{
var rect = _rectInfo.Rectangle;
var dx = Math.Min(rect.X + rect.Width - x, x - rect.X);
var dy = Math.Min(rect.Y + rect.Height - y, y - rect.Y);
var result = Math.Min(dx, dy);
return result > 0 ? (int)result : -1;
}
public override ObjectPoint[] ExtraPoints
{
get
{
var cp1 = ControlPoints[0];
var cp2 = ControlPoints[1];
var ep1 = new ObjectPoint(cp2.X, cp1.Y);
var ep2 = new ObjectPoint(cp1.X, cp2.Y);
var extraPoints = new[] { ep1, ep2 };
return extraPoints;
}
}
public override void ExtraPointChanged(int index, ObjectPoint op)
{
switch (index)
{
case 0:
ControlPoints[1].X = op.X;
ControlPoints[0].Y = op.Y;
break;
case 1:
ControlPoints[0].X = op.X;
ControlPoints[1].Y = op.Y;
break;
}
}
public override void ApplyTheme(IChartTheme theme)
{
base.ApplyTheme(theme);
LineColor = theme.ChartObjectLineColor;
BackColor = theme.ChartObjectFillColor;
}
public override void CopyTemplate(ObjectBase objectBase, bool style)
{
if (objectBase is VolumeProfileObject obj)
{
ProfileType = obj.ProfileType;
ProfileColor = obj.ProfileColor;
Profile2Color = obj.Profile2Color;
ExtendProfile = obj.ExtendProfile;
ShowCumValue = obj.ShowCumValue;
ShowValues = obj.ShowValues;
MinimizeValues = obj.MinimizeValues;
RoundValues = obj.RoundValues;
ValuesColor = obj.ValuesColor;
MaximumType = obj.MaximumType;
ShowMaximum = obj.ShowMaximum;
ShowMaximumValue = obj.ShowMaximumValue;
ExtendMaximum = obj.ExtendMaximum;
MaximumColor = obj.MaximumColor;
ShowValueArea = obj.ShowValueArea;
ExtendValueArea = obj.ExtendValueArea;
ValueAreaPercent = obj.ValueAreaPercent;
ValueAreaColor = obj.ValueAreaColor;
EnableFilter = obj.EnableFilter;
FilterMin = obj.FilterMin;
FilterMax = obj.FilterMax;
FilterColor = obj.FilterColor;
DrawBorder = obj.DrawBorder;
LineColor = obj.LineColor;
LineWidth = obj.LineWidth;
LineStyle = obj.LineStyle;
DrawBack = obj.DrawBack;
BackColor = obj.BackColor;
}
base.CopyTemplate(objectBase, style);
}
}
}
Last updated