Creating a Signal Library for Automated Trade Systems in NinjaScript
Learn how to create a custom class in C#/NinjaScript to define your trade strategy’s logic by building an EMA breakout strategy. Build a library of signals to streamline development and research.
Update:
This article was originally published for paid subscribers but has since then been set free. It has been some time since I have visited this article or used NinjaScript/NinjaTrader. Reach out if you have any questions.
Today, we will cover how to turn our individual strategy logic into a custom class for use inside a NinjaScript trading strategy. Why would you want to do this? There are several reasons, and if you have been reading any of the recent posts, you already know what I am going to say.
Creating a custom class to encapsulate our strategy logic helps us create a modular piece of code that can be reused easily. It enforces organization and improves testing and debugging capabilities. It’s inherently scalable and allows us to use multiple signals without having all our code live in a single strategy file. If that wasn’t enough, it also encourages best code development practices and makes collaboration and version control easier.
For the example, I will create a simple EMA breakout strategy. The strategy logic is: - Enter long/short when the previous bar closes over/under the EMA. - Exit long/short when the previous bar closes under/over the EMA.
We will break this logic up into 4 different signals. That allows us flexibility when we code the actual strategy. We can use the exit signals for trading or implement any of the previous exit strategies we discussed in HGT.
This strategy will use the custom evaluator methods we created in the previous post.
Disclaimer: the following post is an organized representation of my research and project notes. It doesn’t represent any type of advice, financial or otherwise. Its purpose is to be informative and educational. Backtest results are based on historical data, not real-time data. There is no guarantee that these hypothetical results will continue in the future. Day trading is extremely risky, and I do not suggest running any of these strategies live.
Code
Unlike the evaluator class we created, this one will not be static. That means we will need to create a constructor method and ensure it is instantiated correctly in the strategy. I use this method so we can use the signal to hold the names for strategies entry and exit signals. Further removing clutter from the strategy’s main file.
Besides the constructor, we must create four different functions for our strategy logic. This strategy assumes that you run calculations on bar close. If you run it on each tick, it may hold up, but I still need to test this.
Here is what the code for this simple EMA breakout strategy:
using System;
using UtilityFunctions;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript;
namespace SignalLibrary
{
public class EMABreakout
{
public string LongEntryName { get; private set; }
public string ShortEntryName { get; private set; }
public string LongExitName { get; private set; }
public string ShortExitName { get; private set; }
public EMABreakout()
{
LongEntryName = "Open Long";
ShortEntryName = "Open Short";
LongExitName = "Close Long";
ShortExitName = "Close Short";
}
public bool EntryLong(EMA ema, ISeries<double> barClose)
{
return Evaluators.CrossAbove(barClose, ema, 1);
}
public bool EntryShort(EMA ema, ISeries<double> barClose)
{
return Evaluators.CrossBelow(barClose, ema, 1);
}
public bool ExitLong(EMA ema, ISeries<double> barClose)
{
return Evaluators.CrossBelow(barClose, ema, 1);
}
public bool ExitShort(EMA emaFast, ISeries<double> barClose)
{
return Evaluators.CrossAbove(barClose, emaFast, 1);
}
}
}
Using the Signal in a Strategy
Below is an example of instantiating and using this signal in a strategy. We must ensure we instantiate an EMA
object and our custom EMABreakout
object. Then, we can use the signal inside OnBarUpdate()
to check and see if we have a tradeable event per the defined logic.
This example shows how I would use it to enter a trade. The exit logic can be used in the same manner.
private EMA _ema;
private EMABreakout _signal;
protected override void OnBarUpdate()
{
if (CurrentBar < 2)
return;
TimeSpan _timeNow = TimeSpan.FromHours(Time[0].Hour).Add(TimeSpan.FromMinutes(Time[0].Minute));
if (Evaluators.InsideTradeWindow(_startTime, _endTime, _timeNow))
{
if (Position.MarketPosition == MarketPosition.Flat)
{
if (_signal.EntryLong(_ema, Close) && _tradeDirection != TradeDirection.Short)
{
_entryOrder = EnterLong(Convert.ToInt32(DefaultQuantity), _signal.LongEntryName);
}
else if (_signal.EntryShort(_ema, Close) && _tradeDirection != TradeDirection.Long)
{
_entryOrder = EnterShort(Convert.ToInt32(DefaultQuantity), _signal.ShortEntryName);
}
}
}
}
Summary
The EMA breakout strategy is one that I have used before to trade manually. When I first started, I focused on small-cap stocks and momentum trading. I used a couple of different EMA indicators to help validate my trade ideas and entries. I didn’t use it by itself, but in the next post, I will show some backtest results of using this strategy with different exit strategies. It is relatively common to see traders using an EMA to support their trade ideas, and that’s why I made this simple class. It can be extended to include any criteria you want.
Separating the logic in this strategy allows us the ability to implement how we see fit in a strategy. For example, suppose we have a strategy that takes countertrend moves positions after big price moves. We can use the exit signals from this class to exit the position when the price returns to the EMA.
The next post will be the updated strategy template. It will use this signal and all previous classes we have created. It will have several different strategy exit variations to experiment with.
Feel free to comment below or e-mail me if you need help with anything, wish to criticize, or have thoughts on improvements. Paid subscribers can access this code and more at the private HGT GitHub repo. As always, this newsletter represents refined versions of my research notes. That means these notes are plastic. There could be mistakes or better ways to accomplish what I am trying to do. Nothing is perfect, and I always look for ways to improve my techniques.
Awesome