Профиль объёма

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

  1. Support

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

    Регистрация:
    5 сен 2015
    Сообщения:
    1 329
    Симпатии:
    292
    Код графического объекта Профиль объёма
    1. //------------------------------------------------------------------------------
    2. //
    3. // Графический объект VolumeProfile. 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.Data;
    15. using TigerTrade.Chart.Objects.Common;
    16. using TigerTrade.Core.UI.Converters;
    17. using TigerTrade.Dx;
    18. using TigerTrade.Dx.Enums;
    19.  
    20. namespace TigerTrade.Chart.Objects.Custom
    21. {
    22.     [TypeConverter(typeof(EnumDescriptionTypeConverter))]
    23.     [DataContract(Name = "VolumeProfileType", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Objects.Custom")]
    24.     public enum VolumeProfileType
    25.     {
    26.         [EnumMember(Value = "Volume"), Description("Volume")]
    27.         Volume,
    28.         [EnumMember(Value = "Trades"), Description("Trades")]
    29.         Trades,
    30.         [EnumMember(Value = "Delta"), Description("Delta")]
    31.         Delta,
    32.         [EnumMember(Value = "BidAsk"), Description("Bid x Ask")]
    33.         BidAsk
    34.     }
    35.  
    36.     [TypeConverter(typeof(EnumDescriptionTypeConverter))]
    37.     [DataContract(Name = "VolumeProfileMaximumType", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Objects.Custom")]
    38.     public enum VolumeProfileMaximumType
    39.     {
    40.         [EnumMember(Value = "Volume"), Description("Volume")]
    41.         Volume,
    42.         [EnumMember(Value = "Trades"), Description("Trades")]
    43.         Trades,
    44.         [EnumMember(Value = "Delta"), Description("Delta")]
    45.         Delta,
    46.         [EnumMember(Value = "DeltaPlus"), Description("Delta+")]
    47.         DeltaPlus,
    48.         [EnumMember(Value = "DeltaMinus"), Description("Delta-")]
    49.         DeltaMinus,
    50.         [EnumMember(Value = "Bid"), Description("Bid")]
    51.         Bid,
    52.         [EnumMember(Value = "Ask"), Description("Ask")]
    53.         Ask
    54.     }
    55.  
    56.     [DataContract(Name = "VolumeProfileObject", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Objects.Custom")]
    57.     [ChartObject("X_VolumeProfile", "Профиль объёма", 2, Type = typeof(VolumeProfileObject))]
    58.     public sealed class VolumeProfileObject : ObjectBase
    59.     {
    60.         private VolumeProfileType _profileType;
    61.  
    62.         [DataMember(Name = "ProfileType")]
    63.         [Category("Профиль"), DisplayName("Тип")]
    64.         public VolumeProfileType ProfileType
    65.         {
    66.             get => _profileType;
    67.             set
    68.             {
    69.                 if (value == _profileType)
    70.                 {
    71.                     return;
    72.                 }
    73.  
    74.                 _profileType = value;
    75.  
    76.                 OnPropertyChanged();
    77.             }
    78.         }
    79.  
    80.         private XBrush _profileBrush;
    81.  
    82.         private XColor _profileColor;
    83.  
    84.         [DataMember(Name = "ProfileColor")]
    85.         [Category("Профиль"), DisplayName("Цвет")]
    86.         public XColor ProfileColor
    87.         {
    88.             get => _profileColor;
    89.             set
    90.             {
    91.                 if (value == _profileColor)
    92.                 {
    93.                     return;
    94.                 }
    95.  
    96.                 _profileColor = value;
    97.  
    98.                 _profileBrush = new XBrush(_profileColor);
    99.  
    100.                 OnPropertyChanged();
    101.             }
    102.         }
    103.  
    104.         private XBrush _profile2Brush;
    105.  
    106.         private XColor _profile2Color;
    107.  
    108.         [DataMember(Name = "Profile2Color")]
    109.         [Category("Профиль"), DisplayName("Цвет 2")]
    110.         public XColor Profile2Color
    111.         {
    112.             get => _profile2Color;
    113.             set
    114.             {
    115.                 if (value == _profile2Color)
    116.                 {
    117.                     return;
    118.                 }
    119.  
    120.                 _profile2Color = value;
    121.  
    122.                 _profile2Brush = new XBrush(_profile2Color);
    123.  
    124.                 OnPropertyChanged();
    125.             }
    126.         }
    127.  
    128.         private bool _extendProfile;
    129.  
    130.         [DataMember(Name = "ExtendProfile")]
    131.         [Category("Профиль"), DisplayName("Расширить")]
    132.         public bool ExtendProfile
    133.         {
    134.             get => _extendProfile;
    135.             set
    136.             {
    137.                 if (value == _extendProfile)
    138.                 {
    139.                     return;
    140.                 }
    141.  
    142.                 _extendProfile = value;
    143.  
    144.                 OnPropertyChanged();
    145.             }
    146.         }
    147.  
    148.         private bool _showCumValue;
    149.  
    150.         [DataMember(Name = "ShowCumValue")]
    151.         [Category("Профиль"), DisplayName("Отобр. общ. знач.")]
    152.         public bool ShowCumValue
    153.         {
    154.             get => _showCumValue;
    155.             set
    156.             {
    157.                 if (value == _showCumValue)
    158.                 {
    159.                     return;
    160.                 }
    161.  
    162.                 _showCumValue = value;
    163.  
    164.                 OnPropertyChanged();
    165.             }
    166.         }
    167.  
    168.         private bool _showValues;
    169.  
    170.         [DataMember(Name = "ShowValues")]
    171.         [Category("Значения"), DisplayName("Отображать")]
    172.         public bool ShowValues
    173.         {
    174.             get => _showValues;
    175.             set
    176.             {
    177.                 if (value == _showValues)
    178.                 {
    179.                     return;
    180.                 }
    181.  
    182.                 _showValues = value;
    183.  
    184.                 OnPropertyChanged();
    185.             }
    186.         }
    187.  
    188.         private bool _minimizeValues;
    189.  
    190.         [DataMember(Name = "MinimizeValues")]
    191.         [Category("Значения"), DisplayName("Минимизировать")]
    192.         public bool MinimizeValues
    193.         {
    194.             get => _minimizeValues;
    195.             set
    196.             {
    197.                 if (value == _minimizeValues)
    198.                 {
    199.                     return;
    200.                 }
    201.  
    202.                 _minimizeValues = value;
    203.  
    204.                 OnPropertyChanged();
    205.             }
    206.         }
    207.  
    208.         private int _roundValues;
    209.  
    210.         [DefaultValue(0)]
    211.         [DataMember(Name = "RoundValues")]
    212.         [Category("Значения"), DisplayName("Округлять")]
    213.         public int RoundValues
    214.         {
    215.             get => _roundValues;
    216.             set
    217.             {
    218.                 value = Math.Max(-4, Math.Min(4, value));
    219.  
    220.                 if (value == _roundValues)
    221.                 {
    222.                     return;
    223.                 }
    224.  
    225.                 _roundValues = value;
    226.  
    227.                 OnPropertyChanged();
    228.             }
    229.         }
    230.  
    231.         private XBrush _valuesBrush;
    232.  
    233.         private XColor _valuesColor;
    234.  
    235.         [DataMember(Name = "ValuesColor")]
    236.         [Category("Значения"), DisplayName("Цвет")]
    237.         public XColor ValuesColor
    238.         {
    239.             get => _valuesColor;
    240.             set
    241.             {
    242.                 if (value == _valuesColor)
    243.                 {
    244.                     return;
    245.                 }
    246.  
    247.                 _valuesColor = value;
    248.  
    249.                 _valuesBrush = new XBrush(_valuesColor);
    250.  
    251.                 OnPropertyChanged();
    252.             }
    253.         }
    254.  
    255.         private VolumeProfileMaximumType _maximumType;
    256.  
    257.         [DataMember(Name = "MaximumType")]
    258.         [Category("Максимум"), DisplayName("Тип")]
    259.         public VolumeProfileMaximumType MaximumType
    260.         {
    261.             get => _maximumType;
    262.             set
    263.             {
    264.                 if (value == _maximumType)
    265.                 {
    266.                     return;
    267.                 }
    268.  
    269.                 _maximumType = value;
    270.  
    271.                 OnPropertyChanged();
    272.             }
    273.         }
    274.  
    275.         private bool _showMaximum;
    276.  
    277.         [DataMember(Name = "ShowMaximum")]
    278.         [Category("Максимум"), DisplayName("Отображать")]
    279.         public bool ShowMaximum
    280.         {
    281.             get => _showMaximum;
    282.             set
    283.             {
    284.                 if (value == _showMaximum)
    285.                 {
    286.                     return;
    287.                 }
    288.  
    289.                 _showMaximum = value;
    290.  
    291.                 OnPropertyChanged();
    292.             }
    293.         }
    294.  
    295.         private bool _showMaximumValue;
    296.  
    297.         [DataMember(Name = "ShowMaximumValue")]
    298.         [Category("Максимум"), DisplayName("Значение")]
    299.         public bool ShowMaximumValue
    300.         {
    301.             get => _showMaximumValue;
    302.             set
    303.             {
    304.                 if (value == _showMaximumValue)
    305.                 {
    306.                     return;
    307.                 }
    308.  
    309.                 _showMaximumValue = value;
    310.  
    311.                 OnPropertyChanged();
    312.             }
    313.         }
    314.  
    315.         private bool _extendMaximum;
    316.  
    317.         [DataMember(Name = "ExtendMaximum")]
    318.         [Category("Максимум"), DisplayName("Продлить")]
    319.         public bool ExtendMaximum
    320.         {
    321.             get => _extendMaximum;
    322.             set
    323.             {
    324.                 if (value == _extendMaximum)
    325.                 {
    326.                     return;
    327.                 }
    328.  
    329.                 _extendMaximum = value;
    330.  
    331.                 OnPropertyChanged();
    332.             }
    333.         }
    334.  
    335.         private XBrush _maximumBrush;
    336.  
    337.         private XColor _maximumColor;
    338.  
    339.         [DataMember(Name = "MaximumColor")]
    340.         [Category("Максимум"), DisplayName("Цвет")]
    341.         public XColor MaximumColor
    342.         {
    343.             get => _maximumColor;
    344.             set
    345.             {
    346.                 if (value == _maximumColor)
    347.                 {
    348.                     return;
    349.                 }
    350.  
    351.                 _maximumColor = value;
    352.  
    353.                 _maximumBrush = new XBrush(_maximumColor);
    354.  
    355.                 OnPropertyChanged();
    356.             }
    357.         }
    358.  
    359.         private bool _showValueArea;
    360.  
    361.         [DataMember(Name = "ShowValueArea")]
    362.         [Category("Value Area"), DisplayName("Отображать")]
    363.         public bool ShowValueArea
    364.         {
    365.             get => _showValueArea;
    366.             set
    367.             {
    368.                 if (value == _showValueArea)
    369.                 {
    370.                     return;
    371.                 }
    372.  
    373.                 _showValueArea = value;
    374.  
    375.                 OnPropertyChanged();
    376.             }
    377.         }
    378.  
    379.         private bool _extendValueArea;
    380.  
    381.         [DataMember(Name = "ExtendValueArea")]
    382.         [Category("Value Area"), DisplayName("Продлить")]
    383.         public bool ExtendValueArea
    384.         {
    385.             get => _extendValueArea;
    386.             set
    387.             {
    388.                 if (value == _extendValueArea)
    389.                 {
    390.                     return;
    391.                 }
    392.  
    393.                 _extendValueArea = value;
    394.  
    395.                 OnPropertyChanged();
    396.             }
    397.         }
    398.  
    399.         private int _valueAreaPercent;
    400.  
    401.         [DataMember(Name = "ValueAreaPercent")]
    402.         [Category("Value Area"), DisplayName("ValueArea %")]
    403.         public int ValueAreaPercent
    404.         {
    405.             get => _valueAreaPercent;
    406.             set
    407.             {
    408.                 value = Math.Max(0, Math.Min(100, value));
    409.  
    410.                 if (value == 0)
    411.                 {
    412.                     value = 70;
    413.                 }
    414.  
    415.                 if (value == _valueAreaPercent)
    416.                 {
    417.                     return;
    418.                 }
    419.  
    420.                 _valueAreaPercent = value;
    421.  
    422.                 OnPropertyChanged();
    423.             }
    424.         }
    425.  
    426.         private XBrush _valueAreaBrush;
    427.  
    428.         private XColor _valueAreaColor;
    429.  
    430.         [DataMember(Name = "ValueAreaColor")]
    431.         [Category("Value Area"), DisplayName("Цвет")]
    432.         public XColor ValueAreaColor
    433.         {
    434.             get => _valueAreaColor;
    435.             set
    436.             {
    437.                 if (value == _valueAreaColor)
    438.                 {
    439.                     return;
    440.                 }
    441.  
    442.                 _valueAreaColor = value;
    443.  
    444.                 _valueAreaBrush = new XBrush(_valueAreaColor);
    445.  
    446.                 OnPropertyChanged();
    447.             }
    448.         }
    449.  
    450.         private bool _enableFilter;
    451.  
    452.         [DataMember(Name = "EnableFilter")]
    453.         [Category("Фильтр"), DisplayName("Включить")]
    454.         public bool EnableFilter
    455.         {
    456.             get => _enableFilter;
    457.             set
    458.             {
    459.                 if (value == _enableFilter)
    460.                 {
    461.                     return;
    462.                 }
    463.  
    464.                 _enableFilter = value;
    465.  
    466.                 OnPropertyChanged();
    467.             }
    468.         }
    469.  
    470.         private int _filterMin;
    471.  
    472.         [DataMember(Name = "FilterMin")]
    473.         [Category("Фильтр"), DisplayName("Минимум")]
    474.         public int FilterMin
    475.         {
    476.             get => _filterMin;
    477.             set
    478.             {
    479.                 value = Math.Max(0, value);
    480.  
    481.                 if (value == _filterMin)
    482.                 {
    483.                     return;
    484.                 }
    485.  
    486.                 _filterMin = value;
    487.  
    488.                 OnPropertyChanged();
    489.             }
    490.         }
    491.  
    492.         private int _filterMax;
    493.  
    494.         [DataMember(Name = "FilterMax")]
    495.         [Category("Фильтр"), DisplayName("Максимум")]
    496.         public int FilterMax
    497.         {
    498.             get => _filterMax;
    499.             set
    500.             {
    501.                 value = Math.Max(0, value);
    502.  
    503.                 if (value == _filterMax)
    504.                 {
    505.                     return;
    506.                 }
    507.  
    508.                 _filterMax = value;
    509.  
    510.                 OnPropertyChanged();
    511.             }
    512.         }
    513.  
    514.         private XBrush _filterBrush;
    515.  
    516.         private XColor _filterColor;
    517.  
    518.         [DataMember(Name = "FilterColor")]
    519.         [Category("Фильтр"), DisplayName("Цвет")]
    520.         public XColor FilterColor
    521.         {
    522.             get => _filterColor;
    523.             set
    524.             {
    525.                 if (value == _filterColor)
    526.                 {
    527.                     return;
    528.                 }
    529.  
    530.                 _filterColor = value;
    531.  
    532.                 _filterBrush = new XBrush(_filterColor);
    533.  
    534.                 OnPropertyChanged();
    535.             }
    536.         }
    537.  
    538.         private bool _drawBorder;
    539.  
    540.         [DataMember(Name = "DrawBorder")]
    541.         [Category("Граница"), DisplayName("Граница")]
    542.         public bool DrawBorder
    543.         {
    544.             get => _drawBorder;
    545.             set
    546.             {
    547.                 if (value == _drawBorder)
    548.                 {
    549.                     return;
    550.                 }
    551.  
    552.                 _drawBorder = value;
    553.  
    554.                 OnPropertyChanged();
    555.             }
    556.         }
    557.  
    558.         private XBrush _lineBrush;
    559.  
    560.         private XPen _linePen;
    561.  
    562.         private XColor _lineColor;
    563.  
    564.         [DataMember(Name = "LineColor")]
    565.         [Category("Граница"), DisplayName("Цвет линии")]
    566.         public XColor LineColor
    567.         {
    568.             get => _lineColor;
    569.             set
    570.             {
    571.                 if (value == _lineColor)
    572.                 {
    573.                     return;
    574.                 }
    575.  
    576.                 _lineColor = value;
    577.  
    578.                 _lineBrush = new XBrush(_lineColor);
    579.                 _linePen = new XPen(_lineBrush, LineWidth, LineStyle);
    580.  
    581.                 OnPropertyChanged();
    582.             }
    583.         }
    584.  
    585.         private int _lineWidth;
    586.  
    587.         [DataMember(Name = "LineWidth")]
    588.         [Category("Граница"), DisplayName("Толщина линии")]
    589.         public int LineWidth
    590.         {
    591.             get => _lineWidth;
    592.             set
    593.             {
    594.                 value = Math.Max(1, Math.Min(10, value));
    595.  
    596.                 if (value == _lineWidth)
    597.                 {
    598.                     return;
    599.                 }
    600.  
    601.                 _lineWidth = value;
    602.  
    603.                 _linePen = new XPen(_lineBrush, _lineWidth, LineStyle);
    604.  
    605.                 OnPropertyChanged();
    606.             }
    607.         }
    608.  
    609.         private XDashStyle _lineStyle;
    610.  
    611.         [DataMember(Name = "LineStyle")]
    612.         [Category("Граница"), DisplayName("Стиль линии")]
    613.         public XDashStyle LineStyle
    614.         {
    615.             get => _lineStyle;
    616.             set
    617.             {
    618.                 if (value == _lineStyle)
    619.                 {
    620.                     return;
    621.                 }
    622.  
    623.                 _lineStyle = value;
    624.  
    625.                 _linePen = new XPen(_lineBrush, LineWidth, _lineStyle);
    626.  
    627.                 OnPropertyChanged();
    628.             }
    629.         }
    630.  
    631.         private bool _drawBack;
    632.  
    633.         [DataMember(Name = "DrawBack")]
    634.         [Category("Фон"), DisplayName("Фон")]
    635.         public bool DrawBack
    636.         {
    637.             get => _drawBack;
    638.             set
    639.             {
    640.                 if (value == _drawBack)
    641.                 {
    642.                     return;
    643.                 }
    644.  
    645.                 _drawBack = value;
    646.  
    647.                 OnPropertyChanged();
    648.             }
    649.         }
    650.  
    651.         private XBrush _backBrush;
    652.  
    653.         private XColor _backColor;
    654.  
    655.         [DataMember(Name = "BackColor")]
    656.         [Category("Фон"), DisplayName("Цвет фона")]
    657.         public XColor BackColor
    658.         {
    659.             get => _backColor;
    660.             set
    661.             {
    662.                 if (value == _backColor)
    663.                 {
    664.                     return;
    665.                 }
    666.  
    667.                 _backColor = value;
    668.  
    669.                 _backBrush = new XBrush(_backColor);
    670.  
    671.                 OnPropertyChanged();
    672.             }
    673.         }
    674.  
    675.         protected override int PenWidth => LineWidth;
    676.  
    677.         private bool _isObjectInArea;
    678.  
    679.         public class RectangleInfo
    680.         {
    681.             public Point ControlPoint1;
    682.             public Point ControlPoint2;
    683.  
    684.             public Point ExtraPoint1;
    685.             public Point ExtraPoint2;
    686.  
    687.             public Rect Rectangle;
    688.         }
    689.  
    690.         private RectangleInfo _rectInfo;
    691.  
    692.         public VolumeProfileObject()
    693.         {
    694.             ProfileType = VolumeProfileType.Volume;
    695.             ProfileColor = Color.FromArgb(127, 70, 130, 180);
    696.             Profile2Color = Color.FromArgb(127, 178, 34, 34);
    697.             ExtendProfile = false;
    698.             ShowCumValue = false;
    699.  
    700.             ShowValues = false;
    701.             MinimizeValues = false;
    702.             ValuesColor = Color.FromArgb(255, 255, 255, 255);
    703.  
    704.             MaximumType = VolumeProfileMaximumType.Volume;
    705.             ShowMaximum = true;
    706.             ShowMaximumValue = true;
    707.             ExtendMaximum = false;
    708.             MaximumColor = Color.FromArgb(127, 178, 34, 34);
    709.  
    710.             ShowValueArea = true;
    711.             ExtendValueArea = false;
    712.             ValueAreaPercent = 70;
    713.             ValueAreaColor = Color.FromArgb(127, 128, 128, 128);
    714.  
    715.             EnableFilter = false;
    716.             FilterMin = 0;
    717.             FilterMax = 0;
    718.             FilterColor = Color.FromArgb(127, 46, 139, 87);
    719.  
    720.             DrawBorder = true;
    721.             LineColor = Colors.Black;
    722.             LineWidth = 1;
    723.             LineStyle = XDashStyle.Solid;
    724.  
    725.             DrawBack = true;
    726.             BackColor = Color.FromArgb(30, 0, 0, 0);
    727.         }
    728.  
    729.         protected override void Prepare()
    730.         {
    731.             var point1 = ToPoint(ControlPoints[0]);
    732.             var point2 = ToPoint(ControlPoints[1]);
    733.  
    734.             var ep1 = ToPoint(ExtraPoints[0]);
    735.             var ep2 = ToPoint(ExtraPoints[1]);
    736.  
    737.             var w = Canvas.ColumnWidth / 2.0;
    738.             var h = Canvas.StepHeight / 2.0;
    739.  
    740.             if (point1.X > point2.X)
    741.             {
    742.                 point1.X += w;
    743.                 point2.X -= w;
    744.             }
    745.             else
    746.             {
    747.                 point1.X -= w;
    748.                 point2.X += w;
    749.             }
    750.  
    751.             if (point1.Y > point2.Y)
    752.             {
    753.                 point1.Y += h;
    754.                 point2.Y -= h;
    755.             }
    756.             else
    757.             {
    758.                 point1.Y -= h;
    759.                 point2.Y += h;
    760.             }
    761.  
    762.             if (ep1.X > ep2.X)
    763.             {
    764.                 ep1.X += w;
    765.                 ep2.X -= w;
    766.             }
    767.             else
    768.             {
    769.                 ep1.X -= w;
    770.                 ep2.X += w;
    771.             }
    772.  
    773.             if (ep1.Y > ep2.Y)
    774.             {
    775.                 ep1.Y += h;
    776.                 ep2.Y -= h;
    777.             }
    778.             else
    779.             {
    780.                 ep1.Y -= h;
    781.                 ep2.Y += h;
    782.             }
    783.  
    784.             _rectInfo = new RectangleInfo
    785.             {
    786.                 ControlPoint1 = point1,
    787.                 ControlPoint2 = point2,
    788.                 ExtraPoint1 = ep1,
    789.                 ExtraPoint2 = ep2,
    790.                 Rectangle = new Rect(point1, point2)
    791.             };
    792.  
    793.             _isObjectInArea = Canvas.Rect.IntersectsWith(_rectInfo.Rectangle);
    794.         }
    795.  
    796.         protected override void Draw(DxVisualQueue visual, ref List<ObjectLabelInfo> labels)
    797.         {
    798.             if (!ExtendProfile)
    799.             {
    800.                 if (DrawBack)
    801.                 {
    802.                     visual.FillRectangle(_backBrush, _rectInfo.Rectangle);
    803.                 }
    804.  
    805.                 if (DrawBorder)
    806.                 {
    807.                     visual.DrawRectangle(_linePen, _rectInfo.Rectangle);
    808.                 }
    809.             }
    810.  
    811.             if (!Canvas.IsStock)
    812.             {
    813.                 return;
    814.             }
    815.  
    816.             var index1 = 0;
    817.             var index2 = 1;
    818.  
    819.             if (ControlPoints[0].X > ControlPoints[1].X)
    820.             {
    821.                 index1 = 1;
    822.                 index2 = 0;
    823.             }
    824.  
    825.             var bar1 = Canvas.DateToIndex(ControlPoints[index1].X, 0);
    826.             var bar2 = Canvas.DateToIndex(ControlPoints[index2].X, 0);
    827.  
    828.             var step = DataProvider.Step;
    829.  
    830.             var maxPrice = (long)(Math.Max(ControlPoints[0].Y, ControlPoints[1].Y) / step);
    831.             var minPrice = (long)(Math.Min(ControlPoints[0].Y, ControlPoints[1].Y) / step);
    832.  
    833.             var profile = new RawCluster(DateTime.MinValue);
    834.  
    835.             if (ExtendProfile)
    836.             {
    837.                 for (var i = bar1; i <= bar2; i++)
    838.                 {
    839.                     var cluster = DataProvider.GetRawCluster(i);
    840.  
    841.                     if (cluster == null)
    842.                     {
    843.                         continue;
    844.                     }
    845.  
    846.                     foreach (var item in cluster.Items)
    847.                     {
    848.                         profile.AddItem(item);
    849.                     }
    850.  
    851.                     maxPrice = Math.Max(maxPrice, cluster.High);
    852.                     minPrice = Math.Min(minPrice, cluster.Low);
    853.                 }
    854.             }
    855.             else
    856.             {
    857.                 for (var i = bar1; i <= bar2; i++)
    858.                 {
    859.                     var cluster = DataProvider.GetRawCluster(i);
    860.  
    861.                     if (cluster == null)
    862.                     {
    863.                         continue;
    864.                     }
    865.  
    866.                     foreach (var item in cluster.Items)
    867.                     {
    868.                         if (item.Price >= minPrice && item.Price <= maxPrice)
    869.                         {
    870.                             profile.AddItem(item);
    871.                         }
    872.                     }
    873.                 }
    874.             }
    875.  
    876.             profile.UpdateData();
    877.  
    878.             if (profile.Volume <= 0)
    879.             {
    880.                 return;
    881.             }
    882.  
    883.             var valueArea = ShowValueArea ? profile.GetValueArea(ValueAreaPercent) : null;
    884.  
    885.             var p1 = ToPoint(ControlPoints[index1]);
    886.             var p2 = ToPoint(ControlPoints[index2]);
    887.  
    888.             switch (ProfileType)
    889.             {
    890.                 case VolumeProfileType.Volume:
    891.  
    892.                     DrawVolume(visual, profile, valueArea, p1, p2, ref labels);
    893.  
    894.                     break;
    895.  
    896.                 case VolumeProfileType.Trades:
    897.  
    898.                     DrawTrades(visual, profile, valueArea, p1, p2, ref labels);
    899.  
    900.                     break;
    901.  
    902.                 case VolumeProfileType.Delta:
    903.  
    904.                     DrawDelta(visual, profile, valueArea, p1, p2, ref labels);
    905.  
    906.                     break;
    907.  
    908.                 case VolumeProfileType.BidAsk:
    909.  
    910.                     DrawBidAsk(visual, profile, valueArea, p1, p2, ref labels);
    911.  
    912.                     break;
    913.             }
    914.  
    915.             if (ShowCumValue)
    916.             {
    917.                 DrawValues(visual, profile);
    918.             }
    919.         }
    920.  
    921.         private void DrawValues(DxVisualQueue visual, IRawCluster profile)
    922.         {
    923.             var symbol = DataProvider.Symbol;
    924.  
    925.             var mainRect = _rectInfo.Rectangle;
    926.  
    927.             var height = Canvas.ChartFont.GetHeight();
    928.  
    929.             var rect = new Rect(new Point(mainRect.Left + 2, mainRect.Bottom + 4),
    930.                 new Point(mainRect.Right - 2, mainRect.Bottom + height + 4));
    931.  
    932.             switch (ProfileType)
    933.             {
    934.                 case VolumeProfileType.Volume:
    935.  
    936.                     var volumeText = symbol.FormatRawSize(profile.Volume, RoundValues, MinimizeValues);
    937.  
    938.                     visual.DrawString($"V: {volumeText}", Canvas.ChartFont, _valuesBrush, rect, XTextAlignment.Right);
    939.  
    940.                     break;
    941.  
    942.                 case VolumeProfileType.Trades:
    943.  
    944.                     var tradesText = symbol.FormatTrades(profile.Trades, RoundValues, MinimizeValues);
    945.  
    946.                     visual.DrawString($"T: {tradesText}", Canvas.ChartFont, _valuesBrush, rect, XTextAlignment.Right);
    947.  
    948.                     break;
    949.  
    950.                 case VolumeProfileType.Delta:
    951.  
    952.                     var deltaText = symbol.FormatRawSize(profile.Delta, RoundValues, MinimizeValues);
    953.  
    954.                     visual.DrawString($"D: {deltaText}", Canvas.ChartFont, _valuesBrush, rect, XTextAlignment.Right);
    955.  
    956.                     break;
    957.  
    958.                 case VolumeProfileType.BidAsk:
    959.  
    960.                     var bidText = symbol.FormatRawSize(profile.Bid, RoundValues, MinimizeValues);
    961.                     var askText = symbol.FormatRawSize(profile.Ask, RoundValues, MinimizeValues);
    962.  
    963.                     visual.DrawString($"B: {bidText} A: {askText}", Canvas.ChartFont, _valuesBrush, rect,
    964.                         XTextAlignment.Right);
    965.  
    966.                     break;
    967.             }
    968.         }
    969.  
    970.         private bool CheckMaximum(IRawClusterItem item, IRawClusterMaxValues maxValues)
    971.         {
    972.             switch (MaximumType)
    973.             {
    974.                 case VolumeProfileMaximumType.Volume:
    975.  
    976.                     return item.Volume == maxValues.MaxVolume;
    977.  
    978.                 case VolumeProfileMaximumType.Trades:
    979.  
    980.                     return item.Trades == maxValues.MaxTrades;
    981.  
    982.                 case VolumeProfileMaximumType.Delta:
    983.  
    984.                     return Math.Abs(item.Delta) ==
    985.                            Math.Max(Math.Abs(maxValues.MaxDelta), Math.Abs(maxValues.MinDelta));
    986.  
    987.                 case VolumeProfileMaximumType.DeltaPlus:
    988.  
    989.                     return item.Delta > 0 && item.Delta == maxValues.MaxDelta;
    990.  
    991.                 case VolumeProfileMaximumType.DeltaMinus:
    992.  
    993.                     return item.Delta < 0 && item.Delta == maxValues.MinDelta;
    994.  
    995.                 case VolumeProfileMaximumType.Bid:
    996.  
    997.                     return item.Bid == maxValues.MaxBid;
    998.  
    999.                 case VolumeProfileMaximumType.Ask:
    1000.  
    1001.                     return item.Ask == maxValues.MaxAsk;
    1002.             }
    1003.  
    1004.             return false;
    1005.         }
    1006.  
    1007.         private string FormatMaximum(IRawClusterItem item)
    1008.         {
    1009.             switch (MaximumType)
    1010.             {
    1011.                 case VolumeProfileMaximumType.Volume:
    1012.  
    1013.                     return DataProvider.Symbol.FormatRawSize(item.Volume, RoundValues, MinimizeValues);
    1014.  
    1015.                 case VolumeProfileMaximumType.Trades:
    1016.  
    1017.                     return DataProvider.Symbol.FormatTrades(item.Trades, RoundValues, MinimizeValues);
    1018.  
    1019.                 case VolumeProfileMaximumType.Delta:
    1020.                 case VolumeProfileMaximumType.DeltaPlus:
    1021.                 case VolumeProfileMaximumType.DeltaMinus:
    1022.  
    1023.                     return DataProvider.Symbol.FormatRawSize(item.Delta, RoundValues, MinimizeValues);
    1024.  
    1025.                 case VolumeProfileMaximumType.Bid:
    1026.  
    1027.                     return DataProvider.Symbol.FormatRawSize(item.Bid, RoundValues, MinimizeValues);
    1028.  
    1029.                 case VolumeProfileMaximumType.Ask:
    1030.  
    1031.                     return DataProvider.Symbol.FormatRawSize(item.Ask, RoundValues, MinimizeValues);
    1032.             }
    1033.  
    1034.             return "";
    1035.         }
    1036.  
    1037.         private void DrawVolume(DxVisualQueue visual, IRawCluster profile, IRawClusterValueArea valueArea,
    1038.             Point p1, Point p2, ref List<ObjectLabelInfo> labels)
    1039.         {
    1040.             var colorRects = new List<Tuple<Rect, XBrush>>();
    1041.             var colorRects2 = new List<Tuple<Rect, XBrush>>();
    1042.             var valueRects = new List<Tuple<Rect, string>>();
    1043.             var valueRects2 = new List<Tuple<Rect, string>>();
    1044.  
    1045.             var step = DataProvider.Step;
    1046.             var symbol = DataProvider.Symbol;
    1047.  
    1048.             var height = Math.Max(Canvas.StepHeight, 1);
    1049.  
    1050.             var fontSize = Math.Min(height - 2, 18) * 96 / 72;
    1051.  
    1052.             fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
    1053.  
    1054.             var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
    1055.  
    1056.             var dist = Math.Max(p2.X - p1.X + Canvas.ColumnWidth - LineWidth, 0);
    1057.  
    1058.             var left = p1.X - Canvas.ColumnWidth / 2.0 + Math.Ceiling(LineWidth / 2.0);
    1059.  
    1060.             if (ExtendProfile)
    1061.             {
    1062.                 if (DrawBack)
    1063.                 {
    1064.                     visual.FillRectangle(_backBrush,
    1065.                         new Rect(new Point(left, Canvas.Rect.Top), new Point(left + dist, Canvas.Rect.Bottom)));
    1066.                 }
    1067.  
    1068.                 if (DrawBorder)
    1069.                 {
    1070.                     visual.DrawLine(_linePen, new Point(left, Canvas.Rect.Top),
    1071.                         new Point(left, Canvas.Rect.Bottom));
    1072.                     visual.DrawLine(_linePen, new Point(left + dist, Canvas.Rect.Top),
    1073.                         new Point(left + dist, Canvas.Rect.Bottom));
    1074.                 }
    1075.             }
    1076.  
    1077.             if (profile.High - profile.Low > 100000)
    1078.             {
    1079.                 return;
    1080.             }
    1081.  
    1082.             var maxValues = profile.MaxValues;
    1083.  
    1084.             var roundValues = RoundValues;
    1085.  
    1086.             var prevX = (int)left;
    1087.             var prevY = (int)GetY((profile.High + .5) * step);
    1088.  
    1089.             var points = new List<Point>
    1090.             {
    1091.                 new Point(prevX, prevY)
    1092.             };
    1093.  
    1094.             for (var j = profile.High; j >= profile.Low; j--)
    1095.             {
    1096.                 var item = profile.GetItem(j) ?? new RawClusterItem(j);
    1097.  
    1098.                 var width = item.Volume > 0 ? Math.Min(dist / maxValues.MaxVolume * item.Volume, dist) : 0;
    1099.  
    1100.                 var currX = (int)(left + width);
    1101.                 var currY = (int)GetY((j - .5) * step);
    1102.  
    1103.                 var currHeight = Math.Max(currY - prevY, height);
    1104.  
    1105.                 if (currY <= prevY && points.Count > 2)
    1106.                 {
    1107.                     if (currX > prevX)
    1108.                     {
    1109.                         points[points.Count - 2] = new Point(currX, points[points.Count - 2].Y);
    1110.                         points[points.Count - 1] = new Point(currX, points[points.Count - 1].Y);
    1111.  
    1112.                         prevX = currX;
    1113.                     }
    1114.                 }
    1115.                 else
    1116.                 {
    1117.                     points.Add(new Point(currX, prevY));
    1118.                     points.Add(new Point(currX, currY));
    1119.  
    1120.                     prevX = currX;
    1121.                 }
    1122.  
    1123.                 prevY = currY;
    1124.  
    1125.                 var topY = points[points.Count - 2].Y;
    1126.  
    1127.                 if (ShowMaximum && CheckMaximum(item, maxValues))
    1128.                 {
    1129.                     colorRects2.Add(
    1130.                         new Tuple<Rect, XBrush>(
    1131.                             ExtendMaximum
    1132.                                 ? new Rect(new Point(left, topY),
    1133.                                     new Point(Canvas.Rect.Right + 1, topY + currHeight))
    1134.                                 : new Rect(left, topY, dist, currHeight), _maximumBrush));
    1135.  
    1136.                     if (ExtendMaximum)
    1137.                     {
    1138.                         labels.Add(new ObjectLabelInfo(j * step, MaximumColor));
    1139.                     }
    1140.  
    1141.                     if (ShowMaximumValue)
    1142.                     {
    1143.                         var h = Canvas.ChartFont.GetHeight();
    1144.  
    1145.                         valueRects2.Add(new Tuple<Rect, string>(
    1146.                             new Rect(left + 2, topY - h - 2, Math.Max(dist - 4, 1), h),
    1147.                             FormatMaximum(item)));
    1148.                     }
    1149.                 }
    1150.                 else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
    1151.                 {
    1152.                     colorRects2.Add(
    1153.                         new Tuple<Rect, XBrush>(
    1154.                             ExtendValueArea
    1155.                                 ? new Rect(new Point(left, topY), new Point(Canvas.Rect.Right + 1, topY + currHeight))
    1156.                                 : new Rect(left, topY, dist, currHeight), _valueAreaBrush));
    1157.  
    1158.                     if (ExtendValueArea)
    1159.                     {
    1160.                         labels.Add(new ObjectLabelInfo(j * step, ValueAreaColor));
    1161.                     }
    1162.                 }
    1163.                 else if (EnableFilter && item.Volume >= symbol.CorrectSizeFilter(FilterMin) &&
    1164.                          (FilterMax == 0 || item.Volume <= symbol.CorrectSizeFilter(FilterMax)))
    1165.                 {
    1166.                     if (colorRects.Count > 0)
    1167.                     {
    1168.                         var lastRect = colorRects[colorRects.Count - 1].Item1;
    1169.  
    1170.                         if ((int)lastRect.Y == (int)topY)
    1171.                         {
    1172.                             if (width > lastRect.Width)
    1173.                             {
    1174.                                 colorRects[colorRects.Count - 1] =
    1175.                                     new Tuple<Rect, XBrush>(new Rect(left, topY, width, lastRect.Height), _filterBrush);
    1176.                             }
    1177.                         }
    1178.                         else
    1179.                         {
    1180.                             colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight),
    1181.                                 _filterBrush));
    1182.                         }
    1183.                     }
    1184.                     else
    1185.                     {
    1186.                         colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight), _filterBrush));
    1187.                     }
    1188.                 }
    1189.  
    1190.                 if (ShowValues && height > 7 && item.Volume > 0)
    1191.                 {
    1192.                     valueRects.Add(new Tuple<Rect, string>(new Rect(left + 2, topY, dist, height),
    1193.                         symbol.FormatRawSize(item.Volume, roundValues, MinimizeValues)));
    1194.                 }
    1195.             }
    1196.  
    1197.             points.Add(new Point(left, prevY));
    1198.  
    1199.             visual.FillPolygon(_profileBrush, points.ToArray());
    1200.  
    1201.             foreach (var colorRect in colorRects)
    1202.             {
    1203.                 visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1204.             }
    1205.  
    1206.             foreach (var colorRect in colorRects2)
    1207.             {
    1208.                 visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1209.             }
    1210.  
    1211.             foreach (var valueRect in valueRects)
    1212.             {
    1213.                 visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
    1214.             }
    1215.  
    1216.             foreach (var valueRect in valueRects2)
    1217.             {
    1218.                 visual.DrawString(valueRect.Item2, Canvas.ChartFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
    1219.             }
    1220.         }
    1221.  
    1222.         private void DrawTrades(DxVisualQueue visual, IRawCluster profile, IRawClusterValueArea valueArea,
    1223.             Point p1, Point p2, ref List<ObjectLabelInfo> labels)
    1224.         {
    1225.             var colorRects = new List<Tuple<Rect, XBrush>>();
    1226.             var colorRects2 = new List<Tuple<Rect, XBrush>>();
    1227.             var valueRects = new List<Tuple<Rect, string>>();
    1228.             var valueRects2 = new List<Tuple<Rect, string>>();
    1229.  
    1230.             var step = DataProvider.Step;
    1231.             var symbol = DataProvider.Symbol;
    1232.  
    1233.             var height = Math.Max(Canvas.StepHeight, 1);
    1234.  
    1235.             var fontSize = Math.Min(height - 2, 18) * 96 / 72;
    1236.  
    1237.             fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
    1238.  
    1239.             var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
    1240.  
    1241.             var dist = p2.X - p1.X + Canvas.ColumnWidth - LineWidth;
    1242.  
    1243.             var left = p1.X - Canvas.ColumnWidth / 2.0 + Math.Ceiling(LineWidth / 2.0);
    1244.  
    1245.             if (ExtendProfile)
    1246.             {
    1247.                 if (DrawBack)
    1248.                 {
    1249.                     visual.FillRectangle(_backBrush,
    1250.                         new Rect(new Point(left, Canvas.Rect.Top), new Point(left + dist, Canvas.Rect.Bottom)));
    1251.                 }
    1252.  
    1253.                 if (DrawBorder)
    1254.                 {
    1255.                     visual.DrawLine(_linePen, new Point(left, Canvas.Rect.Top),
    1256.                         new Point(left, Canvas.Rect.Bottom));
    1257.                     visual.DrawLine(_linePen, new Point(left + dist, Canvas.Rect.Top),
    1258.                         new Point(left + dist, Canvas.Rect.Bottom));
    1259.                 }
    1260.             }
    1261.  
    1262.             if (profile.High - profile.Low > 10000)
    1263.             {
    1264.                 return;
    1265.             }
    1266.  
    1267.             var maxValues = profile.MaxValues;
    1268.  
    1269.             var roundValues = RoundValues;
    1270.  
    1271.             var prevX = (int)left;
    1272.             var prevY = (int)GetY((profile.High + .5) * step);
    1273.  
    1274.             var points = new List<Point>
    1275.             {
    1276.                 new Point(prevX, prevY)
    1277.             };
    1278.  
    1279.             for (var j = profile.High; j >= profile.Low; j--)
    1280.             {
    1281.                 var item = profile.GetItem(j) ?? new RawClusterItem(j);
    1282.  
    1283.                 var width = item.Trades > 0 ? Math.Min(dist / maxValues.MaxTrades * item.Trades, dist) : 0;
    1284.  
    1285.                 var currX = (int)(left + width);
    1286.                 var currY = (int)GetY((j - .5) * step);
    1287.  
    1288.                 var currHeight = Math.Max(currY - prevY, height);
    1289.  
    1290.                 if (currY <= prevY && points.Count > 2)
    1291.                 {
    1292.                     if (currX > prevX)
    1293.                     {
    1294.                         points[points.Count - 2] = new Point(currX, points[points.Count - 2].Y);
    1295.                         points[points.Count - 1] = new Point(currX, points[points.Count - 1].Y);
    1296.  
    1297.                         prevX = currX;
    1298.                     }
    1299.                 }
    1300.                 else
    1301.                 {
    1302.                     points.Add(new Point(currX, prevY));
    1303.                     points.Add(new Point(currX, currY));
    1304.  
    1305.                     prevX = currX;
    1306.                 }
    1307.  
    1308.                 prevY = currY;
    1309.  
    1310.                 var topY = points[points.Count - 2].Y;
    1311.  
    1312.                 if (ShowMaximum && CheckMaximum(item, maxValues))
    1313.                 {
    1314.                     colorRects2.Add(
    1315.                         new Tuple<Rect, XBrush>(
    1316.                             ExtendMaximum
    1317.                                 ? new Rect(new Point(left, topY),
    1318.                                     new Point(Canvas.Rect.Right + 1, topY + currHeight))
    1319.                                 : new Rect(left, topY, dist, currHeight), _maximumBrush));
    1320.  
    1321.                     if (ExtendMaximum)
    1322.                     {
    1323.                         labels.Add(new ObjectLabelInfo(j * step, MaximumColor));
    1324.                     }
    1325.  
    1326.                     if (ShowMaximumValue)
    1327.                     {
    1328.                         var h = Canvas.ChartFont.GetHeight();
    1329.  
    1330.                         valueRects2.Add(new Tuple<Rect, string>(
    1331.                             new Rect(left + 2, topY - h - 2, Math.Max(dist - 4, 1), h),
    1332.                             FormatMaximum(item)));
    1333.                     }
    1334.                 }
    1335.                 else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
    1336.                 {
    1337.                     colorRects2.Add(
    1338.                         new Tuple<Rect, XBrush>(
    1339.                             ExtendValueArea
    1340.                                 ? new Rect(new Point(left, topY), new Point(Canvas.Rect.Right + 1, topY + currHeight))
    1341.                                 : new Rect(left, topY, dist, currHeight), _valueAreaBrush));
    1342.  
    1343.                     if (ExtendValueArea)
    1344.                     {
    1345.                         labels.Add(new ObjectLabelInfo(j * step, ValueAreaColor));
    1346.                     }
    1347.                 }
    1348.                 else if (EnableFilter && item.Trades >= FilterMin &&
    1349.                          (FilterMax == 0 || item.Trades <= FilterMax))
    1350.                 {
    1351.                     if (colorRects.Count > 0)
    1352.                     {
    1353.                         var lastRect = colorRects[colorRects.Count - 1].Item1;
    1354.  
    1355.                         if ((int)lastRect.Y == (int)topY)
    1356.                         {
    1357.                             if (width > lastRect.Width)
    1358.                             {
    1359.                                 colorRects[colorRects.Count - 1] =
    1360.                                     new Tuple<Rect, XBrush>(new Rect(left, topY, width, lastRect.Height), _filterBrush);
    1361.                             }
    1362.                         }
    1363.                         else
    1364.                         {
    1365.                             colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight),
    1366.                                 _filterBrush));
    1367.                         }
    1368.                     }
    1369.                     else
    1370.                     {
    1371.                         colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight), _filterBrush));
    1372.                     }
    1373.                 }
    1374.  
    1375.                 if (ShowValues && height > 7 && item.Trades > 0)
    1376.                 {
    1377.                     valueRects.Add(new Tuple<Rect, string>(new Rect(left + 2, topY, dist, height),
    1378.                         symbol.FormatTrades(item.Trades, roundValues, MinimizeValues)));
    1379.                 }
    1380.             }
    1381.  
    1382.             points.Add(new Point(left, prevY));
    1383.  
    1384.             visual.FillPolygon(_profileBrush, points.ToArray());
    1385.  
    1386.             foreach (var colorRect in colorRects)
    1387.             {
    1388.                 visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1389.             }
    1390.  
    1391.             foreach (var colorRect in colorRects2)
    1392.             {
    1393.                 visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1394.             }
    1395.  
    1396.             foreach (var valueRect in valueRects)
    1397.             {
    1398.                 visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
    1399.             }
    1400.  
    1401.             foreach (var valueRect in valueRects2)
    1402.             {
    1403.                 visual.DrawString(valueRect.Item2, Canvas.ChartFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
    1404.             }
    1405.         }
    1406.  
    1407.         private void DrawDelta(DxVisualQueue visual, IRawCluster profile, IRawClusterValueArea valueArea,
    1408.             Point p1, Point p2, ref List<ObjectLabelInfo> labels)
    1409.         {
    1410.             var colorRects = new List<Tuple<Rect, XBrush>>();
    1411.             var colorRectsLeft = new List<Tuple<Rect, XBrush>>();
    1412.             var colorRectsRight = new List<Tuple<Rect, XBrush>>();
    1413.             var valueLeftRects = new List<Tuple<Rect, string>>();
    1414.             var valueRightRects = new List<Tuple<Rect, string>>();
    1415.             var valueRects2 = new List<Tuple<Rect, string>>();
    1416.  
    1417.             var step = DataProvider.Step;
    1418.             var symbol = DataProvider.Symbol;
    1419.  
    1420.             var height = Math.Max(Canvas.StepHeight, 1);
    1421.  
    1422.             var fontSize = Math.Min(height - 2, 18) * 96 / 72;
    1423.  
    1424.             fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
    1425.  
    1426.             var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
    1427.  
    1428.             var dist = p2.X - p1.X + Canvas.ColumnWidth - LineWidth;
    1429.  
    1430.             var left = p1.X - Canvas.ColumnWidth / 2.0 + Math.Ceiling(LineWidth / 2.0);
    1431.  
    1432.             if (ExtendProfile)
    1433.             {
    1434.                 if (DrawBack)
    1435.                 {
    1436.                     visual.FillRectangle(_backBrush,
    1437.                         new Rect(new Point(left, Canvas.Rect.Top), new Point(left + dist, Canvas.Rect.Bottom)));
    1438.                 }
    1439.  
    1440.                 if (DrawBorder)
    1441.                 {
    1442.                     visual.DrawLine(_linePen, new Point(left, Canvas.Rect.Top),
    1443.                         new Point(left, Canvas.Rect.Bottom));
    1444.                     visual.DrawLine(_linePen, new Point(left + dist, Canvas.Rect.Top),
    1445.                         new Point(left + dist, Canvas.Rect.Bottom));
    1446.                 }
    1447.             }
    1448.  
    1449.             if (profile.High - profile.Low > 10000)
    1450.             {
    1451.                 return;
    1452.             }
    1453.  
    1454.             var maxValues = profile.MaxValues;
    1455.  
    1456.             var roundValues = RoundValues;
    1457.  
    1458.             var center = left + dist / 2.0;
    1459.  
    1460.             var prevX = (int)center;
    1461.             var prevY = (int)GetY((profile.High + .5) * step);
    1462.  
    1463.             var pointsRight = new List<Point>
    1464.             {
    1465.                 new Point(prevX, prevY)
    1466.             };
    1467.  
    1468.             for (var j = profile.High; j >= profile.Low; j--)
    1469.             {
    1470.                 var item = profile.GetItem(j) ?? new RawClusterItem(j);
    1471.  
    1472.                 var width = item.Delta > 0
    1473.                     ? Math.Min(dist / Math.Max(Math.Abs(maxValues.MinDelta), Math.Abs(maxValues.MaxDelta)) *
    1474.                                Math.Abs(item.Delta), dist) / 2.0
    1475.                     : 0;
    1476.  
    1477.                 var currX = (int)(center + width);
    1478.                 var currY = (int)GetY((j - .5) * step);
    1479.  
    1480.                 var currHeight = Math.Max(currY - prevY, height);
    1481.  
    1482.                 if (currY <= prevY && pointsRight.Count > 2)
    1483.                 {
    1484.                     if (currX > prevX)
    1485.                     {
    1486.                         pointsRight[pointsRight.Count - 2] = new Point(currX, pointsRight[pointsRight.Count - 2].Y);
    1487.                         pointsRight[pointsRight.Count - 1] = new Point(currX, pointsRight[pointsRight.Count - 1].Y);
    1488.  
    1489.                         prevX = currX;
    1490.                     }
    1491.                 }
    1492.                 else
    1493.                 {
    1494.                     pointsRight.Add(new Point(currX, prevY));
    1495.                     pointsRight.Add(new Point(currX, currY));
    1496.  
    1497.                     prevX = currX;
    1498.                 }
    1499.  
    1500.                 prevY = currY;
    1501.  
    1502.                 var topY = pointsRight[pointsRight.Count - 2].Y;
    1503.  
    1504.                 if (ShowMaximum && CheckMaximum(item, maxValues))
    1505.                 {
    1506.                     colorRects.Add(
    1507.                         new Tuple<Rect, XBrush>(
    1508.                             ExtendMaximum
    1509.                                 ? new Rect(new Point(left, topY),
    1510.                                     new Point(Canvas.Rect.Right + 1, topY + currHeight))
    1511.                                 : new Rect(left, topY, dist, currHeight), _maximumBrush));
    1512.  
    1513.                     if (ExtendMaximum)
    1514.                     {
    1515.                         labels.Add(new ObjectLabelInfo(j * step, MaximumColor));
    1516.                     }
    1517.  
    1518.                     if (ShowMaximumValue)
    1519.                     {
    1520.                         var h = Canvas.ChartFont.GetHeight();
    1521.  
    1522.                         valueRects2.Add(new Tuple<Rect, string>(
    1523.                             new Rect(left + 2, topY - h - 2, Math.Max(dist - 4, 1), h),
    1524.                             FormatMaximum(item)));
    1525.                     }
    1526.                 }
    1527.                 else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
    1528.                 {
    1529.                     colorRects.Add(
    1530.                         new Tuple<Rect, XBrush>(
    1531.                             ExtendValueArea
    1532.                                 ? new Rect(new Point(left, topY), new Point(Canvas.Rect.Right + 1, topY + currHeight))
    1533.                                 : new Rect(left, topY, dist, currHeight), _valueAreaBrush));
    1534.  
    1535.                     if (ExtendValueArea)
    1536.                     {
    1537.                         labels.Add(new ObjectLabelInfo(j * step, ValueAreaColor));
    1538.                     }
    1539.                 }
    1540.                 else if (EnableFilter)
    1541.                 {
    1542.                     if (item.Delta > 0 && item.Delta >= symbol.CorrectSizeFilter(FilterMin) &&
    1543.                         (FilterMax == 0 || item.Delta <= symbol.CorrectSizeFilter(FilterMax)))
    1544.                     {
    1545.                         if (colorRectsRight.Count > 0)
    1546.                         {
    1547.                             var lastRect = colorRectsRight[colorRectsRight.Count - 1].Item1;
    1548.  
    1549.                             if ((int)lastRect.Y == (int)topY)
    1550.                             {
    1551.                                 if (width > lastRect.Width)
    1552.                                 {
    1553.                                     colorRectsRight[colorRectsRight.Count - 1] =
    1554.                                         new Tuple<Rect, XBrush>(new Rect(center, topY, width, lastRect.Height), _filterBrush);
    1555.                                 }
    1556.                             }
    1557.                             else
    1558.                             {
    1559.                                 colorRectsRight.Add(new Tuple<Rect, XBrush>(new Rect(center, topY, width, currHeight),
    1560.                                     _filterBrush));
    1561.                             }
    1562.                         }
    1563.                         else
    1564.                         {
    1565.                             colorRectsRight.Add(new Tuple<Rect, XBrush>(new Rect(center, topY, width, currHeight), _filterBrush));
    1566.                         }
    1567.                     }
    1568.                 }
    1569.  
    1570.                 if (ShowValues && height > 7 && item.Delta > 0)
    1571.                 {
    1572.                     valueRightRects.Add(new Tuple<Rect, string>(new Rect(center + 2, topY, dist / 2.0, height),
    1573.                         symbol.FormatRawSize(item.Delta, roundValues, MinimizeValues)));
    1574.                 }
    1575.             }
    1576.  
    1577.             pointsRight.Add(new Point(center, prevY));
    1578.  
    1579.             prevX = (int)center;
    1580.             prevY = (int)GetY((profile.High + .5) * step);
    1581.  
    1582.             var pointsLeft = new List<Point>
    1583.             {
    1584.                 new Point(prevX, prevY)
    1585.             };
    1586.  
    1587.             for (var j = profile.High; j >= profile.Low; j--)
    1588.             {
    1589.                 var item = profile.GetItem(j) ?? new RawClusterItem(j);
    1590.  
    1591.                 var width = item.Delta < 0
    1592.                     ? Math.Min(dist / Math.Max(Math.Abs(maxValues.MinDelta), Math.Abs(maxValues.MaxDelta)) *
    1593.                                Math.Abs(item.Delta), dist) / 2.0
    1594.                     : 0;
    1595.  
    1596.                 var currX = (int)(center - width);
    1597.                 var currY = (int)GetY((j - .5) * step);
    1598.  
    1599.                 var currHeight = Math.Max(currY - prevY, height);
    1600.  
    1601.                 if (currY <= prevY && pointsLeft.Count > 2)
    1602.                 {
    1603.                     if (currX < prevX)
    1604.                     {
    1605.                         pointsLeft[pointsLeft.Count - 2] = new Point(currX, pointsLeft[pointsLeft.Count - 2].Y);
    1606.                         pointsLeft[pointsLeft.Count - 1] = new Point(currX, pointsLeft[pointsLeft.Count - 1].Y);
    1607.  
    1608.                         prevX = currX;
    1609.                     }
    1610.                 }
    1611.                 else
    1612.                 {
    1613.                     pointsLeft.Add(new Point(currX, prevY));
    1614.                     pointsLeft.Add(new Point(currX, currY));
    1615.  
    1616.                     prevX = currX;
    1617.                 }
    1618.  
    1619.                 prevY = currY;
    1620.  
    1621.                 var topY = pointsLeft[pointsLeft.Count - 2].Y;
    1622.  
    1623.                 if (ShowMaximum && CheckMaximum(item, maxValues))
    1624.                 {
    1625.                 }
    1626.                 else if (EnableFilter)
    1627.                 {
    1628.                     if (item.Delta < 0 && -item.Delta >= symbol.CorrectSizeFilter(FilterMin) &&
    1629.                         (FilterMax == 0 || -item.Delta <= symbol.CorrectSizeFilter(FilterMax)))
    1630.                     {
    1631.                         if (colorRectsLeft.Count > 0)
    1632.                         {
    1633.                             var lastRect = colorRectsLeft[colorRectsLeft.Count - 1].Item1;
    1634.  
    1635.                             if ((int)lastRect.Y == (int)topY)
    1636.                             {
    1637.                                 if (width > lastRect.Width)
    1638.                                 {
    1639.                                     colorRectsLeft[colorRectsLeft.Count - 1] =
    1640.                                         new Tuple<Rect, XBrush>(new Rect(center - width, topY, width, lastRect.Height), _filterBrush);
    1641.                                 }
    1642.                             }
    1643.                             else
    1644.                             {
    1645.                                 colorRectsLeft.Add(new Tuple<Rect, XBrush>(new Rect(center - width, topY, width, currHeight),
    1646.                                     _filterBrush));
    1647.                             }
    1648.                         }
    1649.                         else
    1650.                         {
    1651.                             colorRectsLeft.Add(new Tuple<Rect, XBrush>(new Rect(center - width, topY, width, currHeight), _filterBrush));
    1652.                         }
    1653.                     }
    1654.                 }
    1655.  
    1656.                 if (ShowValues && height > 7 && item.Delta < 0)
    1657.                 {
    1658.                     valueLeftRects.Add(new Tuple<Rect, string>(new Rect(left, topY, dist / 2.0 - 2, height),
    1659.                         symbol.FormatRawSize(item.Delta, roundValues, MinimizeValues)));
    1660.                 }
    1661.             }
    1662.  
    1663.             pointsLeft.Add(new Point(center, prevY));
    1664.  
    1665.             visual.FillPolygon(_profile2Brush, pointsLeft.ToArray());
    1666.             visual.FillPolygon(_profileBrush, pointsRight.ToArray());
    1667.  
    1668.             foreach (var colorRect in colorRectsLeft)
    1669.             {
    1670.                 visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1671.             }
    1672.  
    1673.             foreach (var colorRect in colorRectsRight)
    1674.             {
    1675.                 visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1676.             }
    1677.  
    1678.             foreach (var colorRect in colorRects)
    1679.             {
    1680.                 visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1681.             }
    1682.  
    1683.             foreach (var valueRect in valueLeftRects)
    1684.             {
    1685.                 visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
    1686.             }
    1687.  
    1688.             foreach (var valueRect in valueRightRects)
    1689.             {
    1690.                 visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
    1691.             }
    1692.  
    1693.             foreach (var valueRect in valueRects2)
    1694.             {
    1695.                 visual.DrawString(valueRect.Item2, Canvas.ChartFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
    1696.             }
    1697.         }
    1698.  
    1699.         private void DrawBidAsk(DxVisualQueue visual, IRawCluster profile, IRawClusterValueArea valueArea,
    1700.             Point p1, Point p2, ref List<ObjectLabelInfo> labels)
    1701.         {
    1702.             var colorRects = new List<Tuple<Rect, XBrush>>();
    1703.             var colorRectsLeft = new List<Tuple<Rect, XBrush>>();
    1704.             var colorRectsRight = new List<Tuple<Rect, XBrush>>();
    1705.             var valueLeftRects = new List<Tuple<Rect, string>>();
    1706.             var valueRightRects = new List<Tuple<Rect, string>>();
    1707.             var valueRects2 = new List<Tuple<Rect, string>>();
    1708.  
    1709.             var step = DataProvider.Step;
    1710.             var symbol = DataProvider.Symbol;
    1711.  
    1712.             var height = Math.Max(Canvas.StepHeight, 1);
    1713.  
    1714.             var fontSize = Math.Min(height - 2, 18) * 96 / 72;
    1715.  
    1716.             fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
    1717.  
    1718.             var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
    1719.  
    1720.             var dist = p2.X - p1.X + Canvas.ColumnWidth - LineWidth;
    1721.  
    1722.             var left = p1.X - Canvas.ColumnWidth / 2.0 + Math.Ceiling(LineWidth / 2.0);
    1723.  
    1724.             if (ExtendProfile)
    1725.             {
    1726.                 if (DrawBack)
    1727.                 {
    1728.                     visual.FillRectangle(_backBrush,
    1729.                         new Rect(new Point(left, Canvas.Rect.Top), new Point(left + dist, Canvas.Rect.Bottom)));
    1730.                 }
    1731.  
    1732.                 if (DrawBorder)
    1733.                 {
    1734.                     visual.DrawLine(_linePen, new Point(left, Canvas.Rect.Top),
    1735.                         new Point(left, Canvas.Rect.Bottom));
    1736.                     visual.DrawLine(_linePen, new Point(left + dist, Canvas.Rect.Top),
    1737.                         new Point(left + dist, Canvas.Rect.Bottom));
    1738.                 }
    1739.             }
    1740.  
    1741.             if (profile.High - profile.Low > 10000)
    1742.             {
    1743.                 return;
    1744.             }
    1745.  
    1746.             var maxValues = profile.MaxValues;
    1747.  
    1748.             var roundValues = RoundValues;
    1749.  
    1750.             var center = Math.Floor(left + dist / 2.0);
    1751.  
    1752.             var prevX = (int)center;
    1753.             var prevY = (int)GetY((profile.High + .5) * step);
    1754.  
    1755.             var pointsRight = new List<Point>
    1756.             {
    1757.                 new Point(prevX, prevY)
    1758.             };
    1759.  
    1760.             for (var j = profile.High; j >= profile.Low; j--)
    1761.             {
    1762.                 var item = profile.GetItem(j) ?? new RawClusterItem(j);
    1763.  
    1764.                 var askWidth =
    1765.                     (int)(Math.Min(dist / Math.Max(maxValues.MaxBid, maxValues.MaxAsk) * item.Ask, dist) / 2.0);
    1766.  
    1767.                 var currX = (int)(center + askWidth);
    1768.                 var currY = (int)GetY((j - .5) * step);
    1769.  
    1770.                 var currHeight = Math.Max(currY - prevY, height);
    1771.  
    1772.                 if (currY <= prevY && pointsRight.Count > 2)
    1773.                 {
    1774.                     if (currX > prevX)
    1775.                     {
    1776.                         pointsRight[pointsRight.Count - 2] = new Point(currX, pointsRight[pointsRight.Count - 2].Y);
    1777.                         pointsRight[pointsRight.Count - 1] = new Point(currX, pointsRight[pointsRight.Count - 1].Y);
    1778.  
    1779.                         prevX = currX;
    1780.                     }
    1781.                 }
    1782.                 else
    1783.                 {
    1784.                     pointsRight.Add(new Point(currX, prevY));
    1785.                     pointsRight.Add(new Point(currX, currY));
    1786.  
    1787.                     prevX = currX;
    1788.                 }
    1789.  
    1790.                 prevY = currY;
    1791.  
    1792.                 var topY = pointsRight[pointsRight.Count - 2].Y;
    1793.  
    1794.                 if (ShowMaximum && CheckMaximum(item, maxValues))
    1795.                 {
    1796.                     colorRects.Add(
    1797.                         new Tuple<Rect, XBrush>(
    1798.                             ExtendMaximum
    1799.                                 ? new Rect(new Point(left, topY),
    1800.                                     new Point(Canvas.Rect.Right + 1, topY + currHeight))
    1801.                                 : new Rect(left, topY, dist, currHeight), _maximumBrush));
    1802.  
    1803.                     if (ExtendMaximum)
    1804.                     {
    1805.                         labels.Add(new ObjectLabelInfo(j * step, MaximumColor));
    1806.                     }
    1807.  
    1808.                     if (ShowMaximumValue)
    1809.                     {
    1810.                         var h = Canvas.ChartFont.GetHeight();
    1811.  
    1812.                         valueRects2.Add(new Tuple<Rect, string>(
    1813.                             new Rect(left + 2, topY - h - 2, Math.Max(dist - 4, 1), h),
    1814.                             FormatMaximum(item)));
    1815.                     }
    1816.                 }
    1817.                 else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
    1818.                 {
    1819.                     colorRects.Add(
    1820.                         new Tuple<Rect, XBrush>(
    1821.                             ExtendValueArea
    1822.                                 ? new Rect(new Point(left, topY), new Point(Canvas.Rect.Right + 1, topY + currHeight))
    1823.                                 : new Rect(left, topY, dist, currHeight), _valueAreaBrush));
    1824.  
    1825.                     if (ExtendValueArea)
    1826.                     {
    1827.                         labels.Add(new ObjectLabelInfo(j * step, ValueAreaColor));
    1828.                     }
    1829.                 }
    1830.                 else if (EnableFilter)
    1831.                 {
    1832.                     if (item.Ask >= symbol.CorrectSizeFilter(FilterMin) &&
    1833.                         (FilterMax == 0 || item.Ask <= symbol.CorrectSizeFilter(FilterMax)))
    1834.                     {
    1835.                         if (colorRectsRight.Count > 0)
    1836.                         {
    1837.                             var lastRect = colorRectsRight[colorRectsRight.Count - 1].Item1;
    1838.  
    1839.                             if ((int)lastRect.Y == (int)topY)
    1840.                             {
    1841.                                 if (askWidth > lastRect.Width)
    1842.                                 {
    1843.                                     colorRectsRight[colorRectsRight.Count - 1] =
    1844.                                         new Tuple<Rect, XBrush>(new Rect(center, topY, askWidth, lastRect.Height),
    1845.                                             _filterBrush);
    1846.                                 }
    1847.                             }
    1848.                             else
    1849.                             {
    1850.                                 colorRectsRight.Add(
    1851.                                     new Tuple<Rect, XBrush>(new Rect(center, topY, askWidth, currHeight),
    1852.                                         _filterBrush));
    1853.                             }
    1854.                         }
    1855.                         else
    1856.                         {
    1857.                             colorRectsRight.Add(new Tuple<Rect, XBrush>(new Rect(center, topY, askWidth, currHeight),
    1858.                                 _filterBrush));
    1859.                         }
    1860.                     }
    1861.                 }
    1862.  
    1863.                 if (ShowValues && height > 7 && item.Ask > 0)
    1864.                 {
    1865.                     valueRightRects.Add(new Tuple<Rect, string>(new Rect(center + 2, topY, dist / 2.0, height),
    1866.                         symbol.FormatRawSize(item.Ask, roundValues, MinimizeValues)));
    1867.                 }
    1868.             }
    1869.  
    1870.             pointsRight.Add(new Point(center, prevY));
    1871.  
    1872.             prevX = (int)center;
    1873.             prevY = (int)GetY((profile.High + .5) * step);
    1874.  
    1875.             var pointsLeft = new List<Point>
    1876.             {
    1877.                 new Point(prevX, prevY)
    1878.             };
    1879.  
    1880.             for (var j = profile.High; j >= profile.Low; j--)
    1881.             {
    1882.                 var item = profile.GetItem(j) ?? new RawClusterItem(j);
    1883.  
    1884.                 var bidWidth =
    1885.                     (int)(Math.Min(dist / Math.Max(maxValues.MaxBid, maxValues.MaxAsk) * item.Bid, dist) / 2.0);
    1886.  
    1887.                 var currX = (int)(center - bidWidth);
    1888.                 var currY = (int)GetY((j - .5) * step);
    1889.  
    1890.                 var currHeight = Math.Max(currY - prevY, height);
    1891.  
    1892.                 if (currY <= prevY && pointsLeft.Count > 2)
    1893.                 {
    1894.                     if (currX < prevX)
    1895.                     {
    1896.                         pointsLeft[pointsLeft.Count - 2] = new Point(currX, pointsLeft[pointsLeft.Count - 2].Y);
    1897.                         pointsLeft[pointsLeft.Count - 1] = new Point(currX, pointsLeft[pointsLeft.Count - 1].Y);
    1898.  
    1899.                         prevX = currX;
    1900.                     }
    1901.                 }
    1902.                 else
    1903.                 {
    1904.                     pointsLeft.Add(new Point(currX, prevY));
    1905.                     pointsLeft.Add(new Point(currX, currY));
    1906.  
    1907.                     prevX = currX;
    1908.                 }
    1909.  
    1910.                 prevY = currY;
    1911.  
    1912.                 var topY = pointsLeft[pointsLeft.Count - 2].Y;
    1913.  
    1914.                 if (ShowMaximum && CheckMaximum(item, maxValues))
    1915.                 {
    1916.                 }
    1917.                 else if (EnableFilter)
    1918.                 {
    1919.                     if (item.Bid >= symbol.CorrectSizeFilter(FilterMin) &&
    1920.                         (FilterMax == 0 || item.Bid <= symbol.CorrectSizeFilter(FilterMax)))
    1921.                     {
    1922.                         if (colorRectsLeft.Count > 0)
    1923.                         {
    1924.                             var lastRect = colorRectsLeft[colorRectsLeft.Count - 1].Item1;
    1925.  
    1926.                             if ((int)lastRect.Y == (int)topY)
    1927.                             {
    1928.                                 if (bidWidth > lastRect.Width)
    1929.                                 {
    1930.                                     colorRectsLeft[colorRectsLeft.Count - 1] =
    1931.                                         new Tuple<Rect, XBrush>(
    1932.                                             new Rect(center - bidWidth, topY, bidWidth, lastRect.Height), _filterBrush);
    1933.                                 }
    1934.                             }
    1935.                             else
    1936.                             {
    1937.                                 colorRectsLeft.Add(new Tuple<Rect, XBrush>(
    1938.                                     new Rect(center - bidWidth, topY, bidWidth, currHeight), _filterBrush));
    1939.                             }
    1940.                         }
    1941.                         else
    1942.                         {
    1943.                             colorRectsLeft.Add(
    1944.                                 new Tuple<Rect, XBrush>(new Rect(center - bidWidth, topY, bidWidth, currHeight),
    1945.                                     _filterBrush));
    1946.                         }
    1947.                     }
    1948.                 }
    1949.  
    1950.                 if (ShowValues && height > 7 && item.Bid > 0)
    1951.                 {
    1952.                     valueLeftRects.Add(new Tuple<Rect, string>(new Rect(left, topY, dist / 2.0 - 2, height),
    1953.                         symbol.FormatRawSize(item.Bid, roundValues, MinimizeValues)));
    1954.                 }
    1955.             }
    1956.  
    1957.             pointsLeft.Add(new Point(center, prevY));
    1958.  
    1959.             visual.FillPolygon(_profile2Brush, pointsLeft.ToArray());
    1960.             visual.FillPolygon(_profileBrush, pointsRight.ToArray());
    1961.  
    1962.             foreach (var colorRect in colorRectsLeft)
    1963.             {
    1964.                 visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1965.             }
    1966.  
    1967.             foreach (var colorRect in colorRectsRight)
    1968.             {
    1969.                 visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1970.             }
    1971.  
    1972.             foreach (var colorRect in colorRects)
    1973.             {
    1974.                 visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1975.             }
    1976.  
    1977.             foreach (var valueRect in valueLeftRects)
    1978.             {
    1979.                 visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
    1980.             }
    1981.  
    1982.             foreach (var valueRect in valueRightRects)
    1983.             {
    1984.                 visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
    1985.             }
    1986.  
    1987.             foreach (var valueRect in valueRects2)
    1988.             {
    1989.                 visual.DrawString(valueRect.Item2, Canvas.ChartFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
    1990.             }
    1991.         }
    1992.  
    1993.         public override void DrawControlPoints(DxVisualQueue visual)
    1994.         {
    1995.             if (_rectInfo == null)
    1996.             {
    1997.                 return;
    1998.             }
    1999.  
    2000.             DrawControlPoint(visual, _rectInfo.ControlPoint1);
    2001.             DrawControlPoint(visual, _rectInfo.ControlPoint2);
    2002.  
    2003.             DrawControlPoint(visual, _rectInfo.ExtraPoint1);
    2004.             DrawControlPoint(visual, _rectInfo.ExtraPoint2);
    2005.         }
    2006.  
    2007.         public override int GetControlPoint(int x, int y)
    2008.         {
    2009.             if (Canvas == null || _rectInfo == null)
    2010.             {
    2011.                 return -1;
    2012.             }
    2013.  
    2014.             var points = new[] { _rectInfo.ControlPoint1, _rectInfo.ControlPoint2 };
    2015.  
    2016.             for (var i = 0; i < points.Length; i++)
    2017.             {
    2018.                 var distX = points[i].X - x;
    2019.                 var distY = points[i].Y - y;
    2020.  
    2021.                 if (distX * distX + distY * distY < 9.0 + PenWidth / 2.0)
    2022.                 {
    2023.                     return i;
    2024.                 }
    2025.             }
    2026.  
    2027.             return -1;
    2028.         }
    2029.  
    2030.         public override int GetExtraPoint(int x, int y)
    2031.         {
    2032.             if (Canvas == null || _rectInfo == null)
    2033.             {
    2034.                 return -1;
    2035.             }
    2036.  
    2037.             var points = new[] { _rectInfo.ExtraPoint1, _rectInfo.ExtraPoint2 };
    2038.  
    2039.             for (var i = 0; i < points.Length; i++)
    2040.             {
    2041.                 var distX = points[i].X - x;
    2042.                 var distY = points[i].Y - y;
    2043.  
    2044.                 if (distX * distX + distY * distY < 9.0 + PenWidth / 2.0)
    2045.                 {
    2046.                     return i;
    2047.                 }
    2048.             }
    2049.  
    2050.             return -1;
    2051.         }
    2052.  
    2053.         protected override bool IsObjectInArea()
    2054.         {
    2055.             return _isObjectInArea;
    2056.         }
    2057.  
    2058.         protected override bool InObject(int x, int y)
    2059.         {
    2060.             if (_rectInfo == null)
    2061.             {
    2062.                 return false;
    2063.             }
    2064.  
    2065.             return _rectInfo.Rectangle != Rect.Empty && _rectInfo.Rectangle.Contains(x, y);
    2066.         }
    2067.  
    2068.         protected override int GetMinDist(int x, int y)
    2069.         {
    2070.             var rect = _rectInfo.Rectangle;
    2071.  
    2072.             var dx = Math.Min(rect.X + rect.Width - x, x - rect.X);
    2073.             var dy = Math.Min(rect.Y + rect.Height - y, y - rect.Y);
    2074.  
    2075.             var result = Math.Min(dx, dy);
    2076.  
    2077.             return result > 0 ? (int)result : -1;
    2078.         }
    2079.  
    2080.         public override ObjectPoint[] ExtraPoints
    2081.         {
    2082.             get
    2083.             {
    2084.                 var cp1 = ControlPoints[0];
    2085.                 var cp2 = ControlPoints[1];
    2086.  
    2087.                 var ep1 = new ObjectPoint(cp2.X, cp1.Y);
    2088.                 var ep2 = new ObjectPoint(cp1.X, cp2.Y);
    2089.  
    2090.                 var extraPoints = new[] { ep1, ep2 };
    2091.  
    2092.                 return extraPoints;
    2093.             }
    2094.         }
    2095.  
    2096.         public override void ExtraPointChanged(int index, ObjectPoint op)
    2097.         {
    2098.             switch (index)
    2099.             {
    2100.                 case 0:
    2101.  
    2102.                     ControlPoints[1].X = op.X;
    2103.                     ControlPoints[0].Y = op.Y;
    2104.  
    2105.                     break;
    2106.  
    2107.                 case 1:
    2108.  
    2109.                     ControlPoints[0].X = op.X;
    2110.                     ControlPoints[1].Y = op.Y;
    2111.  
    2112.                     break;
    2113.             }
    2114.         }
    2115.  
    2116.         public override void ApplyTheme(IChartTheme theme)
    2117.         {
    2118.             base.ApplyTheme(theme);
    2119.  
    2120.             LineColor = theme.ChartObjectLineColor;
    2121.             BackColor = theme.ChartObjectFillColor;
    2122.         }
    2123.  
    2124.         public override void CopyTemplate(ObjectBase objectBase, bool style)
    2125.         {
    2126.             if (objectBase is VolumeProfileObject obj)
    2127.             {
    2128.                 ProfileType = obj.ProfileType;
    2129.                 ProfileColor = obj.ProfileColor;
    2130.                 Profile2Color = obj.Profile2Color;
    2131.                 ExtendProfile = obj.ExtendProfile;
    2132.                 ShowCumValue = obj.ShowCumValue;
    2133.  
    2134.                 ShowValues = obj.ShowValues;
    2135.                 MinimizeValues = obj.MinimizeValues;
    2136.                 RoundValues = obj.RoundValues;
    2137.                 ValuesColor = obj.ValuesColor;
    2138.  
    2139.                 MaximumType = obj.MaximumType;
    2140.                 ShowMaximum = obj.ShowMaximum;
    2141.                 ShowMaximumValue = obj.ShowMaximumValue;
    2142.                 ExtendMaximum = obj.ExtendMaximum;
    2143.                 MaximumColor = obj.MaximumColor;
    2144.  
    2145.                 ShowValueArea = obj.ShowValueArea;
    2146.                 ExtendValueArea = obj.ExtendValueArea;
    2147.                 ValueAreaPercent = obj.ValueAreaPercent;
    2148.                 ValueAreaColor = obj.ValueAreaColor;
    2149.  
    2150.                 EnableFilter = obj.EnableFilter;
    2151.                 FilterMin = obj.FilterMin;
    2152.                 FilterMax = obj.FilterMax;
    2153.                 FilterColor = obj.FilterColor;
    2154.  
    2155.                 DrawBorder = obj.DrawBorder;
    2156.                 LineColor = obj.LineColor;
    2157.                 LineWidth = obj.LineWidth;
    2158.                 LineStyle = obj.LineStyle;
    2159.  
    2160.                 DrawBack = obj.DrawBack;
    2161.                 BackColor = obj.BackColor;
    2162.             }
    2163.  
    2164.             base.CopyTemplate(objectBase, style);
    2165.         }
    2166.     }
    2167. }