Code to accompany the article “An Expert Of A System” by Sylvain Vervoort, in the October 2013 issue of Technical Analysis of Stocks & Commodities magazine.
SVEHaTypCross - Color Coding Expert
// SVEHaTypCross is Copyright (C)2013, Sylvain Vervoort < stocata.org> . // stocata.org reserves the right to modify this NinjaScript with each release. // Release V1.0 January, 2013. #region Using declarations using System; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Xml.Serialization; using NinjaTrader.Data; using NinjaTrader.Gui.Chart; #endregion // This namespace holds all indicators and is required. Do not change it. namespace NinjaTrader.Indicator { /// < summary> /// A typical and heikin-ashi price crossover color coding the candle chart. /// < /summary> [Description("")] public class SVEHaTypCross : Indicator { #region Variables private int haCaverage = 8; // Default heikin-ashi Closing price average private int typicalaverage = 5; // Default typical price average private DataSeries haOpen; // heikin ashi open price private DataSeries haC; // heikin ashi closing price private DataSeries typical; // typical price private DataSeries AVGtyp; // typical price average private DataSeries AVGhaC; // heikin-ashi average private DataSeries cross; // typical average crossing HA average private Color candlefillup = Color.White; private Color candlednfill = Color.Gray; private Color candleupfill = Color.LimeGreen; private Color outlineup = Color.LimeGreen; private Color outlinedn = Color.Black; #endregion /// < summary> /// Configuring the indicator called once before any bar data. /// < /summary> protected override void Initialize() { haOpen = new DataSeries(this); haC = new DataSeries(this); typical = new DataSeries(this); AVGtyp = new DataSeries(this); AVGhaC = new DataSeries(this); cross = new DataSeries(this); PaintPriceMarkers = false; Overlay = true; } /// < summary> /// Called on each bar update event (incoming tick) /// < /summary> protected override void OnBarUpdate() { if (CurrentBar < 1) // minimum 2 bars required return; // Create crossover data sets haOpen.Set((((Open[1] + High[1] + Low[1] + Close[1]) / 4) + haOpen[1]) / 2); haC.Set(((Open[0] + High[0] + Low[0] + Close[0]) / 4 + haOpen[0] + Math.Max(High[0], haOpen[0]) + Math.Min(Low[0], haOpen[0])) / 4); typical.Set((High[0] + Low[0] + Close[0]) / 3); // Create the averages AVGtyp.Set(EMA(typical, typicalaverage)[0]); AVGhaC.Set(EMA(haC, haCaverage)[0]); // Crossover condition if(AVGtyp[0] > AVGhaC[0] && Close[0] > Open[0]) cross[0] = 1; else if(AVGtyp[0] < AVGhaC[0] && Close[0] < Open[0]) cross[0] = 0; else cross[0] = cross[1]; // Color coding the candle chart if(cross[0] == 1) { BarColorSeries[0] = candleupfill; CandleOutlineColorSeries[0] = outlineup; if(ChartControl.ChartStyleType == ChartStyleType.CandleStick) if(Close[0] > = Open[0]) BarColorSeries[0] = candlefillup; else BarColorSeries[0] = candleupfill; } else if(cross[0] == 0) { BarColorSeries[0] = candlednfill; CandleOutlineColorSeries[0] = outlinedn; if(ChartControl.ChartStyleType == ChartStyleType.CandleStick) if(Close[0] > = Open[0]) BarColorSeries[0] = candlefillup; else BarColorSeries[0] = candlednfill; } } #region Properties /// < summary> /// < /summary> [Description("Heikin-ashi Average DEF = 8")] [Category("Parameters")] [Gui.Design.DisplayName("1. Heikin-Ashi average")] public int AVG__slow { get { return haCaverage; } set { haCaverage = Math.Max(1, value); } } /// < summary> /// < /summary> [Description("Typical average DEF = 5")] [Category("Parameters")] [Gui.Design.DisplayName("2. Typical Price Average")] public int AVG_fast { get { return typicalaverage; } set { typicalaverage = Math.Max(1, value); } } [Description("Color for an UP candle DEFAULT = White")] [Category("Parameters")] [Gui.Design.DisplayName("3. Up candle color")] public Color Candlefillup { get { return candlefillup; } set { candlefillup = value; } } [Browsable(false)] public string CandlefillupSerialize { get { return NinjaTrader.Gui.Design.SerializableColor.ToString(candlefillup); } set { candlefillup = NinjaTrader.Gui.Design.SerializableColor.FromString(value); } } [Description("Down candle fill color DEFAULT = Gray")] [Category("Parameters")] [Gui.Design.DisplayName("4. Down fill color")] public Color Candlednfill { get { return candlednfill; } set { candlednfill = value; } } [Browsable(false)] public string CandlednfillSerialize { get { return NinjaTrader.Gui.Design.SerializableColor.ToString(candlednfill); } set { candlednfill = NinjaTrader.Gui.Design.SerializableColor.FromString(value); } } [Description("Up candle fill color DEFAULT = LimeGreen")] [Category("Parameters")] [Gui.Design.DisplayName("5. Up fill color")] public Color Candleupfill { get { return candleupfill; } set { candleupfill = value; } } [Browsable(false)] public string CandleupfillSerialize { get { return NinjaTrader.Gui.Design.SerializableColor.ToString(candleupfill); } set { candleupfill = NinjaTrader.Gui.Design.SerializableColor.FromString(value); } } [Description("Outline Up color DEFAULT = LimeGreen")] [Category("Parameters")] [Gui.Design.DisplayName("6. Outline Up color")] public Color Outlineup { get { return outlineup; } set { outlineup = value; } } [Browsable(false)] public string OutlineupSerialize { get { return NinjaTrader.Gui.Design.SerializableColor.ToString(outlineup); } set { outlineup = NinjaTrader.Gui.Design.SerializableColor.FromString(value); } } [Description("Outline Down color DEFAULT = Black")] [Category("Parameters")] [Gui.Design.DisplayName("7. Outline Down color")] public Color Outlinedn { get { return outlinedn; } set { outlinedn = value; } } [Browsable(false)] public string OutlinednSerialize { get { return NinjaTrader.Gui.Design.SerializableColor.ToString(outlinedn); } set { outlinedn = NinjaTrader.Gui.Design.SerializableColor.FromString(value); } } #endregion } }
SVEHaTypCrossInd - Digital Indicator
// // SVEHaTypCrossInd is Copyright (C) 2013, Sylvain Vervoort < stocata.org> . // stocata.org reserves the right to modify/overwrite this NinjaScript with each release. // Release V1.1 January, 2013. #region Using declarations using System; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Xml.Serialization; using NinjaTrader.Data; using NinjaTrader.Gui.Chart; #endregion // This namespace holds all indicators and is required. Do not change it. namespace NinjaTrader.Indicator { /// < summary> /// A typical and heikin-ashi price crossover digital indicator. /// < /summary> [Description("Typical price and heikin ashi crossover digital indicator")] public class SVEHaTypCrossInd : Indicator { #region Variables private int haCaverage = 8; // Default heikin-ashi Closing price average private int typicalaverage = 5; // Default typical price average private DataSeries haOpen; // heikin ashi open price private DataSeries haC; // heikin ashi closing price private DataSeries typical; // typical price private DataSeries AVGtyp; // typical price average private DataSeries AVGhaC; // heikin-ashi average private DataSeries cross; // typical average crossing HA average #endregion /// < summary> /// Configuring the indicator called once before any bar data. /// < /summary> protected override void Initialize() { Add(new Plot(Color.DodgerBlue, "Cross Ind")); haOpen = new DataSeries(this); haC = new DataSeries(this); typical = new DataSeries(this); AVGtyp = new DataSeries(this); AVGhaC = new DataSeries(this); cross = new DataSeries(this); PaintPriceMarkers = false; Overlay = false; } /// < summary> /// Called on each bar update event (incoming tick) /// < /summary> protected override void OnBarUpdate() { if (CurrentBar < 1) // minimum 2 bars required return; // Create crossover data sets haOpen.Set((((Open[1] + High[1] + Low[1] + Close[1]) / 4) + haOpen[1]) / 2); haC.Set(((Open[0] + High[0] + Low[0] + Close[0]) / 4 + haOpen[0] + Math.Max(High[0], haOpen[0]) + Math.Min(Low[0], haOpen[0])) / 4); typical.Set((High[0] + Low[0] + Close[0]) / 3); // Create the averages AVGtyp.Set(EMA(typical, typicalaverage)[0]); AVGhaC.Set(EMA(haC, haCaverage)[0]); // Crossover condition if(AVGtyp[0] > AVGhaC[0] && Close[0] > Open[0]) cross[0] = 1; else if(AVGtyp[0] < AVGhaC[0] && Close[0] < Open[0]) cross[0] = 0; else cross[0] = cross[1]; Value.Set(cross[0]); } #region Properties /// < summary> /// < /summary> [Description("Heikin-ashi Average DEF = 8")] [GridCategory("Parameters")] [Gui.Design.DisplayName("1. Heikin-Ashi average")] public int AVG__slow { get { return haCaverage; } set { haCaverage = Math.Max(1, value); } } /// < summary> /// < /summary> [Description("Typical average DEF = 5")] [GridCategory("Parameters")] [Gui.Design.DisplayName("2. Typical Price Average")] public int AVG_fast { get { return typicalaverage; } set { typicalaverage = Math.Max(1, value); } } #endregion } }
SVEHaTypCross - Strategy
// SVEHaTypCross strategy is Copyright (C) 2013, Sylvain Vervoort < stocata.org> . // stocata.org reserves the right to modify/overwrite this NinjaScript with each release. // Release V1.1 February, 2013. // This strategy is for training purposes only. Any other use is strictly at your own risk. #region Using declarations using System; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Xml.Serialization; using NinjaTrader.Cbi; using NinjaTrader.Data; using NinjaTrader.Indicator; using NinjaTrader.Gui.Chart; using NinjaTrader.Strategy; using System.IO; using System.Collections; using System.Windows.Forms; #endregion // This namespace holds all strategies and is required. Do not change it. namespace NinjaTrader.Strategy { /// < summary> /// Typical price cross over with Heikin-Ashi prices for stocks /// < /summary> [Description("SVEHaTypCross Price cross over system for trading Stocks")] public class SVEHaTypCross : Strategy { // Variables---------------------------------------------------------------------------- #region Variables private int haCaverage = 8; // Heikin-Ashi average private int typicalaverage = 5; // Typical price average private double stoplossperc = 25; // Stop loss percentage private double breakevenperc = 15; // Break even percentage private int stocksqty = 100; // Basic stock buying quantity bool OpnBuyClsSell = false, OpnSellClsBuy = false; private IOrder sOrderLong = null; // Long order identity private IOrder sStopLong = null; // Stop loss long order identity private IOrder sOrderShort = null; // Short order identity private IOrder sStopShort = null; // Stop loss short order identity private IOrder sOrdExLong = null; // Exit long order identity private IOrder sOrdExShort = null; // Exit short order identity #endregion // Initialize ---------------------------------------------------------------------------- protected override void Initialize() { CalculateOnBarClose = true; TraceOrders = true; EntryHandling = EntryHandling.UniqueEntries; ExitOnClose = false; SyncAccountPosition = false; StopTargetHandling = StopTargetHandling.ByStrategyPosition; } // On bar update ---------------------------------------------------------------------------- protected override void OnBarUpdate() { OpnBuyClsSell = false; OpnSellClsBuy = false; // The single autotrade signal crossovers if (SVEHaTypCrossInd(haCaverage,typicalaverage)[0] > 0 && SVEHaTypCrossInd(haCaverage,typicalaverage)[1] < 1) OpnBuyClsSell = true; if (SVEHaTypCrossInd(haCaverage,typicalaverage)[0] < 1 && SVEHaTypCrossInd(haCaverage,typicalaverage)[1] > 0) OpnSellClsBuy = true; // Opening the trade if (OpnBuyClsSell == true && Position.MarketPosition == MarketPosition.Flat) sOrderLong = EnterLong(stocksqty,"sOrderLong"); else if (OpnBuyClsSell == true && Position.MarketPosition == MarketPosition.Short) { sOrdExShort = ExitShort(Position.Quantity,"sOrdExShort","sOrderShort"); sOrderLong = EnterLong(stocksqty,"sOrderLong"); } if (OpnSellClsBuy == true && Position.MarketPosition == MarketPosition.Flat) sOrderShort = EnterShort(stocksqty, "sOrderShort"); else if (OpnSellClsBuy == true && Position.MarketPosition == MarketPosition.Long) { sOrdExLong = ExitLong(Position.Quantity,"sOrdExLong","sOrderLong"); sOrderShort = EnterShort(stocksqty,"sOrderShort"); } // Modify stop-loss setting to breakeven for a long position if (Position.MarketPosition == MarketPosition.Long && Close[0] > = Position.AvgPrice + breakevenperc * 0.01 * Position.AvgPrice) { // Check if a Stop Order exists, modify it to breakeven if (sStopLong != null && sStopLong.StopPrice < Position.AvgPrice) { // Modify stop-loss to breakeven sStopLong = ExitLongStop(0,true, sStopLong.Quantity, Position.AvgPrice, "sStopLong", "sOrderLong"); } } // Modify stop-loss to breakeven for a short position if (Position.MarketPosition == MarketPosition.Short && Close[0] < = Position.AvgPrice - breakevenperc * 0.01 * Position.AvgPrice) { // Check if a Stop Order exists, modify it to breakeven if (sStopShort != null && sStopShort.StopPrice > Position.AvgPrice) { // Modify stop-loss to breakeven sStopShort = ExitShortStop(0,true, sStopShort.Quantity, Position.AvgPrice, "sStopShort", "sOrderShort"); } } } // ----------------------------------------------------------------------------------------- protected override void OnOrderUpdate(IOrder order) { // Identify the entry order by calling the OnOrderUpdate() method. if (sOrderLong != null && sOrderLong == order) { // Reset the entryOrder object to null if order was cancelled without any fill if (order.OrderState == OrderState.Cancelled && order.Filled == 0) { sOrderLong = null; } } if (sOrderShort != null && sOrderShort == order) { if (order.OrderState == OrderState.Cancelled && order.Filled == 0) { sOrderShort = null; } } } // ------------------------------------------------------------------------------------------ protected override void OnExecution(IExecution execution) { // Monitoring order Execution to submit a stop order for a long position. // OnExecution() is called after OnOrderUpdate(). if (sOrderLong != null && sOrderLong == execution.Order) { if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled || (execution.Order.OrderState == OrderState.Cancelled && execution.Order.Filled > 0)) { sStopLong = ExitLongStop(0, true, execution.Order.Filled, execution.Order.AvgFillPrice - stoplossperc * 0.01 * execution.Order.AvgFillPrice, "sStopLong", "sOrderLong"); // Resetting the entryOrder object to null after the order is filled if (execution.Order.OrderState != OrderState.PartFilled) sOrderLong = null; } } // Reset exit long order when position is closed if (sOrdExLong == execution.Order) { sOrdExLong = null; } // Reset when stop long position is closed if (sStopLong == execution.Order) { sStopLong = null; } // Submitting stop order for a short position... if (sOrderShort != null && sOrderShort == execution.Order) { if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled || (execution.Order.OrderState == OrderState.Cancelled && execution.Order.Filled > 0)) { sStopShort = ExitShortStop(0, true, execution.Order.Filled, execution.Order.AvgFillPrice + stoplossperc * 0.01 * execution.Order.AvgFillPrice, "sStopShort", "sOrderShort"); // Resetting the entryOrder object to null after the order is filled if (execution.Order.OrderState != OrderState.PartFilled) sOrderShort = null; } } // Reset exit short order when position is closed if (sOrdExShort == execution.Order) { sOrdExShort = null; } // Reset when stop short position is closed if (sStopShort == execution.Order) { sStopShort = null; } } #region Properties [Description("Heikin-Ashi average: DEFAULT = 8")] [GridCategory("Parameters")] [Gui.Design.DisplayName("1. Heikin-Ashi average")] public int P01_haCaverage { get { return haCaverage; } set { haCaverage = Math.Max(1, value); } } [Description("Typical average: DEFAULT = 5")] [GridCategory("Parameters")] [Gui.Design.DisplayName("2. Typical average")] public int P02_typicalaverage { get { return typicalaverage; } set { typicalaverage = Math.Max(1, value); } } [Description("Emergency stop percentage: DEFAULT = 25.0 percent")] [GridCategory("Parameters")] [Gui.Design.DisplayName("3. Emergency stop percentage")] public double P05_stoplossPercentage { get { return stoplossperc; } set { stoplossperc = Math.Max(0.001, value); } } [Description("Breakeven percentage: DEFAULT = 15.0 percent")] [GridCategory("Parameters")] [Gui.Design.DisplayName("4. Breakeven percentage")] public double P06_breakevenPercentage { get { return breakevenperc; } set { breakevenperc = Math.Max(0.001, value); } } [Description("Number of stocks traded: DEFAULT = 100")] [GridCategory("Parameters")] [Gui.Design.DisplayName("5. Buy/Sell quantity")] public int P07_stocks_Quantity { get { return stocksqty; } set { stocksqty = Math.Max(1, value); } } #endregion } }