Открыть на GitHub

Стратегия Nina EA

Обзор

Стратегия Nina EA — это трендовая система с единственной позицией, перенесённая из эксперта MetaTrader 4 «NinaEA». В оригинальной версии используется пользовательский индикатор NINA: робот вычисляет разницу между его бычьим и медвежьим буферами и открывает сделки, когда знак этой разницы меняется. В реализации на StockSharp индикатор заменён на встроенный SuperTrend, который также предоставляет отдельные буферы для направлений тренда. Переворот SuperTrend выступает аналогом нулевого пересечения: при смене тренда на бычий стратегия покупает, при смене на медвежий — продаёт.

Стратегия удерживает только одну позицию. Противоположный сигнал немедленно закрывает текущую сделку и открывает новую в обратном направлении. Дополнительно можно задать стоп-лосс в ценовых пунктах, что соответствует параметру StopLoss в оригинальном эксперте.

Логика торговли

  1. Подписаться на выбранный тип свечей и рассчитать SuperTrend с указанными периодом и множителем ATR.
  2. Дождаться, когда стратегия и индикатор будут сформированы, прежде чем реагировать на сигналы.
  3. На каждой завершённой свече:
    • Если цена достигает защитного стопа, закрыть позицию рыночной заявкой.
    • Если SuperTrend меняется с медвежьего на бычий, закрыть шорт (если он есть) и открыть лонг заданным объёмом.
    • Если SuperTrend меняется с бычьего на медвежий, закрыть лонг и открыть шорт.
    • Сохранить текущее направление тренда для фиксации следующего переворота.

Так воспроизводится логика MetaTrader, где выражение nina = Buffer0 - Buffer1 и изменение его знака управляют выходами и входами.

Управление позицией и рисками

  • Одновременно активна только одна позиция; система всегда разворачивается, а не наращивает объём.
  • Необязательный стоп-лосс в пунктах рассчитывается от цены входа: для лонга стоп ставится ниже, для шорта — выше. Нулевое значение отключает стоп.
  • Вызов StartProtection() позволяет при необходимости подключить встроенные защитные механизмы StockSharp.

Параметры

Параметр Значение по умолчанию Описание
Volume 0.1 Объём заявки для каждого нового входа.
AtrPeriod 10 Период ATR, передаваемый в SuperTrend (соответствует PeriodWATR).
AtrMultiplier 1 Множитель ATR для SuperTrend (соответствует Kwatr).
StopLossPoints 0 Дистанция стоп-лосса в пунктах. Ноль отключает стоп, как и в оригинале, где заявки выставлялись без стоп-цены.
CandleType TimeFrame(1 minute) Тип свечей, по которым работает стратегия.

Особенности конвертации

  • Пользовательский индикатор NINA заменён на SuperTrend, так как стратегии важен только знак разницы между двумя буферами. Свойство IsUpTrend у SuperTrend даёт ту же информацию без обращения к низкоуровневым буферам.
  • Логика закрытия ордеров повторяет цикл OrdersTotal() из исходника: при смене знака сначала закрывается текущая позиция, затем открывается новая в противоположном направлении.
  • Параметры MetaTrader (highlow, cbars, from, maP, SMAspread, Slippage), не влияющие на торговлю в исходном коде, опущены.

Рекомендации по использованию

  1. Запустите стратегию на нужном инструменте и выберите таймфрейм свечей, соответствующий тестам в MetaTrader.
  2. Настройте параметры ATR, чтобы приблизить поведение к оригинальному индикатору.
  3. Установите StopLossPoints, если нужен жёсткий ограничитель убытков; оставьте значение 0, чтобы полагаться только на сигналы.
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;
	}
}