Add indicator for displaying the tape (a.k.a. time and sales) on the chart rather than in a separate window
This commit is contained in:
parent
2b3af88eb8
commit
45311e06c0
269
indicators/Tape.cs
Normal file
269
indicators/Tape.cs
Normal file
@ -0,0 +1,269 @@
|
||||
#region Using declarations
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Xml.Serialization;
|
||||
using NinjaTrader.Cbi;
|
||||
using NinjaTrader.Gui;
|
||||
using NinjaTrader.Gui.Chart;
|
||||
using NinjaTrader.Gui.SuperDom;
|
||||
using NinjaTrader.Gui.Tools;
|
||||
using NinjaTrader.Data;
|
||||
using NinjaTrader.NinjaScript;
|
||||
using NinjaTrader.Core.FloatingPoint;
|
||||
using NinjaTrader.NinjaScript.DrawingTools;
|
||||
using SharpDX.DirectWrite;
|
||||
#endregion
|
||||
|
||||
//This namespace holds Indicators in this folder and is required. Do not change it.
|
||||
namespace NinjaTrader.NinjaScript.Indicators
|
||||
{
|
||||
[CategoryOrder("Order Display", 1)]
|
||||
[CategoryOrder("Order Colors", 2)]
|
||||
[CategoryOrder("Text Formatting", 3)]
|
||||
public class Tape : Indicator
|
||||
{
|
||||
private const int DefaultOrderFilter = 1; // By default, all orders are shown.
|
||||
private const int DefaultMaxOrders = 50;
|
||||
private const int DefaultDisplayOffset = 225;
|
||||
private static readonly Brush DefaultBuyOrderColor = Brushes.LimeGreen;
|
||||
private static readonly Brush DefaultSellOrderColor = Brushes.Red;
|
||||
private const string DefaultTimestampFormat = "HH:mm:ss.fff";
|
||||
private static readonly SimpleFont DefaultFontFamily = new SimpleFont("Arial", 12);
|
||||
|
||||
private class OrderData
|
||||
{
|
||||
public DateTime Time { get; set; }
|
||||
public double Price { get; set; }
|
||||
public long Volume { get; set; }
|
||||
public double Ask { get; set; }
|
||||
public double Bid { get; set; }
|
||||
}
|
||||
|
||||
private List<OrderData> recentOrders = new List<OrderData>();
|
||||
|
||||
protected override void OnStateChange()
|
||||
{
|
||||
if (State == State.SetDefaults)
|
||||
{
|
||||
Description = @"Displays the tape on the chart rather than in a separate window";
|
||||
Name = "Tape";
|
||||
Calculate = Calculate.OnEachTick;
|
||||
IsOverlay = true;
|
||||
DisplayInDataBox = true;
|
||||
DrawOnPricePanel = true;
|
||||
DrawHorizontalGridLines = true;
|
||||
DrawVerticalGridLines = true;
|
||||
PaintPriceMarkers = true;
|
||||
ScaleJustification = ScaleJustification.Right;
|
||||
IsSuspendedWhileInactive = false;
|
||||
OrderFilter = DefaultOrderFilter;
|
||||
CombineOrders = false;
|
||||
MaxDisplayOrders = DefaultMaxOrders;
|
||||
DisplayOrdersOffset = DefaultDisplayOffset;
|
||||
BuyOrderColor = DefaultBuyOrderColor;
|
||||
SellOrderColor = DefaultSellOrderColor;
|
||||
TimestampFormat = DefaultTimestampFormat;
|
||||
TextFontFamily = DefaultFontFamily;
|
||||
}
|
||||
else if (State == State.Configure)
|
||||
{
|
||||
}
|
||||
else if (State == State.Historical)
|
||||
{
|
||||
SetZOrder(-1); // Display behind bars on chart.
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMarketData(MarketDataEventArgs marketDataUpdate)
|
||||
{
|
||||
if (marketDataUpdate.MarketDataType == MarketDataType.Last && marketDataUpdate.Volume >= OrderFilter)
|
||||
{
|
||||
if (CombineOrders && recentOrders.Any(o => o.Time == marketDataUpdate.Time && o.Price == marketDataUpdate.Price))
|
||||
{
|
||||
var existingOrder = recentOrders.First(o => o.Time == marketDataUpdate.Time && o.Price == marketDataUpdate.Price);
|
||||
existingOrder.Volume += marketDataUpdate.Volume;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (recentOrders.Count >= MaxDisplayOrders)
|
||||
recentOrders.RemoveAt(0); // Remove the oldest order.
|
||||
|
||||
recentOrders.Add(new OrderData
|
||||
{
|
||||
Time = marketDataUpdate.Time,
|
||||
Price = marketDataUpdate.Price,
|
||||
Volume = marketDataUpdate.Volume,
|
||||
Ask = marketDataUpdate.Ask,
|
||||
Bid = marketDataUpdate.Bid
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
|
||||
{
|
||||
base.OnRender(chartControl, chartScale);
|
||||
|
||||
if (recentOrders.Count == 0)
|
||||
return; // No values to render
|
||||
|
||||
int startY = ChartPanel.Y;
|
||||
int spaceBetween = 15;
|
||||
int currentY = startY;
|
||||
|
||||
for (int i = recentOrders.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var order = recentOrders[i];
|
||||
string text = string.Format("{0:" + TimestampFormat + "} Price: {1:F2} Volume: {2}", order.Time, order.Price, order.Volume);
|
||||
|
||||
SharpDX.Direct2D1.Brush brush;
|
||||
if (order.Price >= order.Ask)
|
||||
brush = BuyOrderColor.ToDxBrush(RenderTarget);
|
||||
else if (order.Price <= order.Bid)
|
||||
brush = SellOrderColor.ToDxBrush(RenderTarget);
|
||||
else
|
||||
brush = Brushes.White.ToDxBrush(RenderTarget);
|
||||
|
||||
TextFormat format = TextFontFamily.ToDirectWriteTextFormat();
|
||||
TextLayout layout = new TextLayout(Core.Globals.DirectWriteFactory, text, format, 500, format.FontSize);
|
||||
|
||||
SharpDX.Vector2 textOrigin = new SharpDX.Vector2(
|
||||
ChartPanel.W - DisplayOrdersOffset,
|
||||
currentY
|
||||
);
|
||||
|
||||
RenderTarget.DrawTextLayout(textOrigin, layout, brush, SharpDX.Direct2D1.DrawTextOptions.NoSnap);
|
||||
|
||||
currentY += (int)layout.Metrics.Height + spaceBetween;
|
||||
|
||||
layout.Dispose();
|
||||
format.Dispose();
|
||||
brush.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnBarUpdate() {}
|
||||
|
||||
public override string DisplayName
|
||||
{
|
||||
get { return Name; }
|
||||
}
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Range(1, int.MaxValue)]
|
||||
[Display(Name = "Order Filter", Order = 1, GroupName = "Order Display")]
|
||||
public int OrderFilter { get; set; }
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Display(Name = "Combine Orders", Order = 2, GroupName = "Order Display")]
|
||||
public bool CombineOrders { get; set; }
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Range(1, int.MaxValue)]
|
||||
[Display(Name = "Max Orders", Order = 3, GroupName = "Order Display")]
|
||||
public int MaxDisplayOrders { get; set; }
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Range(1, int.MaxValue)]
|
||||
[Display(Name = "Display Offset", Order = 4, GroupName = "Order Display")]
|
||||
public int DisplayOrdersOffset { get; set; }
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[XmlIgnore]
|
||||
[Display(Name = "Buy Order Color", Order = 1, GroupName = "Order Colors")]
|
||||
public Brush BuyOrderColor { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public string BuyOrderColorSerialization
|
||||
{
|
||||
get { return Serialize.BrushToString(BuyOrderColor); }
|
||||
set { BuyOrderColor = Serialize.StringToBrush(value); }
|
||||
}
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[XmlIgnore]
|
||||
[Display(Name = "Sell Order Color", Order = 2, GroupName = "Order Colors")]
|
||||
public Brush SellOrderColor { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public string SellOrderColorSerialization
|
||||
{
|
||||
get { return Serialize.BrushToString(SellOrderColor); }
|
||||
set { SellOrderColor = Serialize.StringToBrush(value); }
|
||||
}
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Display(Name = "Timestamp Format", Order = 1, GroupName = "Text Formatting")]
|
||||
public string TimestampFormat { get; set; }
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Display(Name = "Font Family", Order = 2, GroupName = "Text Formatting")]
|
||||
public SimpleFont TextFontFamily { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#region NinjaScript generated code. Neither change nor remove.
|
||||
|
||||
namespace NinjaTrader.NinjaScript.Indicators
|
||||
{
|
||||
public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
|
||||
{
|
||||
private Tape[] cacheTape;
|
||||
public Tape Tape(int orderFilter, bool combineOrders, int maxDisplayOrders, int displayOrdersOffset, Brush buyOrderColor, Brush sellOrderColor, string timestampFormat, SimpleFont textFontFamily)
|
||||
{
|
||||
return Tape(Input, orderFilter, combineOrders, maxDisplayOrders, displayOrdersOffset, buyOrderColor, sellOrderColor, timestampFormat, textFontFamily);
|
||||
}
|
||||
|
||||
public Tape Tape(ISeries<double> input, int orderFilter, bool combineOrders, int maxDisplayOrders, int displayOrdersOffset, Brush buyOrderColor, Brush sellOrderColor, string timestampFormat, SimpleFont textFontFamily)
|
||||
{
|
||||
if (cacheTape != null)
|
||||
for (int idx = 0; idx < cacheTape.Length; idx++)
|
||||
if (cacheTape[idx] != null && cacheTape[idx].OrderFilter == orderFilter && cacheTape[idx].CombineOrders == combineOrders && cacheTape[idx].MaxDisplayOrders == maxDisplayOrders && cacheTape[idx].DisplayOrdersOffset == displayOrdersOffset && cacheTape[idx].BuyOrderColor == buyOrderColor && cacheTape[idx].SellOrderColor == sellOrderColor && cacheTape[idx].TimestampFormat == timestampFormat && cacheTape[idx].TextFontFamily == textFontFamily && cacheTape[idx].EqualsInput(input))
|
||||
return cacheTape[idx];
|
||||
return CacheIndicator<Tape>(new Tape(){ OrderFilter = orderFilter, CombineOrders = combineOrders, MaxDisplayOrders = maxDisplayOrders, DisplayOrdersOffset = displayOrdersOffset, BuyOrderColor = buyOrderColor, SellOrderColor = sellOrderColor, TimestampFormat = timestampFormat, TextFontFamily = textFontFamily }, input, ref cacheTape);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
|
||||
{
|
||||
public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
|
||||
{
|
||||
public Indicators.Tape Tape(int orderFilter, bool combineOrders, int maxDisplayOrders, int displayOrdersOffset, Brush buyOrderColor, Brush sellOrderColor, string timestampFormat, SimpleFont textFontFamily)
|
||||
{
|
||||
return indicator.Tape(Input, orderFilter, combineOrders, maxDisplayOrders, displayOrdersOffset, buyOrderColor, sellOrderColor, timestampFormat, textFontFamily);
|
||||
}
|
||||
|
||||
public Indicators.Tape Tape(ISeries<double> input , int orderFilter, bool combineOrders, int maxDisplayOrders, int displayOrdersOffset, Brush buyOrderColor, Brush sellOrderColor, string timestampFormat, SimpleFont textFontFamily)
|
||||
{
|
||||
return indicator.Tape(input, orderFilter, combineOrders, maxDisplayOrders, displayOrdersOffset, buyOrderColor, sellOrderColor, timestampFormat, textFontFamily);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace NinjaTrader.NinjaScript.Strategies
|
||||
{
|
||||
public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
|
||||
{
|
||||
public Indicators.Tape Tape(int orderFilter, bool combineOrders, int maxDisplayOrders, int displayOrdersOffset, Brush buyOrderColor, Brush sellOrderColor, string timestampFormat, SimpleFont textFontFamily)
|
||||
{
|
||||
return indicator.Tape(Input, orderFilter, combineOrders, maxDisplayOrders, displayOrdersOffset, buyOrderColor, sellOrderColor, timestampFormat, textFontFamily);
|
||||
}
|
||||
|
||||
public Indicators.Tape Tape(ISeries<double> input , int orderFilter, bool combineOrders, int maxDisplayOrders, int displayOrdersOffset, Brush buyOrderColor, Brush sellOrderColor, string timestampFormat, SimpleFont textFontFamily)
|
||||
{
|
||||
return indicator.Tape(input, orderFilter, combineOrders, maxDisplayOrders, displayOrdersOffset, buyOrderColor, sellOrderColor, timestampFormat, textFontFamily);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
Loading…
Reference in New Issue
Block a user