Horizontal Line
//------------------------------------------------------------------------------
//
// Графический объект HorizontalLine. 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.Base.Enums;
using TigerTrade.Chart.Indicators.Common;
using TigerTrade.Chart.Objects.Common;
using TigerTrade.Chart.Objects.Enums;
using TigerTrade.Core.Utils.Logging;
using TigerTrade.Dx;
using TigerTrade.Dx.Enums;
namespace TigerTrade.Chart.Objects.Custom
{
[DataContract(Name = "HorizontalLineObject", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Objects.Custom")]
[ChartObject("X_HorizontalLine", "Горизонтальная линия", 1, Type = typeof(HorizontalLineObject))]
public class HorizontalLineObject : ObjectBase
{
[Category("Цена"), DisplayName("Цена")]
public decimal Price
{
get => (decimal)ControlPoints[0].Y;
set
{
if (value == (decimal)ControlPoints[0].Y)
{
return;
}
ControlPoints[0].Y = (double)value;
OnPropertyChanged();
OnPropertyChanged(nameof(ControlPoints));
}
}
private ChartAlertSettings _alert;
[DataMember(Name = "Alert")]
[Category("Оповещение"), DisplayName("Оповещение")]
public ChartAlertSettings Alert
{
get => _alert ?? (_alert = new ChartAlertSettings());
set
{
if (Equals(value, _alert))
{
return;
}
_alert = value;
OnPropertyChanged();
}
}
private int _alertMinDistance;
[DataMember(Name = "AlertMinDistance")]
[Category("Оповещение"), DisplayName("Мин. расстояние")]
public int AlertMinDistance
{
get => _alertMinDistance;
set
{
if (value == _alertMinDistance)
{
return;
}
_alertMinDistance = value;
OnPropertyChanged();
}
}
private string _text;
[DataMember(Name = "Text")]
[Category("Текст"), DisplayName("Текст")]
public string Text
{
get => _text;
set
{
if (value == _text)
{
return;
}
_text = value;
OnPropertyChanged();
}
}
private ObjectTextAlignment _textAlignment;
[DataMember(Name = "TextAlignment")]
[Category("Текст"), DisplayName("Расположение")]
public ObjectTextAlignment TextAlignment
{
get => _textAlignment;
set
{
if (value == _textAlignment)
{
return;
}
_textAlignment = value;
OnPropertyChanged();
}
}
private int _fontSize;
[DataMember(Name = "FontSize")]
[Category("Текст"), DisplayName("Размер")]
public int FontSize
{
get => _fontSize;
set
{
value = Math.Max(10, Math.Min(100, value));
if (value == _fontSize)
{
return;
}
_fontSize = 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();
}
}
protected override int PenWidth => LineWidth;
private Rect _lineRect;
public HorizontalLineObject()
{
AlertMinDistance = 3;
Text = "";
TextAlignment = ObjectTextAlignment.RightTop;
FontSize = 14;
LineColor = Colors.Black;
LineWidth = 1;
LineStyle = XDashStyle.Solid;
}
protected override void Draw(DxVisualQueue visual, ref List<ObjectLabelInfo> labels)
{
if (Canvas == null)
{
return;
}
var point = ToPoint(ControlPoints[0]);
var startPoint = new Point(Canvas.Rect.Left, point.Y);
var endPoint = new Point(Canvas.Rect.Right, point.Y);
_lineRect = new Rect(startPoint, endPoint);
if (Settings.TransformHorLines && Canvas.IsStock &&
Canvas.StockType == ChartStockType.Clusters)
{
var y = ControlPoints[0].Y;
var step = DataProvider.Step;
var price = (long)Math.Round(y / step);
var y1 = GetY((price + .5) * step);
var y2 = GetY((price - .5) * step);
if (y2 - y1 > LineWidth + 2)
{
var brush = new XBrush(LineColor, LineColor.Alpha > 127 ? 127 : LineColor.Alpha);
_lineRect = new Rect(new Point(startPoint.X, y1), new Point(endPoint.X, y2));
visual.FillRectangle(brush, _lineRect);
DrawText(visual);
labels.Add(new ObjectLabelInfo(price * step, y1, y2, LineColor));
return;
}
}
visual.DrawLine(_linePen, startPoint, endPoint);
DrawText(visual);
labels.Add(new ObjectLabelInfo(ControlPoints[0].Y, LineColor));
}
protected void DrawText(DxVisualQueue visual)
{
if (string.IsNullOrEmpty(Text) || TextAlignment == ObjectTextAlignment.Hide)
{
return;
}
var font = new XFont(Canvas.ChartFont.Name, FontSize);
var textSize = font.GetSize(Text);
var x = 0.0;
var y = 0.0;
var width = textSize.Width;
switch (TextAlignment)
{
case ObjectTextAlignment.LeftTop:
case ObjectTextAlignment.CenterTop:
case ObjectTextAlignment.RightTop:
y = _lineRect.Top - 4 - textSize.Height;
break;
case ObjectTextAlignment.LeftMiddle:
case ObjectTextAlignment.CenterMiddle:
case ObjectTextAlignment.RightMiddle:
y = (_lineRect.Top + _lineRect.Bottom - textSize.Height) / 2.0;
break;
case ObjectTextAlignment.LeftBottom:
case ObjectTextAlignment.CenterBottom:
case ObjectTextAlignment.RightBottom:
y = _lineRect.Bottom + 4;
break;
}
switch (TextAlignment)
{
case ObjectTextAlignment.LeftTop:
case ObjectTextAlignment.LeftMiddle:
case ObjectTextAlignment.LeftBottom:
x = _lineRect.X;
break;
case ObjectTextAlignment.CenterTop:
case ObjectTextAlignment.CenterMiddle:
case ObjectTextAlignment.CenterBottom:
x = _lineRect.Right - (_lineRect.Width + width) / 2.0;
x = Math.Max(x, _lineRect.Left);
break;
case ObjectTextAlignment.RightTop:
case ObjectTextAlignment.RightMiddle:
case ObjectTextAlignment.RightBottom:
x = _lineRect.Right - width;
x = Math.Max(x, _lineRect.Left);
break;
}
var rect = new Rect(x, y, width, textSize.Height);
visual.DrawString(Text, font, _lineBrush, rect);
}
public override void DrawControlPoints(DxVisualQueue visual)
{
if (_lineRect == Rect.Empty)
{
return;
}
var width = LineWidth / 2 + 4;
var center = new Point((_lineRect.Left + _lineRect.Right) / 2.0, (_lineRect.Top + _lineRect.Bottom) / 2.0);
var rect = new Rect(center, center);
rect.Inflate(new Size(width, width));
visual.FillRectangle(Theme.ChartCpFillBrush, rect);
visual.DrawRectangle(Theme.ChartCpLinePen, rect);
}
protected override bool InObject(int x, int y)
{
if (_lineRect == Rect.Empty)
{
return false;
}
var r = Rect.Inflate(_lineRect, new Size(0, 2));
return r.Contains(x, y);
}
protected override bool IsObjectOnChart()
{
return true;
}
public override void ApplyTheme(IChartTheme theme)
{
base.ApplyTheme(theme);
LineColor = theme.ChartObjectLineColor;
}
public override void CopyTemplate(ObjectBase objectBase, bool style)
{
if (objectBase is HorizontalLineObject obj)
{
Alert.Copy(obj.Alert, !style);
OnPropertyChanged(nameof(Alert));
AlertMinDistance = obj.AlertMinDistance;
Text = obj.Text;
TextAlignment = obj.TextAlignment;
FontSize = obj.FontSize;
LineColor = obj.LineColor;
LineWidth = obj.LineWidth;
LineStyle = obj.LineStyle;
}
base.CopyTemplate(objectBase, style);
}
private double _lastAlertValue;
private int _lastAlertIndex;
public override void CheckAlert(List<IndicatorBase> indicators)
{
if (!Alert.IsActive)
{
return;
}
try
{
foreach (var indicator in indicators)
{
if (indicator.CheckAlert(ControlPoints[0].Y, AlertMinDistance, ref _lastAlertIndex,
ref _lastAlertValue))
{
var message =
$"{indicator.Name}: пересечение уровня {DataProvider.Symbol.FormatPrice((decimal) ControlPoints[0].Y)}.";
AddAlert(Alert, message);
}
}
}
catch (Exception e)
{
LogManager.WriteError(e);
}
}
}
}
Last updated