Ver en GitHub

Nina EA Strategy

Overview

The Nina EA strategy is a one-position trend follower converted from the MetaTrader 4 expert "NinaEA". The original robot uses a custom indicator named NINA and trades whenever the difference between the indicator's bullish and bearish buffers crosses above or below zero. In the StockSharp version the custom indicator is replaced with the built-in SuperTrend indicator, which also publishes separate bullish and bearish buffers. A flip in SuperTrend direction serves as the zero-crossing proxy: when the trend turns bullish the strategy buys, and when it turns bearish it sells.

The strategy always keeps at most one open position. An opposite signal immediately closes the existing position and establishes a new trade in the new direction. An optional stop-loss expressed in price points can be enabled to mimic the original "StopLoss" input.

Trading Logic

  1. Subscribe to the configured candle series and calculate SuperTrend with the supplied ATR period and multiplier.
  2. Wait until both the strategy and the indicator are formed before reacting to signals.
  3. On every completed candle:
    • If a protective stop price is touched, exit the open position at market.
    • If SuperTrend flips from bearish to bullish, close any short exposure and buy with the configured volume.
    • If SuperTrend flips from bullish to bearish, close any long exposure and sell with the configured volume.
    • Store the current SuperTrend direction to detect the next flip.

The logic replicates the MetaTrader expert's behavior, where nina = Buffer0 - Buffer1 and a sign change drives both exits and new entries.

Position and Risk Management

  • Only a single position can be active at a time; all trades reverse the direction rather than stacking multiple orders.
  • An optional stop-loss in price points is calculated from the fill price. For a long trade the stop is placed below the entry, and for a short trade it is placed above the entry. Setting the parameter to zero disables the stop.
  • StartProtection() is called so that built-in StockSharp protections can be configured if desired.

Parameters

Parameter Default Description
Volume 0.1 Order volume used for every new entry.
AtrPeriod 10 ATR period passed to the SuperTrend calculation (maps the original PeriodWATR).
AtrMultiplier 1 ATR multiplier for SuperTrend (maps the original Kwatr).
StopLossPoints 0 Optional stop-loss distance in price points. Zero keeps the stop disabled, identical to the MetaTrader code that sent market orders without a stop price.
CandleType TimeFrame(1 minute) Candle series that feeds the indicator and trading logic.

Conversion Notes

  • The MetaTrader expert relied on the custom NINA indicator. Its two buffers were interpreted as bullish/bearish SuperTrend lines because only their difference and sign mattered for trading. SuperTrend exposes the same information through its IsUpTrend flag, which makes it a suitable high-level replacement requiring no manual buffer handling.
  • Order closing logic mirrors the OrdersTotal() loop from the original script: a trend flip first flatters the current position and then opens a trade in the new direction.
  • The unused MetaTrader inputs (highlow, cbars, from, maP, SMAspread, Slippage) are omitted because they do not influence the trading rules in the original file.

Usage Tips

  1. Attach the strategy to a security and configure the candle timeframe that matches your MetaTrader test.
  2. Tune the ATR period and multiplier to replicate the behaviour of the original indicator.
  3. Increase StopLossPoints if you want a hard risk limit; otherwise leave it at zero for pure signal-based exits.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// SuperTrend-based strategy from NinaEA.
/// Trades on SuperTrend direction flips - buy on up trend, sell on down trend.
/// </summary>
public class NinaEaStrategy : Strategy
{
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _atrMultiplier;
	private readonly StrategyParam<DataType> _candleType;

	private bool? _previousTrendUp;

	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public decimal AtrMultiplier { get => _atrMultiplier.Value; set => _atrMultiplier.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public NinaEaStrategy()
	{
		_atrPeriod = Param(nameof(AtrPeriod), 10)
			.SetDisplay("ATR Period", "ATR length for SuperTrend", "Indicators");

		_atrMultiplier = Param(nameof(AtrMultiplier), 1m)
			.SetDisplay("ATR Multiplier", "SuperTrend multiplier", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_previousTrendUp = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_previousTrendUp = null;

		var superTrend = new SuperTrend
		{
			Length = AtrPeriod,
			Multiplier = AtrMultiplier
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(superTrend, ProcessCandle)
			.Start();
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue superTrendValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!superTrendValue.IsFinal)
			return;

		var stValue = (SuperTrendIndicatorValue)superTrendValue;
		var isUpTrend = stValue.IsUpTrend;

		if (_previousTrendUp is bool prevUp)
		{
			// Trend flipped to up - go long
			if (isUpTrend && !prevUp)
			{
				if (Position < 0)
					BuyMarket();
				if (Position <= 0)
					BuyMarket();
			}
			// Trend flipped to down - go short
			else if (!isUpTrend && prevUp)
			{
				if (Position > 0)
					SellMarket();
				if (Position >= 0)
					SellMarket();
			}
		}

		_previousTrendUp = isUpTrend;
	}
}