ninjatrader/indicators/Tape.cs

270 lines
12 KiB
C#

#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