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
}
}