Стратегия Nina EA — это трендовая система с единственной позицией, перенесённая из эксперта MetaTrader 4 «NinaEA». В оригинальной версии используется пользовательский индикатор NINA: робот вычисляет разницу между его бычьим и медвежьим буферами и открывает сделки, когда знак этой разницы меняется. В реализации на StockSharp индикатор заменён на встроенный SuperTrend, который также предоставляет отдельные буферы для направлений тренда. Переворот SuperTrend выступает аналогом нулевого пересечения: при смене тренда на бычий стратегия покупает, при смене на медвежий — продаёт.
Стратегия удерживает только одну позицию. Противоположный сигнал немедленно закрывает текущую сделку и открывает новую в обратном направлении. Дополнительно можно задать стоп-лосс в ценовых пунктах, что соответствует параметру StopLoss в оригинальном эксперте.
Логика торговли
Подписаться на выбранный тип свечей и рассчитать SuperTrend с указанными периодом и множителем ATR.
Дождаться, когда стратегия и индикатор будут сформированы, прежде чем реагировать на сигналы.
На каждой завершённой свече:
Если цена достигает защитного стопа, закрыть позицию рыночной заявкой.
Если 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), не влияющие на торговлю в исходном коде, опущены.
Рекомендации по использованию
Запустите стратегию на нужном инструменте и выберите таймфрейм свечей, соответствующий тестам в MetaTrader.
Настройте параметры ATR, чтобы приблизить поведение к оригинальному индикатору.
Установите 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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SuperTrend
from StockSharp.Algo.Strategies import Strategy
class nina_ea_strategy(Strategy):
"""SuperTrend-based strategy. Trades on SuperTrend direction flips.
Go long on up trend, go short on down trend."""
def __init__(self):
super(nina_ea_strategy, self).__init__()
self._atr_period = self.Param("AtrPeriod", 10) \
.SetDisplay("ATR Period", "ATR length for SuperTrend", "Indicators")
self._atr_multiplier = self.Param("AtrMultiplier", 1.0) \
.SetDisplay("ATR Multiplier", "SuperTrend multiplier", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._previous_trend_up = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def AtrPeriod(self):
return self._atr_period.Value
@property
def AtrMultiplier(self):
return self._atr_multiplier.Value
def OnReseted(self):
super(nina_ea_strategy, self).OnReseted()
self._previous_trend_up = None
def OnStarted2(self, time):
super(nina_ea_strategy, self).OnStarted2(time)
self._previous_trend_up = None
super_trend = SuperTrend()
super_trend.Length = self.AtrPeriod
super_trend.Multiplier = self.AtrMultiplier
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(super_trend, self._process_candle).Start()
def _process_candle(self, candle, super_trend_value):
if candle.State != CandleStates.Finished:
return
if not super_trend_value.IsFinal:
return
is_up_trend = super_trend_value.IsUpTrend if hasattr(super_trend_value, 'IsUpTrend') else None
if is_up_trend is None:
return
if self._previous_trend_up is not None:
prev_up = self._previous_trend_up
# Trend flipped to up - go long
if is_up_trend and not prev_up:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
# Trend flipped to down - go short
elif not is_up_trend and prev_up:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
self._previous_trend_up = is_up_trend
def CreateClone(self):
return nina_ea_strategy()