270 lines
12 KiB
C#
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
|