Fibonacci Extensions

Тема в разделе "Примеры графических объектов", создана пользователем Support, 24 апр 2020.

  1. Support

    Support Администратор
    Команда форума

    Регистрация:
    5 сен 2015
    Сообщения:
    1 329
    Симпатии:
    292
    Код графического объекта Fibonacci Extensions
    1.  
    2. //------------------------------------------------------------------------------
    3. //
    4. // Графический объект FibonacciExtensions. Copyright (c) 2020 Ilya Smirnov. All rights reserved.
    5. //
    6. //------------------------------------------------------------------------------
    7.  
    8. using System;
    9. using System.Collections.Generic;
    10. using System.ComponentModel;
    11. using System.Runtime.Serialization;
    12. using System.Windows;
    13. using System.Windows.Media;
    14. using TigerTrade.Chart.Base;
    15. using TigerTrade.Chart.Objects.Common;
    16. using TigerTrade.Chart.Objects.Enums;
    17. using TigerTrade.Dx;
    18. using TigerTrade.Dx.Enums;
    19.  
    20. namespace TigerTrade.Chart.Objects.Custom
    21. {
    22.     [DataContract(Name = "FibonacciExtensionsObject", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Objects.Custom")]
    23.     [ChartObject("X_FibonacciExtensions", "Fibonacci Extensions", 3, Type = typeof(FibonacciExtensionsObject))]
    24.     public sealed class FibonacciExtensionsObject : ObjectBase
    25.     {
    26.         [Browsable(false)]
    27.         private XBrush LineBrush { get; set; }
    28.  
    29.         [Browsable(false)]
    30.         public XPen LinePen { get; private set; }
    31.  
    32.         private XColor _lineColor;
    33.  
    34.         [DataMember(Name = "LineColor")]
    35.         [Category("Линия"), DisplayName("Цвет линии")]
    36.         public XColor LineColor
    37.         {
    38.             get => _lineColor;
    39.             set
    40.             {
    41.                 if (value == _lineColor)
    42.                 {
    43.                     return;
    44.                 }
    45.  
    46.                 _lineColor = value;
    47.  
    48.                 LineBrush = new XBrush(_lineColor);
    49.                 LinePen = new XPen(LineBrush, LineWidth, LineStyle);
    50.  
    51.                 OnPropertyChanged();
    52.             }
    53.         }
    54.  
    55.         private int _lineWidth;
    56.  
    57.         [DataMember(Name = "LineWidth")]
    58.         [Category("Линия"), DisplayName("Толщина линии")]
    59.         public int LineWidth
    60.         {
    61.             get => _lineWidth;
    62.             set
    63.             {
    64.                 value = Math.Max(1, Math.Min(10, value));
    65.  
    66.                 if (value == _lineWidth)
    67.                 {
    68.                     return;
    69.                 }
    70.  
    71.                 _lineWidth = value;
    72.  
    73.                 LinePen = new XPen(LineBrush, _lineWidth, LineStyle);
    74.  
    75.                 OnPropertyChanged();
    76.             }
    77.         }
    78.  
    79.         private XDashStyle _lineStyle;
    80.  
    81.         [DataMember(Name = "LineStyle")]
    82.         [Category("Линия"), DisplayName("Стиль линии")]
    83.         public XDashStyle LineStyle
    84.         {
    85.             get => _lineStyle;
    86.             set
    87.             {
    88.                 if (value == _lineStyle)
    89.                 {
    90.                     return;
    91.                 }
    92.  
    93.                 _lineStyle = value;
    94.  
    95.                 LinePen = new XPen(LineBrush, LineWidth, _lineStyle);
    96.  
    97.                 OnPropertyChanged();
    98.             }
    99.         }
    100.  
    101.         private bool _openStart;
    102.  
    103.         [DataMember(Name = "OpenStart")]
    104.         [Category("Уровни"), DisplayName("Продлить влево")]
    105.         public bool OpenStart
    106.         {
    107.             get => _openStart;
    108.             set
    109.             {
    110.                 if (value == _openStart)
    111.                 {
    112.                     return;
    113.                 }
    114.  
    115.                 _openStart = value;
    116.  
    117.                 OnPropertyChanged();
    118.             }
    119.         }
    120.  
    121.         private bool _openEnd;
    122.  
    123.         [DataMember(Name = "OpenEnd")]
    124.         [Category("Уровни"), DisplayName("Продлить вправо")]
    125.         public bool OpenEnd
    126.         {
    127.             get => _openEnd;
    128.             set
    129.             {
    130.                 if (value == _openEnd)
    131.                 {
    132.                     return;
    133.                 }
    134.  
    135.                 _openEnd = value;
    136.  
    137.                 OnPropertyChanged();
    138.             }
    139.         }
    140.  
    141.         [Browsable(false)]
    142.         private XBrush LevelsLineBrush { get; set; }
    143.  
    144.         [Browsable(false)]
    145.         private XPen LevelsLinePen { get; set; }
    146.  
    147.         private XColor _levelsLineColor;
    148.  
    149.         [DataMember(Name = "LevelsLineColor")]
    150.         [Category("Уровни"), DisplayName("Цвет линии")]
    151.         public XColor LevelsLineColor
    152.         {
    153.             get => _levelsLineColor;
    154.             set
    155.             {
    156.                 if (value == _levelsLineColor)
    157.                 {
    158.                     return;
    159.                 }
    160.  
    161.                 _levelsLineColor = value;
    162.  
    163.                 LevelsLineBrush = new XBrush(_levelsLineColor);
    164.                 LevelsLinePen = new XPen(LevelsLineBrush, LevelsLineWidth, LineStyle);
    165.  
    166.                 OnPropertyChanged();
    167.             }
    168.         }
    169.  
    170.         private int _levelsLineWidth;
    171.  
    172.         [DataMember(Name = "LevelsLineWidth")]
    173.         [Category("Уровни"), DisplayName("Толщина линии")]
    174.         public int LevelsLineWidth
    175.         {
    176.             get => _levelsLineWidth;
    177.             set
    178.             {
    179.                 value = Math.Max(1, Math.Min(10, value));
    180.  
    181.                 if (value == _levelsLineWidth)
    182.                 {
    183.                     return;
    184.                 }
    185.  
    186.                 _levelsLineWidth = value;
    187.  
    188.                 LevelsLinePen = new XPen(LevelsLineBrush, _levelsLineWidth, LineStyle);
    189.  
    190.                 OnPropertyChanged();
    191.             }
    192.         }
    193.  
    194.         private XDashStyle _levelsLineStyle;
    195.  
    196.         [DataMember(Name = "LevelsLineStyle")]
    197.         [Category("Уровни"), DisplayName("Стиль линии")]
    198.         public XDashStyle LevelsLineStyle
    199.         {
    200.             get => _levelsLineStyle;
    201.             set
    202.             {
    203.                 if (value == _lineStyle)
    204.                 {
    205.                     return;
    206.                 }
    207.  
    208.                 _levelsLineStyle = value;
    209.  
    210.                 LevelsLinePen = new XPen(LevelsLineBrush, LevelsLineWidth, _lineStyle);
    211.  
    212.                 OnPropertyChanged();
    213.             }
    214.         }
    215.  
    216.         private int _levelsWidth;
    217.  
    218.         [DataMember(Name = "LevelsWidth")]
    219.         [Category("Уровни"), DisplayName("Ширина уровня")]
    220.         public int LevelsWidth
    221.         {
    222.             get => _levelsWidth;
    223.             set
    224.             {
    225.                 value = Math.Max(20, Math.Min(500, value));
    226.  
    227.                 if (value == _levelsWidth)
    228.                 {
    229.                     return;
    230.                 }
    231.  
    232.                 _levelsWidth = value;
    233.  
    234.                 OnPropertyChanged();
    235.             }
    236.         }
    237.  
    238.         private ObjectTextAlignment _textAlignment;
    239.  
    240.         [DataMember(Name = "TextAlignment")]
    241.         [Category("Уровни"), DisplayName("Текст")]
    242.         public ObjectTextAlignment TextAlignment
    243.         {
    244.             get => _textAlignment;
    245.             set
    246.             {
    247.                 if (value == _textAlignment)
    248.                 {
    249.                     return;
    250.                 }
    251.  
    252.                 _textAlignment = value;
    253.  
    254.                 OnPropertyChanged();
    255.             }
    256.         }
    257.  
    258.         private bool _customLevels;
    259.  
    260.         [DataMember(Name = "CustomLevels")]
    261.         [Category("Свои уровни"), DisplayName("Включить")]
    262.         public bool CustomLevels
    263.         {
    264.             get => _customLevels;
    265.             set
    266.             {
    267.                 if (value == _customLevels)
    268.                 {
    269.                     return;
    270.                 }
    271.  
    272.                 _customLevels = value;
    273.  
    274.                 OnPropertyChanged();
    275.             }
    276.         }
    277.  
    278.         private List<ObjectLine> _lines;
    279.  
    280.         [DataMember(Name = "Levels")]
    281.         [Category("Свои уровни"), DisplayName("Уровни")]
    282.         public List<ObjectLine> Levels
    283.         {
    284.             get => _lines ?? (_lines = new List<ObjectLine>());
    285.             set
    286.             {
    287.                 if (Equals(value, _lines))
    288.                 {
    289.                     return;
    290.                 }
    291.  
    292.                 _lines = value;
    293.  
    294.                 OnPropertyChanged();
    295.             }
    296.         }
    297.  
    298.         private Point[] _startPoints;
    299.         private Point[] _endPoints;
    300.  
    301.         private double[] _split;
    302.  
    303.         protected override int PenWidth => LineWidth;
    304.  
    305.         public FibonacciExtensionsObject()
    306.         {
    307.             LineColor = Colors.Black;
    308.             LineWidth = 1;
    309.             LineStyle = XDashStyle.Solid;
    310.  
    311.             OpenStart = false;
    312.             OpenEnd = false;
    313.  
    314.             LevelsLineColor = Colors.Black;
    315.             LevelsLineWidth = 1;
    316.             LevelsLineStyle = XDashStyle.Solid;
    317.  
    318.             LevelsWidth = 200;
    319.  
    320.             TextAlignment = ObjectTextAlignment.LeftBottom;
    321.  
    322.             CustomLevels = false;
    323.  
    324.             Levels = new List<ObjectLine>
    325.             {
    326.                 new ObjectLine(0.0, Colors.Black),
    327.                 new ObjectLine(23.6, Colors.Black),
    328.                 new ObjectLine(38.2, Colors.Black),
    329.                 new ObjectLine(50.0, Colors.Black),
    330.                 new ObjectLine(61.8, Colors.Black),
    331.                 new ObjectLine(78.6, Colors.Black),
    332.                 new ObjectLine(100.0, Colors.Black),
    333.                 new ObjectLine(161.8, Colors.Black),
    334.                 new ObjectLine(261.8, Colors.Black),
    335.                 new ObjectLine(361.8, Colors.Black),
    336.                 new ObjectLine(423.6, Colors.Black)
    337.             };
    338.         }
    339.  
    340.         protected override void Draw(DxVisualQueue visual, ref List<ObjectLabelInfo> labels)
    341.         {
    342.             CalcPoint();
    343.  
    344.             if (_startPoints == null || _endPoints == null)
    345.             {
    346.                 return;
    347.             }
    348.  
    349.             var points = ToPoints(ControlPoints);
    350.  
    351.             visual.DrawLines(LinePen, points);
    352.  
    353.             if (InSetup)
    354.             {
    355.                 if (ControlPoints[0].X == ControlPoints[2].X && ControlPoints[0].Y == ControlPoints[2].Y)
    356.                 {
    357.                     return;
    358.                 }
    359.             }
    360.  
    361.             for (var i = 0; i < _startPoints.Length; i++)
    362.             {
    363.                 if (CustomLevels)
    364.                 {
    365.                     var level = Levels[i];
    366.  
    367.                     if (!level.ShowLine)
    368.                     {
    369.                         continue;
    370.                     }
    371.  
    372.                     visual.DrawLine(level.LinePen, _startPoints[i], _endPoints[i]);
    373.  
    374.                     if (TextAlignment != ObjectTextAlignment.Hide)
    375.                     {
    376.                         visual.DrawString(GetStr(i), Canvas.ChartFont, level.LineBrush, GetRect(i, level.LineWidth));
    377.                     }
    378.                 }
    379.                 else
    380.                 {
    381.                     visual.DrawLine(LevelsLinePen, _startPoints[i], _endPoints[i]);
    382.  
    383.                     if (TextAlignment != ObjectTextAlignment.Hide)
    384.                     {
    385.                         visual.DrawString(GetStr(i), Canvas.ChartFont, LevelsLineBrush, GetRect(i, LineWidth));
    386.                     }
    387.                 }
    388.             }
    389.         }
    390.  
    391.         private string GetStr(int i)
    392.         {
    393.             var p = DataProvider.Symbol.FormatPrice((decimal)GetPrice(i), true);
    394.  
    395.             return $"{_split[i]:P2} ({p})";
    396.         }
    397.  
    398.         private Rect GetRect(int i, int lineWidth)
    399.         {
    400.             var textSize = Canvas.ChartFont.GetSize(GetStr(i));
    401.  
    402.             var x = 0.0;
    403.             var y = 0.0;
    404.  
    405.             var width = textSize.Width;
    406.  
    407.             switch (TextAlignment)
    408.             {
    409.                 case ObjectTextAlignment.LeftTop:
    410.                 case ObjectTextAlignment.CenterTop:
    411.                 case ObjectTextAlignment.RightTop:
    412.  
    413.                     y = _startPoints[i].Y - 4 - Math.Ceiling(lineWidth / 2.0) - textSize.Height;
    414.  
    415.                     break;
    416.  
    417.                 case ObjectTextAlignment.LeftMiddle:
    418.                 case ObjectTextAlignment.CenterMiddle:
    419.                 case ObjectTextAlignment.RightMiddle:
    420.  
    421.                     y = _startPoints[i].Y - 4 - Math.Ceiling(lineWidth / 2.0);
    422.  
    423.                     break;
    424.  
    425.                 case ObjectTextAlignment.LeftBottom:
    426.                 case ObjectTextAlignment.CenterBottom:
    427.                 case ObjectTextAlignment.RightBottom:
    428.  
    429.                     y = _startPoints[i].Y + 4 + Math.Ceiling(lineWidth / 2.0);
    430.  
    431.                     break;
    432.             }
    433.  
    434.             switch (TextAlignment)
    435.             {
    436.                 case ObjectTextAlignment.LeftTop:
    437.                 case ObjectTextAlignment.LeftMiddle:
    438.                 case ObjectTextAlignment.LeftBottom:
    439.  
    440.                     x = Math.Min(_startPoints[i].X, _endPoints[i].X) + 4;
    441.  
    442.                     break;
    443.  
    444.                 case ObjectTextAlignment.CenterTop:
    445.                 case ObjectTextAlignment.CenterMiddle:
    446.                 case ObjectTextAlignment.CenterBottom:
    447.  
    448.                     x = (_startPoints[i].X + _endPoints[i].X - width) / 2.0;
    449.  
    450.                     break;
    451.  
    452.                 case ObjectTextAlignment.RightTop:
    453.                 case ObjectTextAlignment.RightMiddle:
    454.                 case ObjectTextAlignment.RightBottom:
    455.  
    456.                     x = Math.Max(_startPoints[i].X, _endPoints[i].X) - width - 4;
    457.  
    458.                     break;
    459.             }
    460.  
    461.             return new Rect(x, y, width, textSize.Height);
    462.         }
    463.  
    464.         private void CalcPoint()
    465.         {
    466.             if (CustomLevels)
    467.             {
    468.                 _split = new double[Levels.Count];
    469.  
    470.                 for (var i = 0; i < Levels.Count; i++)
    471.                 {
    472.                     _split[i] = Levels[i].Value / 100.0;
    473.                 }
    474.             }
    475.             else
    476.             {
    477.                 _split = new[] { 0.0, 0.236, 0.382, 0.5, 0.618, 0.786, 1.0, 1.618, 2.618, 3.618, 4.236 };
    478.             }
    479.  
    480.             var p = ToPoint(ControlPoints[2]);
    481.  
    482.             _startPoints = new Point[_split.Length];
    483.             _endPoints = new Point[_split.Length];
    484.  
    485.             var op = new ObjectPoint(ControlPoints[2].X, 0.0);
    486.  
    487.             for (var i = 0; i < _split.Length; i++)
    488.             {
    489.                 op.Y = GetPrice(i);
    490.  
    491.                 var p3 = ToPoint(op);
    492.  
    493.                 _startPoints[i] = new Point(p.X, p3.Y);
    494.                 _endPoints[i] = new Point(p.X + LevelsWidth, p3.Y);
    495.             }
    496.  
    497.             for (var i = 0; i < _startPoints.Length; i++)
    498.             {
    499.                 if (_startPoints[i].X <= _endPoints[i].X)
    500.                 {
    501.                     if (OpenStart)
    502.                     {
    503.                         _startPoints[i].X = 0;
    504.                     }
    505.  
    506.                     if (OpenEnd)
    507.                     {
    508.                         _endPoints[i].X = Canvas.Rect.Right;
    509.                     }
    510.                 }
    511.                 else
    512.                 {
    513.                     if (OpenStart)
    514.                     {
    515.                         _endPoints[i].X = 0;
    516.                     }
    517.  
    518.                     if (OpenEnd)
    519.                     {
    520.                         _startPoints[i].X = Canvas.Rect.Right;
    521.                     }
    522.                 }
    523.             }
    524.         }
    525.  
    526.         private double GetPrice(int lineIndex)
    527.         {
    528.             return (ControlPoints[1].Y - ControlPoints[0].Y) * _split[lineIndex] +
    529.                    ControlPoints[2].Y;
    530.         }
    531.  
    532.         protected override bool InObject(int x, int y)
    533.         {
    534.             if (_startPoints == null || _endPoints == null || _startPoints.Length != Levels.Count)
    535.             {
    536.                 return false;
    537.             }
    538.  
    539.             for (var i = 0; i < _startPoints.Length; i++)
    540.             {
    541.                 if (_startPoints[i] == new Point() || (CustomLevels && !Levels[i].ShowLine))
    542.                 {
    543.                     continue;
    544.                 }
    545.  
    546.                 var result = InLineSegment(x, y, _startPoints[i], _endPoints[i], PenWidth + 2);
    547.  
    548.                 if (result)
    549.                 {
    550.                     return true;
    551.                 }
    552.             }
    553.  
    554.             var points = ToPoints(ControlPoints);
    555.  
    556.             for (var i = 0; i < points.Length - 1; i++)
    557.             {
    558.                 if (InLineSegment(x, y, points[i], points[i + 1], LineWidth + 2))
    559.                 {
    560.                     return true;
    561.                 }
    562.             }
    563.  
    564.             return false;
    565.         }
    566.  
    567.         private static bool InLineSegment(int x, int y, Point p1, Point p2, int width)
    568.         {
    569.             var n1 = Math.Max(p1.X, p2.X);
    570.             var n2 = Math.Min(p1.X, p2.X);
    571.             var n3 = Math.Max(p1.Y, p2.Y);
    572.             var n4 = Math.Min(p1.Y, p2.Y);
    573.  
    574.             return (Math.Abs(Dist(x, y, p1, p2)) <= width) && (x <= n1 + width) && (x >= n2 - width) &&
    575.                    (y <= n3 + width) && (y >= n4 - width);
    576.         }
    577.  
    578.         private static double Dist(int x, int y, Point p1, Point p2)
    579.         {
    580.             var d1 = p1.X - p2.X;
    581.             var d2 = p1.Y - p2.Y;
    582.  
    583.             return ((x - p1.X) * (p2.Y - p1.Y) - (p2.X - p1.X) * (y - p1.Y)) / Math.Sqrt(d1 * d1 + d2 * d2);
    584.         }
    585.  
    586.         public override void ApplyTheme(IChartTheme theme)
    587.         {
    588.             base.ApplyTheme(theme);
    589.  
    590.             LevelsLineColor = theme.ChartObjectLineColor;
    591.             LineColor = theme.ChartObjectLineColor;
    592.  
    593.             foreach (var level in Levels)
    594.             {
    595.                 level.LineColor = theme.ChartObjectLineColor;
    596.             }
    597.         }
    598.  
    599.         public override void CopyTemplate(ObjectBase objectBase, bool style)
    600.         {
    601.             if (objectBase is FibonacciExtensionsObject obj)
    602.             {
    603.                 LineColor = obj.LineColor;
    604.                 LineWidth = obj.LineWidth;
    605.                 LineStyle = obj.LineStyle;
    606.  
    607.                 OpenStart = obj.OpenStart;
    608.                 OpenEnd = obj.OpenEnd;
    609.  
    610.                 LevelsLineColor = obj.LevelsLineColor;
    611.                 LevelsLineStyle = obj.LevelsLineStyle;
    612.                 LevelsLineWidth = obj.LevelsLineWidth;
    613.  
    614.                 LevelsWidth = obj.LevelsWidth;
    615.  
    616.                 TextAlignment = obj.TextAlignment;
    617.  
    618.                 CustomLevels = obj.CustomLevels;
    619.  
    620.                 Levels = new List<ObjectLine>();
    621.  
    622.                 foreach (var level in obj.Levels)
    623.                 {
    624.                     Levels.Add(new ObjectLine(level));
    625.                 }
    626.  
    627.                 OnPropertyChanged(nameof(Levels));
    628.             }
    629.  
    630.             base.CopyTemplate(objectBase, style);
    631.         }
    632.     }
    633. }