@Maverick’s tab colorizer (I am posting in a separate thread to avoid confusion) gave me idea to color chart trader background to distinguish between mini and micro. The code could be modified further to alert with color if mini has too many contracts, for example…
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Xml.Serialization;
using NinjaTrader.Gui.Chart;
namespace NinjaTrader.NinjaScript.Indicators
{
public class ChartTraderColorizer : Indicator
{
private Chart chartWindow;
private ChartTrader chartTrader;
private Grid mainGrid;
private Border parentBorder;
private Grid parentGrid;
private Brush originalTraderBg;
private Brush originalGridBg;
private Brush originalParentBg;
private bool subscribed;
private DispatcherTimer findTimer;
private Brush originalParentGridBg;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Description = @"Colors Chart Trader background based on contract size Mini vs Micro.";
Name = "ChartTraderColorizer";
Calculate = Calculate.OnBarClose;
IsOverlay = true;
DisplayInDataBox = false;
PaintPriceMarkers = false;
IsSuspendedWhileInactive = true;
MColor = Brushes.DeepSkyBlue;
NonMColor = Brushes.LightSkyBlue;
}
else if (State == State.Realtime) // Optimization: Only instantiate on Realtime UI thread
{
if (ChartControl == null) return;
ChartControl.Dispatcher.InvokeAsync((Action)(() => { SetupChartTrader(); }));
}
else if (State == State.Terminated)
{
if (ChartControl != null)
{
ChartControl.Dispatcher.InvokeAsync((Action)(() => { RestoreAndUnsubscribe(); }));
}
else
{
RestoreAndUnsubscribe();
}
}
}
private void SetupChartTrader()
{
if (findTimer == null)
{
findTimer = new DispatcherTimer();
findTimer.Interval = TimeSpan.FromMilliseconds(500);
findTimer.Tick += FindTimer_Tick;
findTimer.Start();
}
FindTimer_Tick(null, null);
}
private void FindTimer_Tick(object sender, EventArgs e)
{
if (ChartControl == null)
{
StopTimer();
return;
}
if (chartWindow == null)
{
chartWindow = Window.GetWindow(ChartControl.Parent) as Chart;
if (chartWindow == null) chartWindow = Window.GetWindow(ChartControl) as Chart;
}
if (chartWindow != null)
{
TryApplyColors();
if (chartTrader != null)
{
StopTimer();
}
}
}
private void StopTimer()
{
if (findTimer != null)
{
findTimer.Stop();
findTimer.Tick -= FindTimer_Tick;
findTimer = null;
}
}
private void TryApplyColors()
{
if (chartWindow == null) return;
if (chartTrader == null)
chartTrader = chartWindow.FindFirst("ChartWindowChartTraderControl") as ChartTrader;
if (chartTrader == null) return;
if (!subscribed)
{
chartTrader.IsVisibleChanged -= OnChartTraderVisibleChanged;
chartTrader.IsVisibleChanged += OnChartTraderVisibleChanged;
subscribed = true;
}
ApplyColors();
}
private void OnChartTraderVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is bool isVisible && isVisible)
{
ApplyColors();
}
}
private void ApplyColors()
{
if (chartTrader == null || Instrument?.MasterInstrument == null)
return;
Brush targetBrush = IsMicroInstrument() ? MColor : NonMColor;
if (originalTraderBg == null)
originalTraderBg = chartTrader.Background;
if (chartTrader.Background != targetBrush)
chartTrader.Background = targetBrush;
if (mainGrid == null)
mainGrid = chartTrader.Content as Grid;
if (mainGrid != null)
{
if (originalGridBg == null)
originalGridBg = mainGrid.Background;
if (mainGrid.Background != targetBrush)
mainGrid.Background = targetBrush;
}
DependencyObject parent = VisualTreeHelper.GetParent(chartTrader);
while (parent != null)
{
if (parent is Border border &&
border.Background != null &&
border.Background != Brushes.Transparent)
{
if (parentBorder == null)
parentBorder = border;
if (originalParentBg == null)
originalParentBg = parentBorder.Background;
if (!ReferenceEquals(parentBorder.Background, targetBrush))
parentBorder.Background = targetBrush;
break;
}
if (parent is Grid grid &&
grid.Background != null &&
grid.Background != Brushes.Transparent)
{
if (parentGrid == null)
parentGrid = grid;
if (originalParentGridBg == null)
originalParentGridBg = parentGrid.Background;
if (!ReferenceEquals(parentGrid.Background, targetBrush))
parentGrid.Background = targetBrush;
break;
}
parent = VisualTreeHelper.GetParent(parent);
}
}
private void RestoreAndUnsubscribe()
{
StopTimer();
if (subscribed && chartTrader != null) {
try { chartTrader.IsVisibleChanged -= OnChartTraderVisibleChanged; } catch { }
subscribed = false;
}
if (chartTrader != null && originalTraderBg != null)
chartTrader.Background = originalTraderBg;
if (mainGrid != null && originalGridBg != null)
mainGrid.Background = originalGridBg;
if (parentBorder != null && originalParentBg != null)
parentBorder.Background = originalParentBg;
if (parentGrid != null && originalParentGridBg != null)
parentGrid.Background = originalParentGridBg;
chartTrader = null;
mainGrid = null;
parentBorder = null;
parentGrid = null;
originalTraderBg = null;
originalGridBg = null;
originalParentBg = null;
originalParentGridBg = null;
chartWindow = null;
}
private bool IsMicroInstrument()
{
if (Instrument?.MasterInstrument == null) return false;
string name = Instrument.MasterInstrument.Name;
string desc = Instrument.MasterInstrument.Description;
if (!string.IsNullOrEmpty(desc) && desc.IndexOf("MICRO", StringComparison.OrdinalIgnoreCase) >= 0) return true;
if (name.Equals("SIL", StringComparison.OrdinalIgnoreCase) ||
name.Equals("10Y", StringComparison.OrdinalIgnoreCase) ||
name.Equals("2YY", StringComparison.OrdinalIgnoreCase) ||
name.Equals("30Y", StringComparison.OrdinalIgnoreCase) ||
name.Equals("5YY", StringComparison.OrdinalIgnoreCase) ||
name.Equals("EBM", StringComparison.OrdinalIgnoreCase)) return true;
if (name.StartsWith("M6", StringComparison.OrdinalIgnoreCase)) return true;
if (name.Equals("M2K", StringComparison.OrdinalIgnoreCase)) return true;
if (name.StartsWith("M", StringComparison.OrdinalIgnoreCase) && (name.Length == 3) && !name.Equals("MME", StringComparison.OrdinalIgnoreCase)) return true;
return false;
}
#region Properties
private Brush mColor;
[XmlIgnore]
[Display(Name = "Color if Micro", Description = "Background color if instrument is a micro contract (e.g. MNQ, MES)", Order = 1, GroupName = "Parameters")]
public Brush MColor
{
get => mColor;
set
{
if (value != null && value.CanFreeze && !value.IsFrozen)
value.Freeze();
mColor = value;
}
}
[Browsable(false)]
public string MColorSerialize
{
get => NinjaTrader.Gui.Serialize.BrushToString(mColor);
set => MColor = NinjaTrader.Gui.Serialize.StringToBrush(value);
}
private Brush nonMColor;
[XmlIgnore]
[Display(Name = "Color if NOT Micro", Description = "Background color if instrument is not micro contract (e.g. NQ, ES)", Order = 2, GroupName = "Parameters")]
public Brush NonMColor
{
get => nonMColor;
set
{
if (value != null && value.CanFreeze && !value.IsFrozen)
value.Freeze();
nonMColor = value;
}
}
[Browsable(false)]
public string NonMColorSerialize
{
get => NinjaTrader.Gui.Serialize.BrushToString(nonMColor);
set => NonMColor = NinjaTrader.Gui.Serialize.StringToBrush(value);
}
#endregion
}
}

