Define Register Actions Method

Register actions which define your strategy logic.

Once we have connected our strategy to indicators and data, we're ready to do the fun part — automating our trading idea. First, let's write down the essence of our investment strategy in pseudocode:

BUY RULES:
IF [smaFast > smaSlow] AND [no open position] THEN BUY.
SELL RULES:
IF [smaFast < smaSlow] AND [open position] THEN SELL.

We would like to have these investment rules performed each hour, every time a new hourly bar is created. We have already created the hourlyBar variable, which contains a data stream of hourly bars, so every time it is updated a new bar is streamed into the variable. To register the action which will be performed each time the hourlyBar variable is updated and a new hourly bar is created, we just have to write a few lines of code inside the RegisterActions method:

public override void RegisterActions()
{
OnUpdateOf(hourlyBars).Do(() =>
{
// Our investment rule will be here
}
);
}

One last step is missing. We need to transform the pseudocode from our investment rules into code for Signals Framework. Let’s first see how the code looks and then we can go over it:

public override void RegisterActions()
{
OnUpdateOf(hourlyBars).Do(() =>
{
if (smaFast.Value > smaSlow.Value && !Position.InPosition)
{
EnterLong();
}
else if (smaFast.Value < smaSlow.Value && Position.InPosition)
{
ExitLong();
}
}
);
}

You can see that the syntax of Signals Framework is very simple and easy to read. Moreover, the intellisense feature and Signals documentation will help you in the process of transforming your ideas into scripts.

To access the value of smaFast (simple moving average with period 10) we just used a smaFast.Value expression. We did the same for smaSlow (simple moving average with period 25) to compare those two values. In the condition, we also want to check whether the strategy is currently in an open position or not. This is possible using the Position object and its property Position.InPosition, which returns whether the current position is open (returns True value) or not (returns False).

The EnterLong() function is used to open a long position (Buy order) and ExitLong() is used to close this long position (Sell order). If we wanted to implement the Short position (the opposite of this strategy), to speculate about a cryptocurrency price drop, we would use the function EnterShort() to open the position (sell order) and function ExitShort() to close the position (buy order).

The complete code of this Crossover strategy will look as follows:

using Signals.Indicators.SMA;
using Signals.DataSeries.Bars;
using Signals.Framework;
public class MyStrategy : SingleMarketStrategy
{
private Bars hourlyBars;
private SMA smaSlow;
private SMA smaFast;
public override void Setup(DataMarketplace data, IndicatorsMarketplace indicators)
{
hourlyBars = data.Bars(BarPeriodType.Hour, 1).WithOffset(25);
smaSlow = indicators.SMA(25).OnSeries(hourlyBars.Close);
smaFast = indicators.SMA(10).OnSeries(hourlyBars.Close);
}
public override void RegisterActions()
{
OnUpdateOf(hourlyBars).Do(() =>
{
if (smaFast.Value > smaSlow.Value && !Position.InPosition)
{
EnterLong();
}
else if (smaFast.Value < smaSlow.Value && Position.InPosition)
{
ExitLong();
}
}
);
}
}