Стратегия StepMA NRTR
Трендовая стратегия, основанная на индикаторе StepMA NRTR. Индикатор объединяет ступенчатое скользящее среднее и механизм разворота Nick Rar Trend, формируя сигналы на покупку или продажу при смене тренда.
Детали
- Вход: сигнал индикатора StepMA NRTR
- Длинные/Короткие: обе стороны
- Выход: противоположный сигнал StepMA NRTR
- Стопы: отсутствуют
- Значения по умолчанию:
Length= 10Kv= 1StepSize= 0UseHighLow= trueCandleType= таймфрейм 1 часBuyPosOpen= trueSellPosOpen= trueBuyPosClose= trueSellPosClose= true
- Фильтры:
- Категория: Trend
- Направление: Обе
- Индикаторы: StepMA NRTR
- Стопы: Нет
- Сложность: Средняя
- Таймфрейм: Внутридневной
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// StepMA NRTR trend-following strategy.
/// </summary>
public class StepMaNrtrStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<decimal> _kv;
private readonly StrategyParam<int> _stepSize;
private readonly StrategyParam<bool> _useHighLow;
private readonly StrategyParam<DataType> _candleType;
private readonly Queue<decimal> _ranges = new();
private decimal _smax1;
private decimal _smin1;
private int _trend1;
private bool _first = true;
public int Length { get => _length.Value; set => _length.Value = value; }
public decimal Kv { get => _kv.Value; set => _kv.Value = value; }
public int StepSize { get => _stepSize.Value; set => _stepSize.Value = value; }
public bool UseHighLow { get => _useHighLow.Value; set => _useHighLow.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public StepMaNrtrStrategy()
{
_length = Param(nameof(Length), 10)
.SetGreaterThanZero()
.SetDisplay("Length", "Volatility length", "Indicator");
_kv = Param(nameof(Kv), 1m)
.SetDisplay("Sensitivity", "Sensitivity factor", "Indicator");
_stepSize = Param(nameof(StepSize), 0)
.SetDisplay("Step Size", "Constant step size, 0 - auto", "Indicator");
_useHighLow = Param(nameof(UseHighLow), true)
.SetDisplay("Use High/Low", "Use high/low range", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type for processing", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_ranges.Clear();
_smax1 = 0;
_smin1 = 0;
_trend1 = 0;
_first = true;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var warmup = new ExponentialMovingAverage { Length = Length };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(warmup, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal _warmupVal)
{
if (candle.State != CandleStates.Finished)
return;
var range = candle.HighPrice - candle.LowPrice;
_ranges.Enqueue(range);
if (_ranges.Count > Length)
_ranges.Dequeue();
if (_ranges.Count < Length)
return;
decimal step;
if (StepSize == 0)
{
var atrMax = _ranges.Max();
var atrMin = _ranges.Min();
step = 0.5m * Kv * (atrMax + atrMin);
}
else
step = Kv * StepSize;
if (step == 0)
return;
var sizeP = step;
var size2P = 2m * step;
if (_first)
{
_trend1 = 0;
_smax1 = candle.LowPrice + size2P;
_smin1 = candle.HighPrice - size2P;
_first = false;
}
decimal smax0, smin0;
if (UseHighLow)
{
smax0 = candle.LowPrice + size2P;
smin0 = candle.HighPrice - size2P;
}
else
{
smax0 = candle.ClosePrice + size2P;
smin0 = candle.ClosePrice - size2P;
}
var trend0 = _trend1;
if (candle.ClosePrice > _smax1)
trend0 = 1;
else if (candle.ClosePrice < _smin1)
trend0 = -1;
if (trend0 > 0)
{
if (smin0 < _smin1)
smin0 = _smin1;
}
else
{
if (smax0 > _smax1)
smax0 = _smax1;
}
var buySignal = trend0 > 0 && _trend1 < 0;
var sellSignal = trend0 < 0 && _trend1 > 0;
if (IsFormedAndOnlineAndAllowTrading())
{
if (buySignal && Position <= 0)
BuyMarket();
else if (sellSignal && Position >= 0)
SellMarket();
}
_smax1 = smax0;
_smin1 = smin0;
_trend1 = trend0;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class step_ma_nrtr_strategy(Strategy):
def __init__(self):
super(step_ma_nrtr_strategy, self).__init__()
self._length = self.Param("Length", 10) \
.SetDisplay("Length", "Volatility length", "Indicator")
self._kv = self.Param("Kv", 1.0) \
.SetDisplay("Sensitivity", "Sensitivity factor", "Indicator")
self._step_size = self.Param("StepSize", 0) \
.SetDisplay("Step Size", "Constant step size, 0 - auto", "Indicator")
self._use_high_low = self.Param("UseHighLow", True) \
.SetDisplay("Use High/Low", "Use high/low range", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type for processing", "General")
self._ranges = []
self._smax1 = 0.0
self._smin1 = 0.0
self._trend1 = 0
self._first = True
@property
def length(self):
return self._length.Value
@property
def kv(self):
return self._kv.Value
@property
def step_size(self):
return self._step_size.Value
@property
def use_high_low(self):
return self._use_high_low.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(step_ma_nrtr_strategy, self).OnReseted()
self._ranges = []
self._smax1 = 0.0
self._smin1 = 0.0
self._trend1 = 0
self._first = True
def OnStarted2(self, time):
super(step_ma_nrtr_strategy, self).OnStarted2(time)
warmup = ExponentialMovingAverage()
warmup.Length = self.length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(warmup, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle, _warmup_val):
if candle.State != CandleStates.Finished:
return
h = float(candle.HighPrice)
l = float(candle.LowPrice)
c = float(candle.ClosePrice)
rng = h - l
self._ranges.append(rng)
if len(self._ranges) > self.length:
self._ranges.pop(0)
if len(self._ranges) < self.length:
return
kv = float(self.kv)
if self.step_size == 0:
atr_max = max(self._ranges)
atr_min = min(self._ranges)
step = 0.5 * kv * (atr_max + atr_min)
else:
step = kv * float(self.step_size)
if step == 0:
return
size2p = 2.0 * step
if self._first:
self._trend1 = 0
self._smax1 = l + size2p
self._smin1 = h - size2p
self._first = False
if self.use_high_low:
smax0 = l + size2p
smin0 = h - size2p
else:
smax0 = c + size2p
smin0 = c - size2p
trend0 = self._trend1
if c > self._smax1:
trend0 = 1
elif c < self._smin1:
trend0 = -1
if trend0 > 0:
if smin0 < self._smin1:
smin0 = self._smin1
else:
if smax0 > self._smax1:
smax0 = self._smax1
buy_signal = trend0 > 0 and self._trend1 < 0
sell_signal = trend0 < 0 and self._trend1 > 0
if buy_signal and self.Position <= 0:
self.BuyMarket()
elif sell_signal and self.Position >= 0:
self.SellMarket()
self._smax1 = smax0
self._smin1 = smin0
self._trend1 = trend0
def CreateClone(self):
return step_ma_nrtr_strategy()