TradesFlow

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

  1. Support

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

    Регистрация:
    5 сен 2015
    Сообщения:
    1 084
    Симпатии:
    219
    Код индикатора TradesFlow
    1. //------------------------------------------------------------------------------
    2. //
    3. // Индикатор TradesFlow. Copyright (c) 2019 Ilya Smirnov. All rights reserved.
    4. //
    5. //------------------------------------------------------------------------------
    6.  
    7. using System;
    8. using System.Collections.Generic;
    9. using System.ComponentModel;
    10. using System.Linq;
    11. using System.Runtime.Serialization;
    12. using System.Windows;
    13. using System.Windows.Media;
    14. using TigerTrade.Chart.Alerts;
    15. using TigerTrade.Chart.Base;
    16. using TigerTrade.Chart.Data;
    17. using TigerTrade.Chart.Indicators.Common;
    18. using TigerTrade.Chart.Indicators.Enums;
    19. using TigerTrade.Dx;
    20. using TigerTrade.Dx.Enums;
    21.  
    22. namespace TigerTrade.Chart.Indicators.Custom
    23. {
    24.     [DataContract(Name = "TradesFlowIndicator", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")]
    25.     [Indicator("X_TradesFlow", "*TradesFlow", true, Type = typeof(TradesFlowIndicator))]
    26.     internal sealed class TradesFlowIndicator : IndicatorBase
    27.     {
    28.         internal sealed class TradesFlowItem
    29.         {
    30.             public DateTime Time { get; set; }
    31.             public decimal Price { get; set; }
    32.             public decimal Price2 { get; set; }
    33.             public decimal Size { get; set; }
    34.             public bool IsBuy { get; set; }
    35.  
    36.             public bool Added { get; set; }
    37.             public bool Alert { get; set; }
    38.  
    39.             public TradesFlowItem(IChartTick trade)
    40.             {
    41.                 Time = trade.Time;
    42.                 Price = trade.Price;
    43.                 Size = trade.Size;
    44.                 IsBuy = trade.IsBuy;
    45.             }
    46.         }
    47.  
    48.         internal sealed class TradesFlowList
    49.         {
    50.             private readonly LinkedList<TradesFlowItem> _ticks = new LinkedList<TradesFlowItem>();
    51.  
    52.             public TradesFlowItem Last { get; private set; }
    53.  
    54.             private bool _aggregate;
    55.             private decimal _min;
    56.  
    57.             public void Add(IChartTick tick, bool aggregate, decimal min)
    58.             {
    59.                 if (_aggregate != aggregate || _min != min)
    60.                 {
    61.                     _aggregate = aggregate;
    62.                     _min = min;
    63.  
    64.                     Last = null;
    65.  
    66.                     _ticks.Clear();
    67.                 }
    68.  
    69.                 if (Last == null)
    70.                 {
    71.                     Last = new TradesFlowItem(tick);
    72.                 }
    73.  
    74.                 if (aggregate && Last.Time == tick.Time && Last.IsBuy == tick.IsBuy)
    75.                 {
    76.                     Last.Size += tick.Size;
    77.                     Last.Price2 = tick.Price;
    78.                 }
    79.                 else
    80.                 {
    81.                     if (Last.Size >= min)
    82.                     {
    83.                         if (!Last.Added)
    84.                         {
    85.                             _ticks.AddFirst(Last);
    86.                         }
    87.                     }
    88.  
    89.                     Last = new TradesFlowItem(tick);
    90.                 }
    91.  
    92.                 if (Last != null && Last.Size >= min && !Last.Added)
    93.                 {
    94.                     Last.Added = true;
    95.  
    96.                     _ticks.AddFirst(Last);
    97.                 }
    98.  
    99.                 if (_ticks.Count > 500)
    100.                 {
    101.                     while (_ticks.Count >= 300)
    102.                     {
    103.                         _ticks.RemoveLast();
    104.                     }
    105.                 }
    106.             }
    107.  
    108.             public void Clear()
    109.             {
    110.                 Last = null;
    111.  
    112.                 _ticks.Clear();
    113.             }
    114.  
    115.             public LinkedList<TradesFlowItem> GetTicks()
    116.             {
    117.                 return _ticks;
    118.             }
    119.         }
    120.  
    121.         internal sealed class TickData
    122.         {
    123.             public decimal Size { get; set; }
    124.             public bool IsBuy { get; set; }
    125.             public bool DrawSize { get; set; }
    126.             public bool DrawRect { get; set; }
    127.  
    128.             public double Radius { get; set; }
    129.             public Point Center { get; set; }
    130.             public Rect Rect { get; set; }
    131.         }
    132.  
    133.         private IndicatorDecimalParam _tradesFilterParam;
    134.  
    135.         [DataMember(Name = "TradesFilterParam")]
    136.         public IndicatorDecimalParam TradesFilterParam
    137.         {
    138.             get => _tradesFilterParam ?? (_tradesFilterParam = new IndicatorDecimalParam(0));
    139.             set => _tradesFilterParam = value;
    140.         }
    141.  
    142.         [DefaultValue(null)]
    143.         [Category("Параметры"), DisplayName("Фильтр сделок")]
    144.         public decimal TradesFilter
    145.         {
    146.             get => TradesFilterParam.Get(SettingsShortKey);
    147.             set
    148.             {
    149.                 if (!TradesFilterParam.Set(SettingsShortKey, value, 0))
    150.                 {
    151.                     return;
    152.                 }
    153.  
    154.                 OnPropertyChanged();
    155.  
    156.                 _tradesFlow?.Clear();
    157.             }
    158.         }
    159.  
    160.         private IndicatorDecimalParam _valuesFilterParam;
    161.  
    162.         [DataMember(Name = "ValuesFilterParam")]
    163.         public IndicatorDecimalParam ValuesFilterParam
    164.         {
    165.             get => _valuesFilterParam ?? (_valuesFilterParam = new IndicatorDecimalParam(5));
    166.             set => _valuesFilterParam = value;
    167.         }
    168.  
    169.         [DefaultValue(5)]
    170.         [Category("Параметры"), DisplayName("Фильтр значений")]
    171.         public decimal ValuesFilter
    172.         {
    173.             get => ValuesFilterParam.Get(SettingsShortKey);
    174.             set
    175.             {
    176.                 if (!ValuesFilterParam.Set(SettingsShortKey, value, 0))
    177.                 {
    178.                     return;
    179.                 }
    180.  
    181.                 OnPropertyChanged();
    182.             }
    183.         }
    184.  
    185.         private bool _minimizeValues;
    186.  
    187.         [DataMember(Name = "MinimizeValues")]
    188.         [Category("Параметры"), DisplayName("Минимизировать значения")]
    189.         public bool MinimizeValues
    190.         {
    191.             get => _minimizeValues;
    192.             set
    193.             {
    194.                 if (value == _minimizeValues)
    195.                 {
    196.                     return;
    197.                 }
    198.  
    199.                 _minimizeValues = value;
    200.  
    201.                 OnPropertyChanged();
    202.             }
    203.         }
    204.  
    205.         private IndicatorIntParam _roundValueParam;
    206.  
    207.         [DataMember(Name = "RoundValueParam")]
    208.         public IndicatorIntParam RoundValuesParam
    209.         {
    210.             get => _roundValueParam ?? (_roundValueParam = new IndicatorIntParam(0));
    211.             set => _roundValueParam = value;
    212.         }
    213.  
    214.         [DefaultValue(0)]
    215.         [Category("Параметры"), DisplayName("Округлять значения")]
    216.         public int RoundValues
    217.         {
    218.             get => RoundValuesParam.Get(SettingsLongKey);
    219.             set
    220.             {
    221.                 if (!RoundValuesParam.Set(SettingsLongKey, value, -4, 4))
    222.                 {
    223.                     return;
    224.                 }
    225.  
    226.                 OnPropertyChanged();
    227.             }
    228.         }
    229.  
    230.         private bool _сompactMode;
    231.  
    232.         [DataMember(Name = "CompactMode"), DefaultValue(false)]
    233.         [Category("Параметры"), DisplayName("Компактный режим")]
    234.         public bool CompactMode
    235.         {
    236.             get => _сompactMode;
    237.             set
    238.             {
    239.                 if (value == _сompactMode)
    240.                 {
    241.                     return;
    242.                 }
    243.  
    244.                 _сompactMode = value;
    245.  
    246.                 OnPropertyChanged();
    247.             }
    248.         }
    249.  
    250.         private bool _aggregateTicks;
    251.  
    252.         [DataMember(Name = "AggregateTicks"), DefaultValue(false)]
    253.         [Category("Параметры"), DisplayName("Агрегировать сделки")]
    254.         public bool AggregateTicks
    255.         {
    256.             get => _aggregateTicks;
    257.             set
    258.             {
    259.                 if (value == _aggregateTicks)
    260.                 {
    261.                     return;
    262.                 }
    263.  
    264.                 _aggregateTicks = value;
    265.  
    266.                 OnPropertyChanged();
    267.  
    268.                 _tradesFlow?.Clear();
    269.             }
    270.         }
    271.  
    272.         private int _width;
    273.  
    274.         [DataMember(Name = "Width"), DefaultValue(30)]
    275.         [Category("Параметры"), DisplayName("Ширина (%)")]
    276.         public int Width
    277.         {
    278.             get => _width;
    279.             set
    280.             {
    281.                 value = Math.Max(10, Math.Min(100, value));
    282.  
    283.                 if (value == _width)
    284.                 {
    285.                     return;
    286.                 }
    287.  
    288.                 _width = value;
    289.  
    290.                 OnPropertyChanged();
    291.             }
    292.         }
    293.  
    294.         private int _offset;
    295.  
    296.         [DataMember(Name = "Offset"), DefaultValue(0)]
    297.         [Category("Параметры"), DisplayName("Отступ справа")]
    298.         public int Offset
    299.         {
    300.             get => _offset;
    301.             set
    302.             {
    303.                 value = Math.Max(0, value);
    304.  
    305.                 if (value == _offset)
    306.                 {
    307.                     return;
    308.                 }
    309.  
    310.                 _offset = value;
    311.  
    312.                 OnPropertyChanged();
    313.             }
    314.         }
    315.  
    316.         private ChartAlertSettings _alert;
    317.  
    318.         [DataMember(Name = "Alert"), Browsable(true)]
    319.         [Category("Параметры"), DisplayName("Оповещение")]
    320.         public ChartAlertSettings Alert
    321.         {
    322.             get => _alert ?? (_alert = new ChartAlertSettings());
    323.             set
    324.             {
    325.                 if (Equals(value, _alert))
    326.                 {
    327.                     return;
    328.                 }
    329.  
    330.                 _alert = value;
    331.  
    332.                 OnPropertyChanged();
    333.             }
    334.         }
    335.  
    336.         private IndicatorIntParam _signalFilterParam;
    337.  
    338.         [DataMember(Name = "SignalFilterParam")]
    339.         public IndicatorIntParam SignalFilterParam
    340.         {
    341.             get => _signalFilterParam ?? (_signalFilterParam = new IndicatorIntParam(100));
    342.             set => _signalFilterParam = value;
    343.         }
    344.  
    345.         [DefaultValue(100)]
    346.         [Category("Сигнал"), DisplayName("Фильтр")]
    347.         public int SignalFilter
    348.         {
    349.             get => SignalFilterParam.Get(SettingsShortKey);
    350.             set
    351.             {
    352.                 if (!SignalFilterParam.Set(SettingsShortKey, value, 0))
    353.                 {
    354.                     return;
    355.                 }
    356.  
    357.                 OnPropertyChanged();
    358.             }
    359.         }
    360.  
    361.         [Browsable(false)]
    362.         public XBrush TickBuyBackBrush { get; private set; }
    363.  
    364.         [Browsable(false)]
    365.         public XBrush TickBuyBorderBrush { get; private set; }
    366.  
    367.         [Browsable(false)]
    368.         public XPen TickBuyBorderPen { get; private set; }
    369.  
    370.         private XColor _tickBuyBorderColor;
    371.  
    372.         [DataMember(Name = "TickBuyBorderColor")]
    373.         [Category("Стиль"), DisplayName("Цвет покупок")]
    374.         public XColor TickBuyColor
    375.         {
    376.             get => _tickBuyBorderColor;
    377.             set
    378.             {
    379.                 if (_tickBuyBorderColor == value)
    380.                 {
    381.                     return;
    382.                 }
    383.  
    384.                 _tickBuyBorderColor = value;
    385.  
    386.                 TickBuyBackBrush = new XBrush(value);
    387.                 TickBuyBorderBrush = new XBrush(new XColor(255, value));
    388.  
    389.                 TickBuyBorderPen = new XPen(TickBuyBorderBrush, 1);
    390.  
    391.                 OnPropertyChanged();
    392.             }
    393.         }
    394.  
    395.         [Browsable(false)]
    396.         public XBrush TickSellBackBrush { get; private set; }
    397.  
    398.         [Browsable(false)]
    399.         public XBrush TickSellBorderBrush { get; private set; }
    400.  
    401.         [Browsable(false)]
    402.         public XPen TickSellBorderPen { get; private set; }
    403.  
    404.         private XColor _tickSellBorderColor;
    405.  
    406.         [DataMember(Name = "TickSellBorderColor")]
    407.         [Category("Стиль"), DisplayName("Цвет продаж")]
    408.         public XColor TickSellColor
    409.         {
    410.             get => _tickSellBorderColor;
    411.             set
    412.             {
    413.                 if (_tickSellBorderColor == value)
    414.                 {
    415.                     return;
    416.                 }
    417.  
    418.                 _tickSellBorderColor = value;
    419.  
    420.                 TickSellBackBrush = new XBrush(value);
    421.                 TickSellBorderBrush = new XBrush(new XColor(255, value));
    422.  
    423.                 TickSellBorderPen = new XPen(TickSellBorderBrush, 1);
    424.  
    425.                 OnPropertyChanged();
    426.             }
    427.         }
    428.  
    429.         [Browsable(false)]
    430.         public XBrush TicksLineBrush { get; private set; }
    431.  
    432.         private XColor _ticksLineColor;
    433.  
    434.         [DataMember(Name = "TicksLineColor")]
    435.         [Category("Стиль"), DisplayName("Цвет линии")]
    436.         public XColor TicksLineColor
    437.         {
    438.             get => _ticksLineColor;
    439.             set
    440.             {
    441.                 if (_ticksLineColor == value)
    442.                 {
    443.                     return;
    444.                 }
    445.  
    446.                 _ticksLineColor = value;
    447.  
    448.                 TicksLineBrush = new XBrush(value);
    449.  
    450.                 OnPropertyChanged();
    451.             }
    452.         }
    453.  
    454.         private int _ticksLineWidth;
    455.  
    456.         [DataMember(Name = "TicksLineWidth"), DefaultValue(1)]
    457.         [Category("Стиль"), DisplayName("Толщина линии")]
    458.         public int TicksLineWidth
    459.         {
    460.             get => _ticksLineWidth;
    461.             set
    462.             {
    463.                 value = Math.Max(0, Math.Min(10, value));
    464.  
    465.                 if (value == _ticksLineWidth)
    466.                 {
    467.                     return;
    468.                 }
    469.  
    470.                 _ticksLineWidth = value;
    471.  
    472.                 OnPropertyChanged();
    473.             }
    474.         }
    475.  
    476.         [Browsable(false)]
    477.         public override bool ShowIndicatorValues => false;
    478.  
    479.         [Browsable(false)]
    480.         public override bool ShowIndicatorLabels => false;
    481.  
    482.         [Browsable(false)]
    483.         public override IndicatorCalculation Calculation => IndicatorCalculation.OnEachTick;
    484.  
    485.         private TradesFlowList _tradesFlow;
    486.      
    487.         public TradesFlowIndicator()
    488.         {
    489.             ShowIndicatorTitle = false;
    490.  
    491.             CompactMode = false;
    492.             AggregateTicks = false;
    493.  
    494.             MinimizeValues = false;
    495.  
    496.             Width = 30;
    497.             Offset = 0;
    498.  
    499.             TickBuyColor = Color.FromArgb(127, 70, 130, 180);
    500.             TickSellColor = Color.FromArgb(127, 178, 34, 34);
    501.             TicksLineColor = Color.FromArgb(255, 255, 255, 255);
    502.             TicksLineWidth = 1;
    503.         }
    504.  
    505.         protected override void Execute()
    506.         {
    507.             if (_tradesFlow == null)
    508.             {
    509.                 _tradesFlow = new TradesFlowList();
    510.             }
    511.  
    512.             if (ClearData)
    513.             {
    514.                 _tradesFlow.Clear();
    515.             }
    516.  
    517.             var ticks = DataProvider.GetTicks();
    518.  
    519.             var tradesFilter = TradesFilter;
    520.             var signalFilter = SignalFilter;
    521.  
    522.             foreach (var tick in ticks)
    523.             {
    524.                 _tradesFlow.Add(tick, AggregateTicks, tradesFilter);
    525.  
    526.                 var last = _tradesFlow.Last;
    527.  
    528.                 if (!Alert.IsActive || last.Size < signalFilter || last.Alert)
    529.                 {
    530.                     continue;
    531.                 }
    532.  
    533.                 last.Alert = true;
    534.  
    535.                 var p = DataProvider.Symbol.FormatPrice(last.Price);
    536.  
    537.                 AddAlert(Alert, $"TradesFlow: {(last.IsBuy ? "Buy" : "Sell")} {p} x {last.Size}.");
    538.             }
    539.         }
    540.  
    541.         public override void Render(DxVisualQueue visual)
    542.         {
    543.             if (_tradesFlow == null)
    544.             {
    545.                 return;
    546.             }
    547.  
    548.             var ticksList = _tradesFlow.GetTicks();
    549.  
    550.             if (ticksList.Count == 0)
    551.             {
    552.                 return;
    553.             }
    554.  
    555.             var width = Canvas.Rect.Width / 100.0 * Width;
    556.  
    557.             if (width < 20)
    558.             {
    559.                 return;
    560.             }
    561.  
    562.             var start = Canvas.Rect.Right - Offset - 5;
    563.  
    564.             if (start < 20)
    565.             {
    566.                 return;
    567.             }
    568.  
    569.             var x = start;
    570.             var i = 0;
    571.  
    572.             var tradesListData = new LinkedList<TickData>();
    573.             var tradePoints = new Point[ticksList.Count];
    574.  
    575.             var symbol = DataProvider.Symbol;
    576.  
    577.             var valuesFilter = ValuesFilter;
    578.             var roundValues = RoundValues;
    579.             var minimizeValues = MinimizeValues;
    580.  
    581.             foreach (var tick in ticksList)
    582.             {
    583.                 if (x < start - width)
    584.                 {
    585.                     continue;
    586.                 }
    587.  
    588.                 var radius = 3.0;
    589.                 var drawVolume = false;
    590.  
    591.                 if (tick.Size >= valuesFilter)
    592.                 {
    593.                     var textSize = Canvas.ChartFont.GetSize(symbol.FormatSize(tick.Size, roundValues, minimizeValues));
    594.  
    595.                     if (textSize.Width > textSize.Height)
    596.                     {
    597.                         radius = textSize.Width / 2.0;
    598.                     }
    599.                     else
    600.                     {
    601.                         radius = textSize.Height / 2.0;
    602.                     }
    603.  
    604.                     radius += 4;
    605.  
    606.                     drawVolume = true;
    607.                 }
    608.  
    609.                 radius += TicksLineWidth / 2.0;
    610.  
    611.                 if (x - 2 * radius - 4 < start - width)
    612.                 {
    613.                     x -= radius;
    614.  
    615.                     continue;
    616.                 }
    617.  
    618.                 var moveSize = tick.Size >= valuesFilter
    619.                     ? radius + 1
    620.                     : 1;
    621.  
    622.                 x -= moveSize + 1;
    623.  
    624.                 var y = GetY(Canvas.IsStock ? (double)tick.Price : 0.5);
    625.  
    626.                 var tradeDrawData = new TickData
    627.                 {
    628.                     Size = tick.Size,
    629.                     IsBuy = tick.IsBuy,
    630.                     DrawSize = drawVolume,
    631.  
    632.                     Radius = radius,
    633.                     Center = new Point(x, y),
    634.                     Rect = new Rect(x - radius, y - radius, radius * 2, radius * 2),
    635.                 };
    636.  
    637.                 if (tick.Price2 > 0)
    638.                 {
    639.                     var top = GetY(Canvas.IsStock ? (double)Math.Max(tick.Price, tick.Price2) : 0.5) - 10;
    640.                     var bottom = GetY(Canvas.IsStock ? (double)Math.Min(tick.Price, tick.Price2) : 0.5) + 10;
    641.  
    642.                     tradeDrawData.Rect = new Rect(x - radius, top, radius * 2, bottom - top);
    643.  
    644.                     tradeDrawData.DrawRect = true;
    645.                 }
    646.  
    647.                 tradesListData.AddFirst(tradeDrawData);
    648.  
    649.                 tradePoints[i++] = new Point(x, y);
    650.  
    651.                 if (!CompactMode)
    652.                 {
    653.                     x -= moveSize + TicksLineWidth / 2.0 + 1;
    654.                 }
    655.             }
    656.  
    657.             if (TicksLineWidth > 0 && i > 1)
    658.             {
    659.                 visual.DrawLines(new XPen(TicksLineBrush, TicksLineWidth), tradePoints.Take(i).ToArray());
    660.             }
    661.  
    662.             foreach (var trade in tradesListData)
    663.             {
    664.                 if (!trade.DrawRect)
    665.                 {
    666.                     visual.FillEllipse(Canvas.Theme.ChartBackBrush, trade.Center, trade.Radius, trade.Radius);
    667.  
    668.                     visual.FillEllipse(
    669.                         trade.IsBuy
    670.                             ? TickBuyBackBrush
    671.                             : TickSellBackBrush, trade.Center,
    672.                         trade.Radius, trade.Radius);
    673.  
    674.                     visual.DrawEllipse(trade.IsBuy
    675.                             ? TickBuyBorderPen
    676.                             : TickSellBorderPen,
    677.                         trade.Center, trade.Radius, trade.Radius
    678.                     );
    679.                 }
    680.                 else
    681.                 {
    682.                     visual.FillRectangle(Canvas.Theme.ChartBackBrush, trade.Rect);
    683.                     visual.FillRectangle(trade.IsBuy ? TickBuyBackBrush : TickSellBackBrush, trade.Rect);
    684.                     visual.DrawRectangle(trade.IsBuy ? TickBuyBorderPen : TickSellBorderPen, trade.Rect);
    685.                 }
    686.  
    687.                 if (trade.DrawSize)
    688.                 {
    689.                     visual.DrawString(symbol.FormatSize(trade.Size, roundValues, minimizeValues), Canvas.ChartFont,
    690.                         Canvas.Theme.ChartFontBrush, trade.Rect, XTextAlignment.Center);
    691.                 }
    692.             }
    693.         }
    694.  
    695.         public override void ApplyColors(IChartTheme theme)
    696.         {
    697.             TickBuyColor = new XColor(127, theme.PaletteColor6);
    698.             TickSellColor = new XColor(127, theme.PaletteColor7);
    699.  
    700.             base.ApplyColors(theme);
    701.         }
    702.  
    703.         public override void CopyTemplate(IndicatorBase indicator, bool style)
    704.         {
    705.             var i = (TradesFlowIndicator)indicator;
    706.  
    707.             CompactMode = i.CompactMode;
    708.             AggregateTicks = i.AggregateTicks;
    709.  
    710.             Alert.Copy(i.Alert, !style);
    711.  
    712.             OnPropertyChanged(nameof(Alert));
    713.  
    714.             TradesFilterParam.Copy(i.TradesFilterParam);
    715.             ValuesFilterParam.Copy(i.ValuesFilterParam);
    716.             RoundValuesParam.Copy(i.RoundValuesParam);
    717.             SignalFilterParam.Copy(i.SignalFilterParam);
    718.  
    719.             Width = i.Width;
    720.             Offset = i.Offset;
    721.  
    722.             TickBuyColor = i.TickBuyColor;
    723.             TickSellColor = i.TickSellColor;
    724.             TicksLineColor = i.TicksLineColor;
    725.             TicksLineWidth = i.TicksLineWidth;
    726.  
    727.             OnPropertyChanged(nameof(TradesFilter));
    728.             OnPropertyChanged(nameof(ValuesFilter));
    729.             OnPropertyChanged(nameof(SignalFilter));
    730.  
    731.             base.CopyTemplate(indicator, style);
    732.         }
    733.     }
    734. }
     
    #1 Support, 26 июл 2019
    Последнее редактирование: 26 июл 2019