Fibonacci Retracement

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

  1. Support

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

    Регистрация:
    5 сен 2015
    Сообщения:
    1 329
    Симпатии:
    292
    Код графического объекта Fibonacci Retracement
    1. //------------------------------------------------------------------------------
    2. //
    3. // Графический объект FibonacciRetracement. Copyright (c) 2020 Ilya Smirnov. All rights reserved.
    4. //
    5. //------------------------------------------------------------------------------
    6.  
    7. using System;
    8. using System.Collections.Generic;
    9. using System.ComponentModel;
    10. using System.Runtime.Serialization;
    11. using System.Windows;
    12. using System.Windows.Media;
    13. using TigerTrade.Chart.Base;
    14. using TigerTrade.Chart.Objects.Common;
    15. using TigerTrade.Chart.Objects.Enums;
    16. using TigerTrade.Dx;
    17. using TigerTrade.Dx.Enums;
    18.  
    19. namespace TigerTrade.Chart.Objects.Custom
    20. {
    21.     [DataContract(Name = "FibonacciRetracementObject",
    22.         Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Objects.Custom")]
    23.     [ChartObject("X_FibonacciRetracement", "Fibonacci Retracement", 2, Type = typeof(FibonacciRetracementObject))]
    24.     public sealed class FibonacciRetracementObject : 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.         private ObjectTextAlignment _textAlignment;
    142.  
    143.         [DataMember(Name = "TextAlignment")]
    144.         [Category("Текст"), DisplayName("Расположение")]
    145.         public ObjectTextAlignment TextAlignment
    146.         {
    147.             get => _textAlignment;
    148.             set
    149.             {
    150.                 if (value == _textAlignment)
    151.                 {
    152.                     return;
    153.                 }
    154.  
    155.                 _textAlignment = value;
    156.  
    157.                 OnPropertyChanged();
    158.             }
    159.         }
    160.  
    161.         private bool _customLevels;
    162.  
    163.         [DataMember(Name = "CustomLevels")]
    164.         [Category("Свои уровни"), DisplayName("Включить")]
    165.         public bool CustomLevels
    166.         {
    167.             get => _customLevels;
    168.             set
    169.             {
    170.                 if (value == _customLevels)
    171.                 {
    172.                     return;
    173.                 }
    174.  
    175.                 _customLevels = value;
    176.  
    177.                 OnPropertyChanged();
    178.             }
    179.         }
    180.  
    181.         private List<ObjectLine> _lines;
    182.  
    183.         [DataMember(Name = "Levels")]
    184.         [Category("Свои уровни"), DisplayName("Уровни")]
    185.         public List<ObjectLine> Levels
    186.         {
    187.             get => _lines ?? (_lines = new List<ObjectLine>());
    188.             set
    189.             {
    190.                 if (Equals(value, _lines))
    191.                 {
    192.                     return;
    193.                 }
    194.  
    195.                 _lines = value;
    196.  
    197.                 OnPropertyChanged();
    198.             }
    199.         }
    200.  
    201.         private Point[] _startPoints;
    202.         private Point[] _endPoints;
    203.  
    204.         private double[] _split;
    205.  
    206.         protected override int PenWidth => LineWidth;
    207.  
    208.         public FibonacciRetracementObject()
    209.         {
    210.             LineColor = Colors.Black;
    211.             LineWidth = 1;
    212.             LineStyle = XDashStyle.Solid;
    213.  
    214.             OpenStart = false;
    215.             OpenEnd = false;
    216.  
    217.             TextAlignment = ObjectTextAlignment.LeftBottom;
    218.  
    219.             CustomLevels = false;
    220.  
    221.             Levels = new List<ObjectLine>
    222.             {
    223.                 new ObjectLine(0.0, Colors.Black),
    224.                 new ObjectLine(23.6, Colors.Black),
    225.                 new ObjectLine(38.2, Colors.Black),
    226.                 new ObjectLine(50.0, Colors.Black),
    227.                 new ObjectLine(61.8, Colors.Black),
    228.                 new ObjectLine(78.6, Colors.Black),
    229.                 new ObjectLine(100.0, Colors.Black)
    230.             };
    231.         }
    232.  
    233.         protected override void Draw(DxVisualQueue visual, ref List<ObjectLabelInfo> labels)
    234.         {
    235.             CalcPoint();
    236.  
    237.             if (_startPoints == null || _endPoints == null)
    238.             {
    239.                 return;
    240.             }
    241.  
    242.             var p1 = ToPoint(ControlPoints[0]);
    243.             var p2 = ToPoint(ControlPoints[1]);
    244.  
    245.             if (InMove && p1 != new Point() && p2 != new Point())
    246.             {
    247.                 visual.DrawLine(LinePen, p1.X, p1.Y, p2.X, p2.Y);
    248.             }
    249.  
    250.             for (var i = 0; i < _startPoints.Length; i++)
    251.             {
    252.                 if (CustomLevels)
    253.                 {
    254.                     var level = Levels[i];
    255.  
    256.                     if (!level.ShowLine)
    257.                     {
    258.                         continue;
    259.                     }
    260.  
    261.                     visual.DrawLine(level.LinePen, _startPoints[i], _endPoints[i]);
    262.  
    263.                     if (TextAlignment != ObjectTextAlignment.Hide)
    264.                     {
    265.                         visual.DrawString(GetStr(i), Canvas.ChartFont, level.LineBrush, GetRect(i, level.LineWidth));
    266.                     }
    267.                 }
    268.                 else
    269.                 {
    270.                     visual.DrawLine(LinePen, _startPoints[i], _endPoints[i]);
    271.  
    272.                     if (TextAlignment != ObjectTextAlignment.Hide)
    273.                     {
    274.                         visual.DrawString(GetStr(i), Canvas.ChartFont, LineBrush, GetRect(i, LineWidth));
    275.                     }
    276.                 }
    277.             }
    278.         }
    279.  
    280.         private string GetStr(int i)
    281.         {
    282.             var p = DataProvider.Symbol.FormatPrice((decimal)GetPrice(i), true);
    283.  
    284.             return $"{_split[i]:P2} ({p})";
    285.         }
    286.  
    287.         private Rect GetRect(int i, int lineWidth)
    288.         {
    289.             var textSize = Canvas.ChartFont.GetSize(GetStr(i));
    290.  
    291.             var x = 0.0;
    292.             var y = 0.0;
    293.  
    294.             var width = textSize.Width;
    295.  
    296.             switch (TextAlignment)
    297.             {
    298.                 case ObjectTextAlignment.LeftTop:
    299.                 case ObjectTextAlignment.CenterTop:
    300.                 case ObjectTextAlignment.RightTop:
    301.  
    302.                     y = _startPoints[i].Y - 4 - Math.Ceiling(lineWidth / 2.0) - textSize.Height;
    303.  
    304.                     break;
    305.  
    306.                 case ObjectTextAlignment.LeftMiddle:
    307.                 case ObjectTextAlignment.CenterMiddle:
    308.                 case ObjectTextAlignment.RightMiddle:
    309.  
    310.                     y = _startPoints[i].Y - 4 - Math.Ceiling(lineWidth / 2.0);
    311.  
    312.                     break;
    313.  
    314.                 case ObjectTextAlignment.LeftBottom:
    315.                 case ObjectTextAlignment.CenterBottom:
    316.                 case ObjectTextAlignment.RightBottom:
    317.  
    318.                     y = _startPoints[i].Y + 4 + Math.Ceiling(lineWidth / 2.0);
    319.  
    320.                     break;
    321.             }
    322.  
    323.             switch (TextAlignment)
    324.             {
    325.                 case ObjectTextAlignment.LeftTop:
    326.                 case ObjectTextAlignment.LeftMiddle:
    327.                 case ObjectTextAlignment.LeftBottom:
    328.  
    329.                     x = Math.Min(_startPoints[i].X, _endPoints[i].X) + 4;
    330.  
    331.                     break;
    332.  
    333.                 case ObjectTextAlignment.CenterTop:
    334.                 case ObjectTextAlignment.CenterMiddle:
    335.                 case ObjectTextAlignment.CenterBottom:
    336.  
    337.                     x = (_startPoints[i].X + _endPoints[i].X - width) / 2.0;
    338.  
    339.                     break;
    340.  
    341.                 case ObjectTextAlignment.RightTop:
    342.                 case ObjectTextAlignment.RightMiddle:
    343.                 case ObjectTextAlignment.RightBottom:
    344.  
    345.                     x = Math.Max(_startPoints[i].X, _endPoints[i].X) - width - 4;
    346.  
    347.                     break;
    348.             }
    349.  
    350.             return new Rect(x, y, width, textSize.Height);
    351.         }
    352.  
    353.         private void CalcPoint()
    354.         {
    355.             if (CustomLevels)
    356.             {
    357.                 _split = new double[Levels.Count];
    358.  
    359.                 for (var i = 0; i < Levels.Count; i++)
    360.                 {
    361.                     _split[i] = Levels[i].Value / 100.0;
    362.                 }
    363.             }
    364.             else
    365.             {
    366.                 _split = new[] { 0.0, 0.236, 0.382, 0.5, 0.618, 0.786, 1.0 };
    367.             }
    368.  
    369.             var p1 = ToPoint(ControlPoints[0]);
    370.             var p2 = ToPoint(ControlPoints[1]);
    371.  
    372.             _startPoints = new Point[_split.Length];
    373.             _endPoints = new Point[_split.Length];
    374.  
    375.             var op = new ObjectPoint(ControlPoints[0].X, 0.0);
    376.  
    377.             for (var i = 0; i < _split.Length; i++)
    378.             {
    379.                 op.Y = GetPrice(i);
    380.  
    381.                 var p3 = ToPoint(op);
    382.  
    383.                 _startPoints[i] = new Point(p1.X, p3.Y);
    384.                 _endPoints[i] = new Point(p2.X, p3.Y);
    385.             }
    386.  
    387.             for (var i = 0; i < _startPoints.Length; i++)
    388.             {
    389.                 if (_startPoints[i].X <= _endPoints[i].X)
    390.                 {
    391.                     if (OpenStart)
    392.                     {
    393.                         _startPoints[i].X = 0;
    394.                     }
    395.  
    396.                     if (OpenEnd)
    397.                     {
    398.                         _endPoints[i].X = Canvas.Rect.Right;
    399.                     }
    400.                 }
    401.                 else
    402.                 {
    403.                     if (OpenStart)
    404.                     {
    405.                         _endPoints[i].X = 0;
    406.                     }
    407.  
    408.                     if (OpenEnd)
    409.                     {
    410.                         _startPoints[i].X = Canvas.Rect.Right;
    411.                     }
    412.                 }
    413.             }
    414.         }
    415.  
    416.         private double GetPrice(int lineIndex)
    417.         {
    418.             return (ControlPoints[0].Y - ControlPoints[1].Y) * _split[lineIndex] +
    419.                    ControlPoints[1].Y;
    420.         }
    421.  
    422.         protected override bool InObject(int x, int y)
    423.         {
    424.             if (_startPoints == null || _endPoints == null || _startPoints.Length != Levels.Count)
    425.             {
    426.                 return false;
    427.             }
    428.  
    429.             for (var i = 0; i < _startPoints.Length; i++)
    430.             {
    431.                 if (_startPoints[i] == new Point() || (CustomLevels && !Levels[i].ShowLine))
    432.                 {
    433.                     continue;
    434.                 }
    435.  
    436.                 var result = InLineSegment(x, y, _startPoints[i], _endPoints[i], PenWidth + 2);
    437.  
    438.                 if (result)
    439.                 {
    440.                     return true;
    441.                 }
    442.             }
    443.  
    444.             return false;
    445.         }
    446.  
    447.         private static bool InLineSegment(int x, int y, Point p1, Point p2, int width)
    448.         {
    449.             var n1 = Math.Max(p1.X, p2.X);
    450.             var n2 = Math.Min(p1.X, p2.X);
    451.             var n3 = Math.Max(p1.Y, p2.Y);
    452.             var n4 = Math.Min(p1.Y, p2.Y);
    453.  
    454.             return (Math.Abs(Dist(x, y, p1, p2)) <= width) && (x <= n1 + width) && (x >= n2 - width) &&
    455.                    (y <= n3 + width) && (y >= n4 - width);
    456.         }
    457.  
    458.         private static double Dist(int x, int y, Point p1, Point p2)
    459.         {
    460.             var d1 = p1.X - p2.X;
    461.             var d2 = p1.Y - p2.Y;
    462.  
    463.             return ((x - p1.X) * (p2.Y - p1.Y) - (p2.X - p1.X) * (y - p1.Y)) / Math.Sqrt(d1 * d1 + d2 * d2);
    464.         }
    465.  
    466.         public override void ApplyTheme(IChartTheme theme)
    467.         {
    468.             base.ApplyTheme(theme);
    469.  
    470.             LineColor = theme.ChartObjectLineColor;
    471.  
    472.             foreach (var level in Levels)
    473.             {
    474.                 level.LineColor = theme.ChartObjectLineColor;
    475.             }
    476.         }
    477.  
    478.         public override void CopyTemplate(ObjectBase objectBase, bool style)
    479.         {
    480.             if (objectBase is FibonacciRetracementObject obj)
    481.             {
    482.                 LineColor = obj.LineColor;
    483.                 LineWidth = obj.LineWidth;
    484.                 LineStyle = obj.LineStyle;
    485.  
    486.                 OpenStart = obj.OpenStart;
    487.                 OpenEnd = obj.OpenEnd;
    488.  
    489.                 TextAlignment = obj.TextAlignment;
    490.  
    491.                 CustomLevels = obj.CustomLevels;
    492.  
    493.                 Levels = new List<ObjectLine>();
    494.  
    495.                 foreach (var level in obj.Levels)
    496.                 {
    497.                     Levels.Add(new ObjectLine(level));
    498.                 }
    499.  
    500.                 OnPropertyChanged(nameof(Levels));
    501.             }
    502.  
    503.             base.CopyTemplate(objectBase, style);
    504.         }
    505.     }
    506. }