VolumeProfiles

Тема в разделе "Примеры индикаторов", создана пользователем Support, 26 июл 2019.

  1. Support

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

    Регистрация:
    5 сен 2015
    Сообщения:
    1 081
    Симпатии:
    219
    Код индикатора VolumeProfiles
    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Runtime.Serialization;
    5. using System.Windows;
    6. using System.Windows.Media;
    7. using TigerTrade.Chart.Base.Enums;
    8. using TigerTrade.Chart.Data;
    9. using TigerTrade.Chart.Indicators.Common;
    10. using TigerTrade.Chart.Indicators.Enums;
    11. using TigerTrade.Core.UI.Converters;
    12. using TigerTrade.Core.Utils.Time;
    13. using TigerTrade.Dx;
    14. using TigerTrade.Dx.Enums;
    15.  
    16. namespace TigerTrade.Chart.Indicators.Custom
    17. {
    18.     [TypeConverter(typeof(EnumDescriptionTypeConverter))]
    19.     [DataContract(Name = "VolumeProfilesPeriodType", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    20.     public enum VolumeProfilesPeriodType
    21.     {
    22.         [EnumMember(Value = "Minute"), Description("Минута")]
    23.         Minute,
    24.         [EnumMember(Value = "Hour"), Description("Час")]
    25.         Hour,
    26.         [EnumMember(Value = "Day"), Description("День")]
    27.         Day,
    28.         [EnumMember(Value = "Week"), Description("Неделя")]
    29.         Week,
    30.         [EnumMember(Value = "Month"), Description("Месяц")]
    31.         Month
    32.     }
    33.  
    34.     [TypeConverter(typeof(EnumDescriptionTypeConverter))]
    35.     [DataContract(Name = "VolumeProfilesType", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    36.     public enum VolumeProfilesType
    37.     {
    38.         [EnumMember(Value = "Volume"), Description("Volume")]
    39.         Volume,
    40.         [EnumMember(Value = "Trades"), Description("Trades")]
    41.         Trades,
    42.         [EnumMember(Value = "Delta"), Description("Delta")]
    43.         Delta,
    44.         [EnumMember(Value = "BidAsk"), Description("Bid x Ask")]
    45.         BidAsk
    46.     }
    47.  
    48.     [TypeConverter(typeof(EnumDescriptionTypeConverter))]
    49.     [DataContract(Name = "VolumeProfilesMaximumType", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    50.     public enum VolumeProfilesMaximumType
    51.     {
    52.         [EnumMember(Value = "Volume"), Description("Volume")]
    53.         Volume,
    54.         [EnumMember(Value = "Trades"), Description("Trades")]
    55.         Trades,
    56.         [EnumMember(Value = "Delta"), Description("Delta")]
    57.         Delta,
    58.         [EnumMember(Value = "DeltaPlus"), Description("Delta+")]
    59.         DeltaPlus,
    60.         [EnumMember(Value = "DeltaMinus"), Description("Delta-")]
    61.         DeltaMinus,
    62.         [EnumMember(Value = "Bid"), Description("Bid")]
    63.         Bid,
    64.         [EnumMember(Value = "Ask"), Description("Ask")]
    65.         Ask
    66.     }
    67.  
    68.     [DataContract(Name = "VolumeProfilesIndicator", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    69.     [Indicator("X_VolumeProfiles", "*VolumeProfiles", true, Type = typeof(VolumeProfilesIndicator))]
    70.     internal sealed class VolumeProfilesIndicator : IndicatorBase
    71.     {
    72.         private List<VolumeProfile> _profiles;
    73.  
    74.         private List<VolumeProfile> Profiles => _profiles ?? (_profiles = new List<VolumeProfile>());
    75.  
    76.         private VolumeProfilesPeriodType _periodType;
    77.  
    78.         [DataMember(Name = "PeriodType")]
    79.         [Category("Период"), DisplayName("Интервал")]
    80.         public VolumeProfilesPeriodType PeriodType
    81.         {
    82.             get => _periodType;
    83.             set
    84.             {
    85.                 if (value == _periodType)
    86.                 {
    87.                     return;
    88.                 }
    89.  
    90.                 _periodType = value;
    91.  
    92.                 _periodValue = _periodType == VolumeProfilesPeriodType.Minute ? 15 : 1;
    93.  
    94.                 Clear();
    95.  
    96.                 OnPropertyChanged();
    97.             }
    98.         }
    99.  
    100.         private int _periodValue;
    101.  
    102.         [DataMember(Name = "PeriodValue")]
    103.         [Category("Период"), DisplayName("Значение")]
    104.         public int PeriodValue
    105.         {
    106.             get => _periodValue;
    107.             set
    108.             {
    109.                 value = Math.Max(1, value);
    110.  
    111.                 if (value == _periodValue)
    112.                 {
    113.                     return;
    114.                 }
    115.  
    116.                 _periodValue = value;
    117.  
    118.                 Clear();
    119.  
    120.                 OnPropertyChanged();
    121.             }
    122.         }
    123.  
    124.         private VolumeProfilesType _profileType;
    125.  
    126.         [DataMember(Name = "ProfileType")]
    127.         [Category("Профиль"), DisplayName("Тип")]
    128.         public VolumeProfilesType ProfileType
    129.         {
    130.             get => _profileType;
    131.             set
    132.             {
    133.                 if (value == _profileType)
    134.                 {
    135.                     return;
    136.                 }
    137.  
    138.                 _profileType = value;
    139.  
    140.                 OnPropertyChanged();
    141.             }
    142.         }
    143.  
    144.         private int _profileProportion;
    145.  
    146.         [DataMember(Name = "ProfileProportion")]
    147.         [Category("Профиль"), DisplayName("Объём шкалы")]
    148.         public int ProfileProportion
    149.         {
    150.             get => _profileProportion;
    151.             set
    152.             {
    153.                 value = Math.Max(0, value);
    154.  
    155.                 if (value == _profileProportion)
    156.                 {
    157.                     return;
    158.                 }
    159.  
    160.                 _profileProportion = value;
    161.  
    162.                 OnPropertyChanged();
    163.             }
    164.         }
    165.  
    166.         private XBrush _profileBrush;
    167.  
    168.         private XColor _profileColor;
    169.  
    170.         [DataMember(Name = "ProfileColor")]
    171.         [Category("Профиль"), DisplayName("Цвет профиля")]
    172.         public XColor ProfileColor
    173.         {
    174.             get => _profileColor;
    175.             set
    176.             {
    177.                 if (value == _profileColor)
    178.                 {
    179.                     return;
    180.                 }
    181.  
    182.                 _profileColor = value;
    183.  
    184.                 _profileBrush = new XBrush(_profileColor);
    185.  
    186.                 OnPropertyChanged();
    187.             }
    188.         }
    189.  
    190.         private XBrush _backBrush;
    191.  
    192.         private XColor _profileBackColor;
    193.  
    194.         [DataMember(Name = "ProfileBackColor")]
    195.         [Category("Профиль"), DisplayName("Цвет фона")]
    196.         public XColor ProfileBackColor
    197.         {
    198.             get => _profileBackColor;
    199.             set
    200.             {
    201.                 if (value == _profileBackColor)
    202.                 {
    203.                     return;
    204.                 }
    205.  
    206.                 _profileBackColor = value;
    207.  
    208.                 _backBrush = new XBrush(_profileBackColor);
    209.  
    210.                 OnPropertyChanged();
    211.             }
    212.         }
    213.  
    214.         private bool _showValues;
    215.  
    216.         [DataMember(Name = "ShowValues")]
    217.         [Category("Значения"), DisplayName("Отображать")]
    218.         public bool ShowValues
    219.         {
    220.             get => _showValues;
    221.             set
    222.             {
    223.                 if (value == _showValues)
    224.                 {
    225.                     return;
    226.                 }
    227.  
    228.                 _showValues = value;
    229.  
    230.                 OnPropertyChanged();
    231.             }
    232.         }
    233.  
    234.         private bool _minimizeValues;
    235.  
    236.         [DataMember(Name = "MinimizeValues")]
    237.         [Category("Значения"), DisplayName("Минимизировать")]
    238.         public bool MinimizeValues
    239.         {
    240.             get => _minimizeValues;
    241.             set
    242.             {
    243.                 if (value == _minimizeValues)
    244.                 {
    245.                     return;
    246.                 }
    247.  
    248.                 _minimizeValues = value;
    249.  
    250.                 OnPropertyChanged();
    251.             }
    252.         }
    253.  
    254.         private IndicatorIntParam _roundValueParam;
    255.  
    256.         [DataMember(Name = "RoundValueParam")]
    257.         public IndicatorIntParam RoundValuesParam
    258.         {
    259.             get => _roundValueParam ?? (_roundValueParam = new IndicatorIntParam(0));
    260.             set => _roundValueParam = value;
    261.         }
    262.  
    263.         [DefaultValue(0)]
    264.         [Category("Значения"), DisplayName("Округлять")]
    265.         public int RoundValues
    266.         {
    267.             get => RoundValuesParam.Get(SettingsLongKey);
    268.             set
    269.             {
    270.                 if (!RoundValuesParam.Set(SettingsLongKey, value, -4, 4))
    271.                 {
    272.                     return;
    273.                 }
    274.  
    275.                 OnPropertyChanged();
    276.             }
    277.         }
    278.  
    279.         private XBrush _valuesBrush;
    280.  
    281.         private XColor _valuesColor;
    282.  
    283.         [DataMember(Name = "ValuesColor")]
    284.         [Category("Значения"), DisplayName("Цвет")]
    285.         public XColor ValuesColor
    286.         {
    287.             get => _valuesColor;
    288.             set
    289.             {
    290.                 if (value == _valuesColor)
    291.                 {
    292.                     return;
    293.                 }
    294.  
    295.                 _valuesColor = value;
    296.  
    297.                 _valuesBrush = new XBrush(_valuesColor);
    298.  
    299.                 OnPropertyChanged();
    300.             }
    301.         }
    302.  
    303.         private VolumeProfilesMaximumType _maximumType;
    304.  
    305.         [DataMember(Name = "MaximumType")]
    306.         [Category("Максимум"), DisplayName("Тип")]
    307.         public VolumeProfilesMaximumType MaximumType
    308.         {
    309.             get => _maximumType;
    310.             set
    311.             {
    312.                 if (value == _maximumType)
    313.                 {
    314.                     return;
    315.                 }
    316.  
    317.                 _maximumType = value;
    318.  
    319.                 OnPropertyChanged();
    320.             }
    321.         }
    322.  
    323.         private bool _showMaximum;
    324.  
    325.         [DataMember(Name = "ShowMaximum")]
    326.         [Category("Максимум"), DisplayName("Отображать")]
    327.         public bool ShowMaximum
    328.         {
    329.             get => _showMaximum;
    330.             set
    331.             {
    332.                 if (value == _showMaximum)
    333.                 {
    334.                     return;
    335.                 }
    336.  
    337.                 _showMaximum = value;
    338.  
    339.                 OnPropertyChanged();
    340.             }
    341.         }
    342.  
    343.         private XBrush _maximumBrush;
    344.  
    345.         private XColor _maximumColor;
    346.  
    347.         [DataMember(Name = "MaximumColor")]
    348.         [Category("Максимум"), DisplayName("Цвет")]
    349.         public XColor MaximumColor
    350.         {
    351.             get => _maximumColor;
    352.             set
    353.             {
    354.                 if (value == _maximumColor)
    355.                 {
    356.                     return;
    357.                 }
    358.  
    359.                 _maximumColor = value;
    360.  
    361.                 _maximumBrush = new XBrush(_maximumColor);
    362.  
    363.                 OnPropertyChanged();
    364.             }
    365.         }
    366.  
    367.         private bool _showValueArea;
    368.  
    369.         [DataMember(Name = "ShowValueArea")]
    370.         [Category("Value Area"), DisplayName("Отображать")]
    371.         public bool ShowValueArea
    372.         {
    373.             get => _showValueArea;
    374.             set
    375.             {
    376.                 if (value == _showValueArea)
    377.                 {
    378.                     return;
    379.                 }
    380.  
    381.                 _showValueArea = value;
    382.  
    383.                 OnPropertyChanged();
    384.             }
    385.         }
    386.  
    387.         private int _valueAreaPercent;
    388.  
    389.         [DataMember(Name = "ValueAreaPercent")]
    390.         [Category("Value Area"), DisplayName("ValueArea %")]
    391.         public int ValueAreaPercent
    392.         {
    393.             get => _valueAreaPercent;
    394.             set
    395.             {
    396.                 value = Math.Max(0, Math.Min(100, value));
    397.  
    398.                 if (value == 0)
    399.                 {
    400.                     value = 70;
    401.                 }
    402.  
    403.                 if (value == _valueAreaPercent)
    404.                 {
    405.                     return;
    406.                 }
    407.  
    408.                 _valueAreaPercent = value;
    409.  
    410.                 Clear();
    411.  
    412.                 OnPropertyChanged();
    413.             }
    414.         }
    415.  
    416.         private XBrush _valueAreaBrush;
    417.  
    418.         private XColor _valueAreaColor;
    419.  
    420.         [DataMember(Name = "ValueAreaColor")]
    421.         [Category("Value Area"), DisplayName("Цвет")]
    422.         public XColor ValueAreaColor
    423.         {
    424.             get => _valueAreaColor;
    425.             set
    426.             {
    427.                 if (value == _valueAreaColor)
    428.                 {
    429.                     return;
    430.                 }
    431.  
    432.                 _valueAreaColor = value;
    433.  
    434.                 _valueAreaBrush = new XBrush(_valueAreaColor);
    435.  
    436.                 OnPropertyChanged();
    437.             }
    438.         }
    439.  
    440.         private bool _enableFilter;
    441.  
    442.         [DataMember(Name = "EnableFilter")]
    443.         [Category("Фильтр"), DisplayName("Включить")]
    444.         public bool EnableFilter
    445.         {
    446.             get => _enableFilter;
    447.             set
    448.             {
    449.                 if (value == _enableFilter)
    450.                 {
    451.                     return;
    452.                 }
    453.  
    454.                 _enableFilter = value;
    455.  
    456.                 OnPropertyChanged();
    457.             }
    458.         }
    459.  
    460.         private int _filterMin;
    461.  
    462.         [DataMember(Name = "FilterValue")]
    463.         [Category("Фильтр"), DisplayName("Минимум")]
    464.         public int FilterMin
    465.         {
    466.             get => _filterMin;
    467.             set
    468.             {
    469.                 value = Math.Max(0, value);
    470.  
    471.                 if (value == _filterMin)
    472.                 {
    473.                     return;
    474.                 }
    475.  
    476.                 _filterMin = value;
    477.  
    478.                 OnPropertyChanged();
    479.             }
    480.         }
    481.  
    482.         private int _filterMax;
    483.  
    484.         [DataMember(Name = "FilterMax")]
    485.         [Category("Фильтр"), DisplayName("Максимум")]
    486.         public int FilterMax
    487.         {
    488.             get => _filterMax;
    489.             set
    490.             {
    491.                 value = Math.Max(0, value);
    492.  
    493.                 if (value == _filterMax)
    494.                 {
    495.                     return;
    496.                 }
    497.  
    498.                 _filterMax = value;
    499.  
    500.                 OnPropertyChanged();
    501.             }
    502.         }
    503.  
    504.         private XBrush _filterBrush;
    505.  
    506.         private XColor _filterColor;
    507.  
    508.         [DataMember(Name = "FilterColor")]
    509.         [Category("Фильтр"), DisplayName("Цвет")]
    510.         public XColor FilterColor
    511.         {
    512.             get => _filterColor;
    513.             set
    514.             {
    515.                 if (value == _filterColor)
    516.                 {
    517.                     return;
    518.                 }
    519.  
    520.                 _filterColor = value;
    521.  
    522.                 _filterBrush = new XBrush(_filterColor);
    523.  
    524.                 OnPropertyChanged();
    525.             }
    526.         }
    527.  
    528.         [Browsable(false)]
    529.         public override bool ShowIndicatorValues => false;
    530.  
    531.         [Browsable(false)]
    532.         public override bool ShowIndicatorLabels => false;
    533.  
    534.         [Browsable(false)]
    535.         public override IndicatorCalculation Calculation => IndicatorCalculation.OnEachTick;
    536.  
    537.         public VolumeProfilesIndicator()
    538.         {
    539.             ShowIndicatorTitle = false;
    540.  
    541.             PeriodType = VolumeProfilesPeriodType.Hour;
    542.             PeriodValue = 1;
    543.  
    544.             ProfileType = VolumeProfilesType.Volume;
    545.             ProfileProportion = 0;
    546.             ProfileColor = Color.FromArgb(127, 70, 130, 180);
    547.             ProfileBackColor = Color.FromArgb(30, 70, 130, 180);
    548.  
    549.             ShowValues = false;
    550.             MinimizeValues = false;
    551.             ValuesColor = Color.FromArgb(255, 255, 255, 255);
    552.  
    553.             MaximumType = VolumeProfilesMaximumType.Volume;
    554.             ShowMaximum = true;
    555.             MaximumColor = Color.FromArgb(127, 178, 34, 34);
    556.  
    557.             ShowValueArea = true;
    558.             ValueAreaPercent = 70;
    559.             ValueAreaColor = Color.FromArgb(127, 128, 128, 128);
    560.  
    561.             EnableFilter = false;
    562.             FilterMin = 0;
    563.             FilterMax = 0;
    564.             FilterColor = Color.FromArgb(127, 46, 139, 87);
    565.         }
    566.  
    567.         private int _lastFullID;
    568.  
    569.         private void Clear()
    570.         {
    571.             _lastFullID = 0;
    572.  
    573.             Profiles.Clear();
    574.         }
    575.  
    576.         private int GetSequence(DateTime date, double offset)
    577.         {
    578.             var cycleBase = ChartPeriodType.Hour;
    579.  
    580.             switch (PeriodType)
    581.             {
    582.                 case VolumeProfilesPeriodType.Minute:
    583.  
    584.                     cycleBase = ChartPeriodType.Minute;
    585.  
    586.                     break;
    587.  
    588.                 case VolumeProfilesPeriodType.Hour:
    589.  
    590.                     cycleBase = ChartPeriodType.Hour;
    591.  
    592.                     break;
    593.  
    594.                 case VolumeProfilesPeriodType.Day:
    595.  
    596.                     cycleBase = ChartPeriodType.Day;
    597.  
    598.                     break;
    599.  
    600.                 case VolumeProfilesPeriodType.Week:
    601.  
    602.                     cycleBase = ChartPeriodType.Week;
    603.  
    604.                     break;
    605.  
    606.                 case VolumeProfilesPeriodType.Month:
    607.  
    608.                     cycleBase = ChartPeriodType.Month;
    609.  
    610.                     break;
    611.             }
    612.  
    613.             return DataProvider.Period.GetSequence(cycleBase, PeriodValue, date, offset);
    614.         }
    615.  
    616.         protected override void Execute()
    617.         {
    618.             if (ClearData)
    619.             {
    620.                 Clear();
    621.             }
    622.  
    623.             if (Profiles.Count > 0 && !Profiles[Profiles.Count - 1].Completed)
    624.             {
    625.                 Profiles.RemoveAt(Profiles.Count - 1);
    626.             }
    627.  
    628.             var timeOffset = TimeHelper.GetSessionOffset(DataProvider.Symbol.Exchange);
    629.  
    630.             var lastSequence = -1;
    631.  
    632.             for (var i = _lastFullID; i < DataProvider.Count; i++)
    633.             {
    634.                 var cluster = DataProvider.GetRawCluster(i);
    635.  
    636.                 var currSequence = GetSequence(cluster.Time, timeOffset);
    637.  
    638.                 if (Profiles.Count == 0 || currSequence != lastSequence)
    639.                 {
    640.                     lastSequence = currSequence;
    641.  
    642.                     if (Profiles.Count > 0 && i > _lastFullID)
    643.                     {
    644.                         _lastFullID = i;
    645.  
    646.                         Profiles[Profiles.Count - 1].Completed = true;
    647.  
    648.                         Profiles[Profiles.Count - 1].Cluster.UpdateData();
    649.                     }
    650.  
    651.                     Profiles.Add(new VolumeProfile(new RawCluster(cluster.Time), i));
    652.                 }
    653.  
    654.                 var lastCluster = Profiles[Profiles.Count - 1];
    655.  
    656.                 lastCluster.Cluster.AddCluster(cluster);
    657.  
    658.                 lastCluster.EndBar = i;
    659.             }
    660.  
    661.             if (Profiles.Count > 0 && !Profiles[Profiles.Count - 1].Completed)
    662.             {
    663.                 Profiles[Profiles.Count - 1].Cluster.UpdateData();
    664.             }
    665.         }
    666.  
    667.         public override void Render(DxVisualQueue visual)
    668.         {
    669.             if (Profiles.Count == 0)
    670.             {
    671.                 return;
    672.             }
    673.  
    674.             var minPrice = (long)(Canvas.MinY / Helper.DataProvider.Step) - 1;
    675.             var maxPrice = (long)(Canvas.MaxY / Helper.DataProvider.Step) + 1;
    676.  
    677.             if (maxPrice - minPrice > 20000)
    678.             {
    679.                 return;
    680.             }
    681.  
    682.             switch (ProfileType)
    683.             {
    684.                 case VolumeProfilesType.Volume:
    685.  
    686.                     RenderVolume(visual);
    687.  
    688.                     break;
    689.  
    690.                 case VolumeProfilesType.Trades:
    691.  
    692.                     RenderTrades(visual);
    693.  
    694.                     break;
    695.  
    696.                 case VolumeProfilesType.Delta:
    697.  
    698.                     RenderDelta(visual);
    699.  
    700.                     break;
    701.  
    702.                 case VolumeProfilesType.BidAsk:
    703.  
    704.                     RenderBidAsk(visual);
    705.  
    706.                     break;
    707.             }
    708.         }
    709.  
    710.         private void RenderVolume(DxVisualQueue visual)
    711.         {
    712.             var startIndex = Canvas.Stop;
    713.             var endIndex = Canvas.Stop + Canvas.Count;
    714.  
    715.             var step = DataProvider.Step;
    716.             var symbol = DataProvider.Symbol;
    717.  
    718.             var minFilter = symbol.CorrectSizeFilter(FilterMin);
    719.             var maxFilter = symbol.CorrectSizeFilter(FilterMax);
    720.  
    721.             var proportion = symbol.CorrectSizeFilter(ProfileProportion);
    722.  
    723.             var height = GetY(0.0) - GetY(step);
    724.  
    725.             var fontSize = Math.Min(height - 2, 18) * 96 / 72;
    726.  
    727.             fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
    728.  
    729.             var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
    730.  
    731.             var columnWidth2 = Canvas.ColumnWidth / 2.0;
    732.  
    733.             var roundValues = RoundValues;
    734.  
    735.             var prevRight = int.MinValue;
    736.  
    737.             foreach (var volumeProfile in Profiles)
    738.             {
    739.                 if (volumeProfile.EndBar < startIndex || volumeProfile.StartBar > endIndex)
    740.                 {
    741.                     continue;
    742.                 }
    743.  
    744.                 var x1 = Canvas.GetX(volumeProfile.StartBar);
    745.                 var x2 = Canvas.GetX(volumeProfile.EndBar);
    746.  
    747.                 var profile = volumeProfile.Cluster;
    748.  
    749.                 var maxValues = profile.MaxValues;
    750.  
    751.                 var valueArea = ShowValueArea ? profile.GetValueArea(ValueAreaPercent) : null;
    752.  
    753.                 var left = x1 - columnWidth2;
    754.                 var right = x2 + columnWidth2 - 1;
    755.  
    756.                 if (prevRight != int.MinValue)
    757.                 {
    758.                     left = prevRight;
    759.                 }
    760.  
    761.                 prevRight = (int)right;
    762.  
    763.                 var dist = Math.Max(right - left, 1);
    764.  
    765.                 var max = ProfileProportion > 0 ? proportion : maxValues.MaxVolume;
    766.  
    767.                 var volStep = dist / Math.Max(max, 1);
    768.  
    769.                 var colorRects = new List<Tuple<Rect, XBrush>>();
    770.                 var colorRects2 = new List<Tuple<Rect, XBrush>>();
    771.                 var valueRects = new List<Tuple<Rect, string>>();
    772.  
    773.                 var prevX = (int)left;
    774.                 var prevY = (int)GetY((profile.High + .5) * step);
    775.  
    776.                 var points = new List<Point>
    777.                 {
    778.                     new Point(prevX, prevY)
    779.                 };
    780.  
    781.                 for (var j = profile.High; j >= profile.Low; j--)
    782.                 {
    783.                     var item = profile.GetItem(j) ?? new RawClusterItem(j);
    784.  
    785.                     var width = Math.Min(volStep * item.Volume, dist);
    786.  
    787.                     var currX = (int)(left + width);
    788.                     var currY = (int)GetY((j - .5) * step);
    789.  
    790.                     var currHeight = Math.Max(currY - prevY, 1);
    791.  
    792.                     if (currY == prevY && points.Count > 2)
    793.                     {
    794.                         if (currX > prevX)
    795.                         {
    796.                             points[points.Count - 2] = new Point(currX, points[points.Count - 2].Y);
    797.                             points[points.Count - 1] = new Point(currX, points[points.Count - 1].Y);
    798.  
    799.                             prevX = currX;
    800.                         }
    801.                     }
    802.                     else
    803.                     {
    804.                         points.Add(new Point(currX, prevY));
    805.                         points.Add(new Point(currX, currY));
    806.  
    807.                         prevX = currX;
    808.                     }
    809.  
    810.                     prevY = currY;
    811.  
    812.                     var topY = points[points.Count - 2].Y;
    813.  
    814.                     if (ShowMaximum && CheckMaximum(item, maxValues))
    815.                     {
    816.                         colorRects2.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, dist, currHeight), _maximumBrush));
    817.                     }
    818.                     else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
    819.                     {
    820.                         colorRects2.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, dist, currHeight),
    821.                             _valueAreaBrush));
    822.                     }
    823.                     else if (EnableFilter && item.Volume >= minFilter &&
    824.                              (maxFilter == 0 || item.Volume <= maxFilter))
    825.                     {
    826.                         if (colorRects.Count > 0)
    827.                         {
    828.                             var lastRect = colorRects[colorRects.Count - 1].Item1;
    829.  
    830.                             if ((int)lastRect.Y == (int)topY)
    831.                             {
    832.                                 if (width > lastRect.Width)
    833.                                 {
    834.                                     colorRects[colorRects.Count - 1] =
    835.                                         new Tuple<Rect, XBrush>(new Rect(left, topY, width, lastRect.Height), _filterBrush);
    836.                                 }
    837.                             }
    838.                             else
    839.                             {
    840.                                 colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight),
    841.                                     _filterBrush));
    842.                             }
    843.                         }
    844.                         else
    845.                         {
    846.                             colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight), _filterBrush));
    847.                         }
    848.                     }
    849.  
    850.                     if (ShowValues && height > 7 && item.Volume > 0)
    851.                     {
    852.                         valueRects.Add(new Tuple<Rect, string>(new Rect(left, topY, dist, height),
    853.                             symbol.FormatRawSize(item.Volume, roundValues, MinimizeValues)));
    854.                     }
    855.                 }
    856.  
    857.                 points.Add(new Point(left, prevY));
    858.  
    859.                 visual.FillRectangle(_backBrush,
    860.                     new Rect(new Point(left, points[0].Y), new Point(right, prevY)));
    861.  
    862.                 visual.FillPolygon(_profileBrush, points.ToArray());
    863.  
    864.                 foreach (var colorRect in colorRects)
    865.                 {
    866.                     visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    867.                 }
    868.  
    869.                 foreach (var colorRect in colorRects2)
    870.                 {
    871.                     visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    872.                 }
    873.  
    874.                 foreach (var valueRect in valueRects)
    875.                 {
    876.                     visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
    877.                 }
    878.             }
    879.         }
    880.  
    881.         private void RenderTrades(DxVisualQueue visual)
    882.         {
    883.             var startIndex = Canvas.Stop;
    884.             var endIndex = Canvas.Stop + Canvas.Count;
    885.  
    886.             var step = DataProvider.Step;
    887.             var symbol = DataProvider.Symbol;
    888.  
    889.             var height = GetY(0.0) - GetY(step);
    890.  
    891.             var fontSize = Math.Min(height - 2, 18) * 96 / 72;
    892.  
    893.             fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
    894.  
    895.             var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
    896.  
    897.             var columnWidth2 = Canvas.ColumnWidth / 2.0;
    898.  
    899.             var roundValues = RoundValues;
    900.  
    901.             var prevRight = int.MinValue;
    902.  
    903.             foreach (var volumeProfile in Profiles)
    904.             {
    905.                 if (volumeProfile.EndBar < startIndex || volumeProfile.StartBar > endIndex)
    906.                 {
    907.                     continue;
    908.                 }
    909.  
    910.                 var x1 = Canvas.GetX(volumeProfile.StartBar);
    911.                 var x2 = Canvas.GetX(volumeProfile.EndBar);
    912.  
    913.                 var profile = volumeProfile.Cluster;
    914.  
    915.                 var maxValues = profile.MaxValues;
    916.  
    917.                 var valueArea = ShowValueArea ? profile.GetValueArea(ValueAreaPercent) : null;
    918.  
    919.                 var left = x1 - columnWidth2;
    920.                 var right = x2 + columnWidth2 - 1;
    921.  
    922.                 if (prevRight != int.MinValue)
    923.                 {
    924.                     left = prevRight;
    925.                 }
    926.  
    927.                 prevRight = (int)right;
    928.  
    929.                 var dist = Math.Max(right - left, 1);
    930.  
    931.                 var max = ProfileProportion > 0 ? ProfileProportion : maxValues.MaxTrades;
    932.  
    933.                 var volStep = dist / Math.Max(max, 1);
    934.  
    935.                 var colorRects = new List<Tuple<Rect, XBrush>>();
    936.                 var colorRects2 = new List<Tuple<Rect, XBrush>>();
    937.                 var valueRects = new List<Tuple<Rect, string>>();
    938.  
    939.                 var prevX = (int)left;
    940.                 var prevY = (int)GetY((profile.High + .5) * step);
    941.  
    942.                 var points = new List<Point>
    943.                 {
    944.                     new Point(prevX, prevY)
    945.                 };
    946.  
    947.                 for (var j = profile.High; j >= profile.Low; j--)
    948.                 {
    949.                     var item = profile.GetItem(j) ?? new RawClusterItem(j);
    950.  
    951.                     var width = Math.Min(volStep * item.Trades, dist);
    952.  
    953.                     var currX = (int)(left + width);
    954.                     var currY = (int)GetY((j - .5) * step);
    955.  
    956.                     var currHeight = Math.Max(currY - prevY, 1);
    957.  
    958.                     if (currY == prevY && points.Count > 2)
    959.                     {
    960.                         if (currX > prevX)
    961.                         {
    962.                             points[points.Count - 2] = new Point(currX, points[points.Count - 2].Y);
    963.                             points[points.Count - 1] = new Point(currX, points[points.Count - 1].Y);
    964.  
    965.                             prevX = currX;
    966.                         }
    967.                     }
    968.                     else
    969.                     {
    970.                         points.Add(new Point(currX, prevY));
    971.                         points.Add(new Point(currX, currY));
    972.  
    973.                         prevX = currX;
    974.                     }
    975.  
    976.                     prevY = currY;
    977.  
    978.                     var topY = points[points.Count - 2].Y;
    979.  
    980.                     if (ShowMaximum && CheckMaximum(item, maxValues))
    981.                     {
    982.                         colorRects2.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, dist, currHeight), _maximumBrush));
    983.                     }
    984.                     else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
    985.                     {
    986.                         colorRects2.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, dist, currHeight),
    987.                             _valueAreaBrush));
    988.                     }
    989.                     else if (EnableFilter && item.Trades >= FilterMin && (FilterMax == 0 || item.Trades <= FilterMax))
    990.                     {
    991.                         if (colorRects.Count > 0)
    992.                         {
    993.                             var lastRect = colorRects[colorRects.Count - 1].Item1;
    994.  
    995.                             if ((int)lastRect.Y == (int)topY)
    996.                             {
    997.                                 if (width > lastRect.Width)
    998.                                 {
    999.                                     colorRects[colorRects.Count - 1] =
    1000.                                         new Tuple<Rect, XBrush>(new Rect(left, topY, width, lastRect.Height), _filterBrush);
    1001.                                 }
    1002.                             }
    1003.                             else
    1004.                             {
    1005.                                 colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight),
    1006.                                     _filterBrush));
    1007.                             }
    1008.                         }
    1009.                         else
    1010.                         {
    1011.                             colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, width, currHeight), _filterBrush));
    1012.                         }
    1013.                     }
    1014.  
    1015.                     if (ShowValues && height > 7 && item.Trades > 0)
    1016.                     {
    1017.                         valueRects.Add(new Tuple<Rect, string>(new Rect(left, topY, dist, height),
    1018.                             symbol.FormatTrades(item.Trades, roundValues, MinimizeValues)));
    1019.                     }
    1020.                 }
    1021.  
    1022.                 points.Add(new Point(left, prevY));
    1023.  
    1024.                 visual.FillRectangle(_backBrush,
    1025.                     new Rect(new Point(left, points[0].Y), new Point(right, prevY)));
    1026.  
    1027.                 visual.FillPolygon(_profileBrush, points.ToArray());
    1028.  
    1029.                 foreach (var colorRect in colorRects)
    1030.                 {
    1031.                     visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1032.                 }
    1033.  
    1034.                 foreach (var colorRect in colorRects2)
    1035.                 {
    1036.                     visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1037.                 }
    1038.  
    1039.                 foreach (var valueRect in valueRects)
    1040.                 {
    1041.                     visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
    1042.                 }
    1043.             }
    1044.         }
    1045.  
    1046.         private void RenderDelta(DxVisualQueue visual)
    1047.         {
    1048.             var startIndex = Canvas.Stop;
    1049.             var endIndex = Canvas.Stop + Canvas.Count;
    1050.  
    1051.             var step = DataProvider.Step;
    1052.             var symbol = DataProvider.Symbol;
    1053.  
    1054.             var minFilter = symbol.CorrectSizeFilter(FilterMin);
    1055.             var maxFilter = symbol.CorrectSizeFilter(FilterMax);
    1056.  
    1057.             var proportion = symbol.CorrectSizeFilter(ProfileProportion);
    1058.  
    1059.             var height = GetY(0.0) - GetY(step);
    1060.  
    1061.             var fontSize = Math.Min(height - 2, 18) * 96 / 72;
    1062.  
    1063.             fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
    1064.  
    1065.             var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
    1066.  
    1067.             var columnWidth2 = Canvas.ColumnWidth / 2.0;
    1068.  
    1069.             var roundValues = RoundValues;
    1070.  
    1071.             var prevRight = int.MinValue;
    1072.  
    1073.             foreach (var volumeProfile in Profiles)
    1074.             {
    1075.                 if (volumeProfile.EndBar < startIndex || volumeProfile.StartBar > endIndex)
    1076.                 {
    1077.                     continue;
    1078.                 }
    1079.  
    1080.                 var x1 = Canvas.GetX(volumeProfile.StartBar);
    1081.                 var x2 = Canvas.GetX(volumeProfile.EndBar);
    1082.  
    1083.                 var profile = volumeProfile.Cluster;
    1084.  
    1085.                 var maxValues = profile.MaxValues;
    1086.  
    1087.                 var valueArea = ShowValueArea ? profile.GetValueArea(ValueAreaPercent) : null;
    1088.  
    1089.                 var left = x1 - columnWidth2;
    1090.                 var right = x2 + columnWidth2 - 1;
    1091.  
    1092.                 if (prevRight != int.MinValue)
    1093.                 {
    1094.                     left = prevRight;
    1095.                 }
    1096.  
    1097.                 prevRight = (int)right;
    1098.  
    1099.                 var dist = Math.Max(right - left, 1);
    1100.  
    1101.                 var max = ProfileProportion > 0
    1102.                     ? proportion
    1103.                     : Math.Max(Math.Abs(maxValues.MinDelta), Math.Abs(maxValues.MaxDelta));
    1104.  
    1105.                 var volStep = dist / Math.Max(max, 1);
    1106.  
    1107.                 var colorRects = new List<Tuple<Rect, XBrush>>();
    1108.                 var colorRectsLeft = new List<Tuple<Rect, XBrush>>();
    1109.                 var colorRectsRight = new List<Tuple<Rect, XBrush>>();
    1110.                 var valueLeftRects = new List<Tuple<Rect, string>>();
    1111.                 var valueRightRects = new List<Tuple<Rect, string>>();
    1112.  
    1113.                 var center = left + dist / 2.0;
    1114.  
    1115.                 // right part
    1116.  
    1117.                 var prevX = (int)center;
    1118.                 var prevY = (int)GetY((profile.High + .5) * step);
    1119.  
    1120.                 var pointsRight = new List<Point>
    1121.                 {
    1122.                     new Point(prevX, prevY)
    1123.                 };
    1124.  
    1125.                 for (var j = profile.High; j >= profile.Low; j--)
    1126.                 {
    1127.                     var item = profile.GetItem(j) ?? new RawClusterItem(j);
    1128.  
    1129.                     var width = item.Delta > 0 ? Math.Min(volStep * Math.Abs(item.Delta), dist) / 2.0 : 0;
    1130.  
    1131.                     var currX = (int)(center + width);
    1132.                     var currY = (int)GetY((j - .5) * step);
    1133.  
    1134.                     var currHeight = Math.Max(currY - prevY, 1);
    1135.  
    1136.                     if (currY <= prevY && pointsRight.Count > 2)
    1137.                     {
    1138.                         if (currX > prevX)
    1139.                         {
    1140.                             pointsRight[pointsRight.Count - 2] = new Point(currX, pointsRight[pointsRight.Count - 2].Y);
    1141.                             pointsRight[pointsRight.Count - 1] = new Point(currX, pointsRight[pointsRight.Count - 1].Y);
    1142.  
    1143.                             prevX = currX;
    1144.                         }
    1145.                     }
    1146.                     else
    1147.                     {
    1148.                         pointsRight.Add(new Point(currX, prevY));
    1149.                         pointsRight.Add(new Point(currX, currY));
    1150.  
    1151.                         prevX = currX;
    1152.                     }
    1153.  
    1154.                     prevY = currY;
    1155.  
    1156.                     var topY = pointsRight[pointsRight.Count - 2].Y;
    1157.  
    1158.                     if (ShowMaximum && CheckMaximum(item, maxValues))
    1159.                     {
    1160.                         colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, dist, currHeight), _maximumBrush));
    1161.                     }
    1162.                     else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
    1163.                     {
    1164.                         colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, dist, currHeight), _valueAreaBrush));
    1165.                     }
    1166.                     else if (EnableFilter)
    1167.                     {
    1168.                         if (item.Delta > 0 && item.Delta >= minFilter &&
    1169.                             (maxFilter == 0 || item.Delta <= maxFilter))
    1170.                         {
    1171.                             if (colorRectsRight.Count > 0)
    1172.                             {
    1173.                                 var lastRect = colorRectsRight[colorRectsRight.Count - 1].Item1;
    1174.  
    1175.                                 if ((int)lastRect.Y == (int)topY)
    1176.                                 {
    1177.                                     if (width > lastRect.Width)
    1178.                                     {
    1179.                                         colorRectsRight[colorRectsRight.Count - 1] =
    1180.                                             new Tuple<Rect, XBrush>(new Rect(center, topY, width, lastRect.Height), _filterBrush);
    1181.                                     }
    1182.                                 }
    1183.                                 else
    1184.                                 {
    1185.                                     colorRectsRight.Add(new Tuple<Rect, XBrush>(new Rect(center, topY, width, currHeight),
    1186.                                         _filterBrush));
    1187.                                 }
    1188.                             }
    1189.                             else
    1190.                             {
    1191.                                 colorRectsRight.Add(new Tuple<Rect, XBrush>(new Rect(center, topY, width, currHeight), _filterBrush));
    1192.                             }
    1193.                         }
    1194.                     }
    1195.  
    1196.                     if (ShowValues && height > 7 && item.Delta > 0)
    1197.                     {
    1198.                         valueRightRects.Add(new Tuple<Rect, string>(new Rect(center + 2, topY, dist / 2.0, height),
    1199.                             symbol.FormatRawSize(item.Delta, roundValues, MinimizeValues)));
    1200.                     }
    1201.                 }
    1202.  
    1203.                 pointsRight.Add(new Point(center, prevY));
    1204.  
    1205.                 // left part
    1206.  
    1207.                 prevX = (int)center;
    1208.                 prevY = (int)GetY((profile.High + .5) * step);
    1209.  
    1210.                 var pointsLeft = new List<Point>
    1211.                 {
    1212.                     new Point(prevX, prevY)
    1213.                 };
    1214.  
    1215.                 for (var j = profile.High; j >= profile.Low; j--)
    1216.                 {
    1217.                     var item = profile.GetItem(j) ?? new RawClusterItem(j);
    1218.  
    1219.                     var width = item.Delta < 0 ? Math.Min(volStep * Math.Abs(item.Delta), dist) / 2.0 : 0;
    1220.  
    1221.                     var currX = (int)(center - width);
    1222.                     var currY = (int)GetY((j - .5) * step);
    1223.  
    1224.                     var currHeight = Math.Max(currY - prevY, 1);
    1225.  
    1226.                     if (currY <= prevY && pointsLeft.Count > 2)
    1227.                     {
    1228.                         if (currX < prevX)
    1229.                         {
    1230.                             pointsLeft[pointsLeft.Count - 2] = new Point(currX, pointsLeft[pointsLeft.Count - 2].Y);
    1231.                             pointsLeft[pointsLeft.Count - 1] = new Point(currX, pointsLeft[pointsLeft.Count - 1].Y);
    1232.  
    1233.                             prevX = currX;
    1234.                         }
    1235.                     }
    1236.                     else
    1237.                     {
    1238.                         pointsLeft.Add(new Point(currX, prevY));
    1239.                         pointsLeft.Add(new Point(currX, currY));
    1240.  
    1241.                         prevX = currX;
    1242.                     }
    1243.  
    1244.                     prevY = currY;
    1245.  
    1246.                     var topY = pointsLeft[pointsLeft.Count - 2].Y;
    1247.  
    1248.                     if (ShowMaximum && CheckMaximum(item, maxValues))
    1249.                     {
    1250.                     }
    1251.                     else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
    1252.                     {
    1253.                     }
    1254.                     else if (EnableFilter)
    1255.                     {
    1256.                         if (item.Delta < 0 && -item.Delta >= minFilter &&
    1257.                             (maxFilter == 0 || -item.Delta <= maxFilter))
    1258.                         {
    1259.                             if (colorRectsLeft.Count > 0)
    1260.                             {
    1261.                                 var lastRect = colorRectsLeft[colorRectsLeft.Count - 1].Item1;
    1262.  
    1263.                                 if ((int)lastRect.Y == (int)topY)
    1264.                                 {
    1265.                                     if (width > lastRect.Width)
    1266.                                     {
    1267.                                         colorRectsLeft[colorRectsLeft.Count - 1] =
    1268.                                             new Tuple<Rect, XBrush>(
    1269.                                                 new Rect(center - width, topY, width, lastRect.Height),
    1270.                                                 _filterBrush);
    1271.                                     }
    1272.                                 }
    1273.                                 else
    1274.                                 {
    1275.                                     colorRectsLeft.Add(new Tuple<Rect, XBrush>(
    1276.                                         new Rect(center - width, topY, width, currHeight),
    1277.                                         _filterBrush));
    1278.                                 }
    1279.                             }
    1280.                             else
    1281.                             {
    1282.                                 colorRectsLeft.Add(
    1283.                                     new Tuple<Rect, XBrush>(new Rect(center - width, topY, width, currHeight),
    1284.                                         _filterBrush));
    1285.                             }
    1286.                         }
    1287.                     }
    1288.  
    1289.                     if (ShowValues && height > 7 && item.Delta < 0)
    1290.                     {
    1291.                         valueLeftRects.Add(new Tuple<Rect, string>(new Rect(left, topY, dist / 2.0 - 2, height),
    1292.                             symbol.FormatRawSize(item.Delta, roundValues, MinimizeValues)));
    1293.                     }
    1294.                 }
    1295.  
    1296.                 pointsLeft.Add(new Point(center, prevY));
    1297.  
    1298.                 visual.FillRectangle(_backBrush,
    1299.                     new Rect(new Point(left, pointsLeft[0].Y), new Point(right, prevY)));
    1300.  
    1301.                 visual.FillPolygon(_profileBrush, pointsLeft.ToArray());
    1302.                 visual.FillPolygon(_profileBrush, pointsRight.ToArray());
    1303.  
    1304.                 foreach (var colorRect in colorRectsLeft)
    1305.                 {
    1306.                     visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1307.                 }
    1308.  
    1309.                 foreach (var colorRect in colorRectsRight)
    1310.                 {
    1311.                     visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1312.                 }
    1313.  
    1314.                 foreach (var colorRect in colorRects)
    1315.                 {
    1316.                     visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1317.                 }
    1318.  
    1319.                 foreach (var valueRect in valueLeftRects)
    1320.                 {
    1321.                     visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
    1322.                 }
    1323.  
    1324.                 foreach (var valueRect in valueRightRects)
    1325.                 {
    1326.                     visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
    1327.                 }
    1328.             }
    1329.         }
    1330.  
    1331.         private void RenderBidAsk(DxVisualQueue visual)
    1332.         {
    1333.             var startIndex = Canvas.Stop;
    1334.             var endIndex = Canvas.Stop + Canvas.Count;
    1335.  
    1336.             var step = DataProvider.Step;
    1337.             var symbol = DataProvider.Symbol;
    1338.  
    1339.             var minFilter = symbol.CorrectSizeFilter(FilterMin);
    1340.             var maxFilter = symbol.CorrectSizeFilter(FilterMax);
    1341.  
    1342.             var proportion = symbol.CorrectSizeFilter(ProfileProportion);
    1343.  
    1344.             var height = GetY(0.0) - GetY(step);
    1345.  
    1346.             var fontSize = Math.Min(height - 2, 18) * 96 / 72;
    1347.  
    1348.             fontSize = Math.Min(fontSize, Canvas.ChartFont.Size);
    1349.  
    1350.             var normalFont = new XFont(Canvas.ChartFont.Name, fontSize);
    1351.  
    1352.             var columnWidth2 = Canvas.ColumnWidth / 2.0;
    1353.  
    1354.             var roundValues = RoundValues;
    1355.  
    1356.             var prevRight = int.MinValue;
    1357.  
    1358.             foreach (var volumeProfile in Profiles)
    1359.             {
    1360.                 if (volumeProfile.EndBar < startIndex || volumeProfile.StartBar > endIndex)
    1361.                 {
    1362.                     continue;
    1363.                 }
    1364.  
    1365.                 var x1 = Canvas.GetX(volumeProfile.StartBar);
    1366.                 var x2 = Canvas.GetX(volumeProfile.EndBar);
    1367.  
    1368.                 var profile = volumeProfile.Cluster;
    1369.  
    1370.                 var maxValues = profile.MaxValues;
    1371.  
    1372.                 var valueArea = ShowValueArea ? profile.GetValueArea(ValueAreaPercent) : null;
    1373.  
    1374.                 var left = x1 - columnWidth2;
    1375.                 var right = x2 + columnWidth2 - 1;
    1376.  
    1377.                 if (prevRight != int.MinValue)
    1378.                 {
    1379.                     left = prevRight;
    1380.                 }
    1381.  
    1382.                 prevRight = (int)right;
    1383.  
    1384.                 var dist = Math.Max(right - left, 1);
    1385.  
    1386.                 var max = ProfileProportion > 0
    1387.                     ? proportion
    1388.                     : Math.Max(maxValues.MaxBid, maxValues.MaxAsk);
    1389.  
    1390.                 var volStep = dist / Math.Max(max, 1);
    1391.  
    1392.                 var colorRects = new List<Tuple<Rect, XBrush>>();
    1393.                 var colorRectsLeft = new List<Tuple<Rect, XBrush>>();
    1394.                 var colorRectsRight = new List<Tuple<Rect, XBrush>>();
    1395.                 var valueLeftRects = new List<Tuple<Rect, string>>();
    1396.                 var valueRightRects = new List<Tuple<Rect, string>>();
    1397.  
    1398.                 var center = left + dist / 2.0;
    1399.  
    1400.                 // right part - ask
    1401.  
    1402.                 var prevX = (int)center;
    1403.                 var prevY = (int)GetY((profile.High + .5) * step);
    1404.  
    1405.                 var pointsRight = new List<Point>
    1406.                 {
    1407.                     new Point(prevX, prevY)
    1408.                 };
    1409.  
    1410.                 for (var j = profile.High; j >= profile.Low; j--)
    1411.                 {
    1412.                     var item = profile.GetItem(j) ?? new RawClusterItem(j);
    1413.  
    1414.                     var askWidth = item.Ask > 0 ? (int)(Math.Min(volStep * item.Ask, dist) / 2.0) : 0;
    1415.  
    1416.                     var currX = (int)(center + askWidth);
    1417.                     var currY = (int)GetY((j - .5) * step);
    1418.  
    1419.                     var currHeight = Math.Max(currY - prevY, 1);
    1420.  
    1421.                     if (currY <= prevY && pointsRight.Count > 2)
    1422.                     {
    1423.                         if (currX > prevX)
    1424.                         {
    1425.                             pointsRight[pointsRight.Count - 2] = new Point(currX, pointsRight[pointsRight.Count - 2].Y);
    1426.                             pointsRight[pointsRight.Count - 1] = new Point(currX, pointsRight[pointsRight.Count - 1].Y);
    1427.  
    1428.                             prevX = currX;
    1429.                         }
    1430.                     }
    1431.                     else
    1432.                     {
    1433.                         pointsRight.Add(new Point(currX, prevY));
    1434.                         pointsRight.Add(new Point(currX, currY));
    1435.  
    1436.                         prevX = currX;
    1437.                     }
    1438.  
    1439.                     prevY = currY;
    1440.  
    1441.                     var topY = pointsRight[pointsRight.Count - 2].Y;
    1442.  
    1443.                     if (ShowMaximum && CheckMaximum(item, maxValues))
    1444.                     {
    1445.                         colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, dist, currHeight), _maximumBrush));
    1446.                     }
    1447.                     else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
    1448.                     {
    1449.                         colorRects.Add(new Tuple<Rect, XBrush>(new Rect(left, topY, dist, currHeight),
    1450.                             _valueAreaBrush));
    1451.                     }
    1452.                     else if (EnableFilter)
    1453.                     {
    1454.                         if (item.Ask >= minFilter && (maxFilter == 0 || item.Ask <= maxFilter))
    1455.                         {
    1456.                             if (colorRectsRight.Count > 0)
    1457.                             {
    1458.                                 var lastRect = colorRectsRight[colorRectsRight.Count - 1].Item1;
    1459.  
    1460.                                 if ((int)lastRect.Y == (int)topY)
    1461.                                 {
    1462.                                     if (askWidth > lastRect.Width)
    1463.                                     {
    1464.                                         colorRectsRight[colorRectsRight.Count - 1] =
    1465.                                             new Tuple<Rect, XBrush>(new Rect(center, topY, askWidth, lastRect.Height),
    1466.                                                 _filterBrush);
    1467.                                     }
    1468.                                 }
    1469.                                 else
    1470.                                 {
    1471.                                     colorRectsRight.Add(
    1472.                                         new Tuple<Rect, XBrush>(new Rect(center, topY, askWidth, currHeight),
    1473.                                             _filterBrush));
    1474.                                 }
    1475.                             }
    1476.                             else
    1477.                             {
    1478.                                 colorRectsRight.Add(new Tuple<Rect, XBrush>(
    1479.                                     new Rect(center, topY, askWidth, currHeight),
    1480.                                     _filterBrush));
    1481.                             }
    1482.                         }
    1483.                     }
    1484.  
    1485.                     if (ShowValues && height > 7 && item.Ask > 0)
    1486.                     {
    1487.                         valueRightRects.Add(new Tuple<Rect, string>(new Rect(center + 2, topY, dist / 2.0, height),
    1488.                             symbol.FormatRawSize(item.Ask, roundValues, MinimizeValues)));
    1489.                     }
    1490.                 }
    1491.  
    1492.                 pointsRight.Add(new Point(center, prevY));
    1493.  
    1494.                 // left part - bid
    1495.  
    1496.                 prevX = (int)center;
    1497.                 prevY = (int)GetY((profile.High + .5) * step);
    1498.  
    1499.                 var pointsLeft = new List<Point>
    1500.                 {
    1501.                     new Point(prevX, prevY)
    1502.                 };
    1503.  
    1504.                 for (var j = profile.High; j >= profile.Low; j--)
    1505.                 {
    1506.                     var item = profile.GetItem(j) ?? new RawClusterItem(j);
    1507.  
    1508.                     var bidWidth = (int)(Math.Min(volStep * item.Bid, dist) / 2.0);
    1509.  
    1510.                     var currX = (int)(center - bidWidth);
    1511.                     var currY = (int)GetY((j - .5) * step);
    1512.  
    1513.                     var currHeight = Math.Max(currY - prevY, 1);
    1514.  
    1515.                     if (currY <= prevY && pointsLeft.Count > 2)
    1516.                     {
    1517.                         if (currX < prevX)
    1518.                         {
    1519.                             pointsLeft[pointsLeft.Count - 2] = new Point(currX, pointsLeft[pointsLeft.Count - 2].Y);
    1520.                             pointsLeft[pointsLeft.Count - 1] = new Point(currX, pointsLeft[pointsLeft.Count - 1].Y);
    1521.  
    1522.                             prevX = currX;
    1523.                         }
    1524.                     }
    1525.                     else
    1526.                     {
    1527.                         pointsLeft.Add(new Point(currX, prevY));
    1528.                         pointsLeft.Add(new Point(currX, currY));
    1529.  
    1530.                         prevX = currX;
    1531.                     }
    1532.  
    1533.                     prevY = currY;
    1534.  
    1535.                     var topY = pointsLeft[pointsLeft.Count - 2].Y;
    1536.  
    1537.                     if (ShowMaximum && CheckMaximum(item, maxValues))
    1538.                     {
    1539.                     }
    1540.                     else if (valueArea != null && (item.Price == valueArea.Vah || item.Price == valueArea.Val))
    1541.                     {
    1542.                     }
    1543.                     else if (EnableFilter)
    1544.                     {
    1545.                         if (item.Bid >= minFilter && (maxFilter == 0 || item.Bid <= maxFilter))
    1546.                         {
    1547.                             if (colorRectsLeft.Count > 0)
    1548.                             {
    1549.                                 var lastRect = colorRectsLeft[colorRectsLeft.Count - 1].Item1;
    1550.  
    1551.                                 if ((int)lastRect.Y == (int)topY)
    1552.                                 {
    1553.                                     if (bidWidth > lastRect.Width)
    1554.                                     {
    1555.                                         colorRectsLeft[colorRectsLeft.Count - 1] =
    1556.                                             new Tuple<Rect, XBrush>(
    1557.                                                 new Rect(center - bidWidth, topY, bidWidth, lastRect.Height),
    1558.                                                 _filterBrush);
    1559.                                     }
    1560.                                 }
    1561.                                 else
    1562.                                 {
    1563.                                     colorRectsLeft.Add(new Tuple<Rect, XBrush>(
    1564.                                         new Rect(center - bidWidth, topY, bidWidth, currHeight), _filterBrush));
    1565.                                 }
    1566.                             }
    1567.                             else
    1568.                             {
    1569.                                 colorRectsLeft.Add(
    1570.                                     new Tuple<Rect, XBrush>(new Rect(center - bidWidth, topY, bidWidth, currHeight),
    1571.                                         _filterBrush));
    1572.                             }
    1573.                         }
    1574.                     }
    1575.  
    1576.                     if (ShowValues && height > 7 && item.Bid > 0)
    1577.                     {
    1578.                         valueLeftRects.Add(new Tuple<Rect, string>(new Rect(left, topY, dist / 2.0 - 2, height),
    1579.                             symbol.FormatRawSize(item.Bid, roundValues, MinimizeValues)));
    1580.                     }
    1581.                 }
    1582.  
    1583.                 pointsLeft.Add(new Point(center, prevY));
    1584.  
    1585.                 visual.FillRectangle(_backBrush,
    1586.                     new Rect(new Point(left, pointsLeft[0].Y), new Point(right, prevY)));
    1587.  
    1588.                 visual.FillPolygon(_profileBrush, pointsLeft.ToArray());
    1589.                 visual.FillPolygon(_profileBrush, pointsRight.ToArray());
    1590.  
    1591.                 foreach (var colorRect in colorRectsLeft)
    1592.                 {
    1593.                     visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1594.                 }
    1595.  
    1596.                 foreach (var colorRect in colorRectsRight)
    1597.                 {
    1598.                     visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1599.                 }
    1600.  
    1601.                 foreach (var colorRect in colorRects)
    1602.                 {
    1603.                     visual.FillRectangle(colorRect.Item2, colorRect.Item1);
    1604.                 }
    1605.  
    1606.                 foreach (var valueRect in valueLeftRects)
    1607.                 {
    1608.                     visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1, XTextAlignment.Right);
    1609.                 }
    1610.  
    1611.                 foreach (var valueRect in valueRightRects)
    1612.                 {
    1613.                     visual.DrawString(valueRect.Item2, normalFont, _valuesBrush, valueRect.Item1);
    1614.                 }
    1615.             }
    1616.         }
    1617.  
    1618.         private bool CheckMaximum(IRawClusterItem item, IRawClusterMaxValues maxValues)
    1619.         {
    1620.             switch (MaximumType)
    1621.             {
    1622.                 case VolumeProfilesMaximumType.Volume:
    1623.  
    1624.                     return item.Volume == maxValues.MaxVolume;
    1625.  
    1626.                 case VolumeProfilesMaximumType.Trades:
    1627.  
    1628.                     return item.Trades == maxValues.MaxTrades;
    1629.  
    1630.                 case VolumeProfilesMaximumType.Delta:
    1631.  
    1632.                     return Math.Abs(item.Delta) ==
    1633.                                      Math.Max(Math.Abs(maxValues.MaxDelta), Math.Abs(maxValues.MinDelta));
    1634.  
    1635.                 case VolumeProfilesMaximumType.DeltaPlus:
    1636.  
    1637.                     return item.Delta > 0 && item.Delta == maxValues.MaxDelta;
    1638.  
    1639.                 case VolumeProfilesMaximumType.DeltaMinus:
    1640.  
    1641.                     return item.Delta < 0 && item.Delta == maxValues.MinDelta;
    1642.  
    1643.                 case VolumeProfilesMaximumType.Bid:
    1644.  
    1645.                     return item.Bid == maxValues.MaxBid;
    1646.  
    1647.                 case VolumeProfilesMaximumType.Ask:
    1648.  
    1649.                     return item.Ask == maxValues.MaxAsk;
    1650.             }
    1651.  
    1652.             return false;
    1653.         }
    1654.  
    1655.         public override void CopyTemplate(IndicatorBase indicator, bool style)
    1656.         {
    1657.             var i = (VolumeProfilesIndicator)indicator;
    1658.  
    1659.             PeriodType = i.PeriodType;
    1660.             PeriodValue = i.PeriodValue;
    1661.  
    1662.             ProfileType = i.ProfileType;
    1663.             ProfileProportion = i.ProfileProportion;
    1664.             ProfileColor = i.ProfileColor;
    1665.             ProfileBackColor = i.ProfileBackColor;
    1666.  
    1667.             ShowValues = i.ShowValues;
    1668.             MinimizeValues = i.MinimizeValues;
    1669.             ValuesColor = i.ValuesColor;
    1670.  
    1671.             RoundValuesParam.Copy(i.RoundValuesParam);
    1672.  
    1673.             MaximumType = i.MaximumType;
    1674.             ShowMaximum = i.ShowMaximum;
    1675.             MaximumColor = i.MaximumColor;
    1676.  
    1677.             ShowValueArea = i.ShowValueArea;
    1678.             ValueAreaPercent = i.ValueAreaPercent;
    1679.             ValueAreaColor = i.ValueAreaColor;
    1680.  
    1681.             EnableFilter = i.EnableFilter;
    1682.             FilterMin = i.FilterMin;
    1683.             FilterMax = i.FilterMax;
    1684.             FilterColor = i.FilterColor;
    1685.  
    1686.             base.CopyTemplate(indicator, style);
    1687.         }
    1688.  
    1689.         private class VolumeProfile
    1690.         {
    1691.             public readonly int StartBar;
    1692.             public int EndBar;
    1693.             public readonly RawCluster Cluster;
    1694.             public bool Completed;
    1695.  
    1696.             public VolumeProfile(RawCluster cluster, int startBar)
    1697.             {
    1698.                 Cluster = cluster;
    1699.                 StartBar = startBar;
    1700.             }
    1701.         }
    1702.     }
    1703. }
     
    #1 Support, 26 июл 2019
    Последнее редактирование: 26 июл 2019