Depth Of Market indicator Code
//------------------------------------------------------------------------------ // // DepthOfMarket. Copyright (c) 2019 Ilya Smirnov. All rights reserved. // //------------------------------------------------------------------------------ using System; using System.ComponentModel; using System.Runtime.Serialization; using System.Windows; using System.Windows.Media; using TigerTrade.Chart.Base; using TigerTrade.Chart.Indicators.Common; using TigerTrade.Chart.Indicators.Enums; using TigerTrade.Core.UI.Converters; using TigerTrade.Dx; using TigerTrade.Dx.Enums; namespace TigerTrade.Chart.Indicators.Custom { [TypeConverter(typeof(EnumDescriptionTypeConverter))] [DataContract(Name = "DepthOfMarketScaleAlignment", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")] public enum DepthOfMarketScaleAlignment { [EnumMember(Value = "Left"), Description("Слева")] Left, [EnumMember(Value = "Right"), Description("Справа")] Right } [DataContract(Name = "DepthOfMarketIndicator", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Indicators.Custom")] [Indicator("X_DepthOfMarket", "*DepthOfMarket", true, Type = typeof(DepthOfMarketIndicator))] internal sealed class DepthOfMarketIndicator : IndicatorBase { private int _scaleWidth; [DataMember(Name = "ScaleWidth")] [Category("Параметры"), DisplayName("Ширина шкалы")] public int ScaleWidth { get => _scaleWidth; set { value = Math.Max(0, value); if (value == _scaleWidth) { return; } _scaleWidth = value; OnPropertyChanged(); } } private IndicatorNullIntParam _scaleVolumeParam; [DataMember(Name = "ScaleVolumeParam")] public IndicatorNullIntParam ScaleVolumeParam { get => _scaleVolumeParam ?? (_scaleVolumeParam = new IndicatorNullIntParam(null)); set => _scaleVolumeParam = value; } [DefaultValue(null)] [Category("Параметры"), DisplayName("Объём шкалы")] public int? ScaleVolume { get => ScaleVolumeParam.Get(SettingsShortKey); set { if (!ScaleVolumeParam.Set(SettingsShortKey, value, 1)) { return; } OnPropertyChanged(); } } private DepthOfMarketScaleAlignment _scaleAlignment; [DataMember(Name = "DepthOfMarketScaleAlignment")] [Category("Параметры"), DisplayName("Расположение шкалы")] public DepthOfMarketScaleAlignment ScaleAlignment { get => _scaleAlignment; set { if (value == _scaleAlignment) { return; } _scaleAlignment = value; OnPropertyChanged(); } } private bool _addMargins; [DataMember(Name = "AddMargins")] [Category("Параметры"), DisplayName("Добавить отступы")] public bool AddMargins { get => _addMargins; set { if (value == _addMargins) { return; } _addMargins = value; OnPropertyChanged(); } } private bool _showValues; [DataMember(Name = "ShowValues")] [Category("Параметры"), DisplayName("Отображать значения")] public bool ShowValues { get => _showValues; set { if (value == _showValues) { return; } _showValues = value; OnPropertyChanged(); } } private bool _minimizeValues; [DataMember(Name = "MinimizeValues")] [Category("Параметры"), DisplayName("Минимизировать значения")] public bool MinimizeValues { get => _minimizeValues; set { if (value == _minimizeValues) { return; } _minimizeValues = value; OnPropertyChanged(); } } private IndicatorIntParam _roundValueParam; [DataMember(Name = "RoundValueParam")] public IndicatorIntParam RoundValuesParam { get => _roundValueParam ?? (_roundValueParam = new IndicatorIntParam(0)); set => _roundValueParam = value; } [DefaultValue(0)] [Category("Параметры"), DisplayName("Округлять значения")] public int RoundValues { get => RoundValuesParam.Get(SettingsLongKey); set { if (!RoundValuesParam.Set(SettingsLongKey, value, -4, 4)) { return; } OnPropertyChanged(); } } private XBrush _bidQuoteBrush; private XColor _quoteBuyColor; [DataMember(Name = "BidQuoteColor")] [Category("Стиль"), DisplayName("Заявка на покупку")] public XColor BidQuoteColor { get => _quoteBuyColor; set { if (_quoteBuyColor == value) { return; } _quoteBuyColor = value; _bidQuoteBrush = new XBrush(value); OnPropertyChanged(); } } private XBrush _bestBidQuoteBrush; private XColor _quoteBestBuyColor; [DataMember(Name = "BestBidQuoteColor")] [Category("Стиль"), DisplayName("Лучшая заявка на покупку")] public XColor BestBidQuoteColor { get => _quoteBestBuyColor; set { if (_quoteBestBuyColor == value) { return; } _quoteBestBuyColor = value; _bestBidQuoteBrush = new XBrush(value); OnPropertyChanged(); } } private XBrush _askQuoteBrush; private XColor _quoteSellColor; [DataMember(Name = "AskQuoteColor")] [Category("Стиль"), DisplayName("Заявка на продажу")] public XColor AskQuoteColor { get => _quoteSellColor; set { if (_quoteSellColor == value) { return; } _quoteSellColor = value; _askQuoteBrush = new XBrush(value); OnPropertyChanged(); } } private XBrush _bestAskQuoteBrush; private XColor _quoteBestSellColor; [DataMember(Name = "BestAskQuoteColor")] [Category("Стиль"), DisplayName("Лучшая заявка на прдажу")] public XColor BestAskQuoteColor { get => _quoteBestSellColor; set { if (_quoteBestSellColor == value) { return; } _quoteBestSellColor = value; _bestAskQuoteBrush = new XBrush(value); OnPropertyChanged(); } } private XBrush _emptyQuoteBrush; private XColor _quoteEmptyColor; [Browsable(false)] [DataMember(Name = "EmptyQuoteColor")] [Category("Стиль"), DisplayName("Цена без заявок")] public XColor EmptyQuoteColor { get => _quoteEmptyColor; set { if (_quoteEmptyColor == value) { return; } _quoteEmptyColor = value; _emptyQuoteBrush = new XBrush(value); OnPropertyChanged(); } } private XBrush _bidVolumeBrush; private XColor _quoteBuyVolumeColor; [DataMember(Name = "BidVolumeColor")] [Category("Стиль"), DisplayName("Шкала покупок")] public XColor BidVolumeColor { get => _quoteBuyVolumeColor; set { if (_quoteBuyVolumeColor == value) { return; } _quoteBuyVolumeColor = value; _bidVolumeBrush = new XBrush(value); OnPropertyChanged(); } } private XBrush _askVolumeBrush; private XColor _quoteSellVolumeColor; [DataMember(Name = "AskVolumeColor")] [Category("Стиль"), DisplayName("Шкала продаж")] public XColor AskVolumeColor { get => _quoteSellVolumeColor; set { if (_quoteSellVolumeColor == value) { return; } _quoteSellVolumeColor = value; _askVolumeBrush = new XBrush(value); OnPropertyChanged(); } } private XBrush _textBrush; private XColor _textColor; [DataMember(Name = "TextColor")] [Category("Стиль"), DisplayName("Цвет текста")] public XColor TextColor { get => _textColor; set { if (_textColor == value) { return; } _textColor = value; _textBrush = new XBrush(value); OnPropertyChanged(); } } private XBrush _backBrush; private XColor _backColor; [DataMember(Name = "BackColor")] [Category("Стиль"), DisplayName("Цвет фона")] public XColor BackColor { get => _backColor; set { if (_backColor == value) { return; } _backColor = value; _backBrush = new XBrush(value); OnPropertyChanged(); } } [Browsable(false)] public override bool ShowIndicatorValues => false; [Browsable(false)] public override bool ShowIndicatorLabels => false; [Browsable(false)] public override IndicatorCalculation Calculation => IndicatorCalculation.OnEachTick; public DepthOfMarketIndicator() { ShowIndicatorTitle = false; ScaleWidth = 0; ScaleAlignment = DepthOfMarketScaleAlignment.Right; AddMargins = false; ShowValues = true; MinimizeValues = false; BidQuoteColor = Colors.Transparent; BestBidQuoteColor = Colors.Transparent; AskQuoteColor = Colors.Transparent; BestAskQuoteColor = Colors.Transparent; EmptyQuoteColor = Colors.Transparent; BidVolumeColor = Color.FromArgb(255, 30, 144, 255); AskVolumeColor = Color.FromArgb(255, 178, 34, 34); TextColor = Colors.White; BackColor = Colors.Transparent; } protected override void Execute() { } public override void Render(DxVisualQueue visual) { var dp = DataProvider; var step = dp.Step; var symbol = dp.Symbol; var md = dp.GetRawMarketDepth(); var r = Canvas.Rect; var maxWidth = ScaleWidth > 0 ? ScaleWidth : r.Width * 0.1; var maxVolume = ScaleVolume > 0 ? symbol.CorrectSizeFilter(ScaleVolume.Value) : md.MaxSize; if (maxWidth < 5 || maxVolume < 1) { return; } var heightCorrect = AddMargins ? -1 : 0; var height = Math.Max(GetY(0.0) - GetY(step), 1); var fontSize = Math.Min(height + heightCorrect - 2, 18) * 96.0 / 72.0; fontSize = Math.Min(fontSize, Canvas.ChartFont.Size); var textFont = new XFont(Canvas.ChartFont.Name, fontSize); visual.FillRectangle(_backBrush, new Rect(r.Right - maxWidth, r.Y, maxWidth, r.Height)); var asksY1 = (int)GetY(md.MaxAskPrice * step + step / 2.0); var asksY2 = (int)GetY(md.MinAskPrice * step + step / 2.0); visual.FillRectangle(_askQuoteBrush, new Rect(new Point(r.Right - maxWidth, asksY1), new Point(r.Right, asksY2))); var bidsY1 = (int)GetY(md.MaxBidPrice * step - step / 2.0); var bidsY2 = (int)GetY(md.MinBidPrice * step - step / 2.0); visual.FillRectangle(_bidQuoteBrush, new Rect(new Point(r.Right - maxWidth, bidsY1), new Point(r.Right, bidsY2))); var prevY = (int)GetY(md.MaxAskPrice * step + step / 2.0); var maxPrice = Math.Min((long)Math.Round(Canvas.GetValue(r.Top) / step), md.MaxAskPrice); var minPrice = Math.Max((long)Math.Round(Canvas.GetValue(r.Bottom) / step), md.MinAskPrice); if (maxPrice - minPrice > 5000) { return; } var roundValues = RoundValues; for (var price = maxPrice; price >= minPrice; price--) { var currY = (int)GetY(price * step - step / 2.0); var currHeight = Math.Max(currY - prevY, 1); var y = prevY; prevY = currY; if (!md.AskQuotes.ContainsKey(price) || currY < r.Top) { continue; } if (price == md.MinAskPrice) { var quoteRect = new Rect(new Point(r.Right - maxWidth, y), new Point(r.Right, y + currHeight)); visual.FillRectangle(_bestAskQuoteBrush, quoteRect); } var volume = md.AskQuotes[price]; var text = symbol.FormatRawSize(volume, roundValues, MinimizeValues); var textWidth = textFont.GetWidth(text); var width = (int)Math.Min(volume * maxWidth / maxVolume, maxWidth); if (ShowValues && height > 8) { width = (int)Math.Min(Math.Max(width, textWidth), maxWidth); } var volumeRect = ScaleAlignment == DepthOfMarketScaleAlignment.Right ? new Rect(new Point(r.Right - width, y), new Point(r.Right, y + Math.Max(currHeight + heightCorrect, 1))) : new Rect(new Point(r.Right - maxWidth, y), new Point(r.Right - (maxWidth - width), y + Math.Max(currHeight + heightCorrect, 1))); visual.FillRectangle(_askVolumeBrush, volumeRect); if (ShowValues && height > 8) { visual.DrawString(text, textFont, _textBrush, volumeRect, ScaleAlignment == DepthOfMarketScaleAlignment.Right ? XTextAlignment.Right : XTextAlignment.Left); } } prevY = (int)GetY(md.MaxBidPrice * step + step / 2.0); maxPrice = Math.Min((long)Math.Round(Canvas.GetValue(r.Top) / step), md.MaxBidPrice); minPrice = Math.Max((long)Math.Round(Canvas.GetValue(r.Bottom) / step), md.MinBidPrice); if (maxPrice - minPrice > 5000) { return; } for (var price = maxPrice; price >= minPrice; price--) { var currY = (int)GetY(price * step - step / 2.0); var currHeight = Math.Max((currY - prevY), 1); var y = prevY; prevY = currY; if (!md.BidQuotes.ContainsKey(price) || y > r.Bottom) { continue; } if (price == md.MaxBidPrice) { var quoteRect = new Rect(new Point(r.Right - maxWidth, y), new Point(r.Right, y + currHeight)); visual.FillRectangle(_bestBidQuoteBrush, quoteRect); } var volume = md.BidQuotes[price]; var text = symbol.FormatRawSize(volume, roundValues, MinimizeValues); var textWidth = textFont.GetWidth(text); var width = (int)Math.Min(volume * maxWidth / maxVolume, maxWidth); if (ShowValues && height > 8) { width = (int)Math.Min(Math.Max(width, textWidth), maxWidth); } var volumeRect = ScaleAlignment == DepthOfMarketScaleAlignment.Right ? new Rect(new Point(r.Right - width, y), new Point(r.Right, y + Math.Max(currHeight + heightCorrect, 1))) : new Rect(new Point(r.Right - maxWidth, y), new Point(r.Right - (maxWidth - width), y + Math.Max(currHeight + heightCorrect, 1))); visual.FillRectangle(_bidVolumeBrush, volumeRect); if (ShowValues && height > 8) { visual.DrawString(text, textFont, _textBrush, volumeRect, ScaleAlignment == DepthOfMarketScaleAlignment.Right ? XTextAlignment.Right : XTextAlignment.Left); } } } public override void ApplyColors(IChartTheme theme) { BidVolumeColor = theme.PaletteColor6; AskVolumeColor = theme.PaletteColor7; TextColor = theme.ChartFontColor; base.ApplyColors(theme); } public override void CopyTemplate(IndicatorBase indicator, bool style) { var i = (DepthOfMarketIndicator)indicator; ScaleWidth = i.ScaleWidth; ScaleAlignment = i.ScaleAlignment; AddMargins = i.AddMargins; ShowValues = i.ShowValues; MinimizeValues = i.MinimizeValues; ScaleVolumeParam.Copy(i.ScaleVolumeParam); RoundValuesParam.Copy(i.RoundValuesParam); BidQuoteColor = i.BidQuoteColor; BestBidQuoteColor = i.BestBidQuoteColor; AskQuoteColor = i.AskQuoteColor; BestAskQuoteColor = i.BestAskQuoteColor; EmptyQuoteColor = i.EmptyQuoteColor; BidVolumeColor = i.BidVolumeColor; AskVolumeColor = i.AskVolumeColor; TextColor = i.TextColor; BackColor = i.BackColor; OnPropertyChanged(nameof(ScaleVolume)); base.CopyTemplate(indicator, style); } } }