Стратегия Random Trailing Stop
Стратегия Random Trailing Stop открывает случайные сделки с уклоном по простой скользящей средней и управляет ими с помощью трейлинг-стопа.
Детали
- Критерий входа: случайное направление с уклоном от SMA
- Длин/Шорт: обе стороны
- Критерий выхода: трейлинг-стоп
- Стопы: да
- Значения по умолчанию:
MinStopLevel= 0.00036TrailingStep= 0.00001SleepMinutes= 5SmaPeriod= 100Volume= 0.1
- Фильтры:
- Категория: Экспериментальная
- Направление: Обе стороны
- Индикаторы: SMA
- Стопы: Да
- Сложность: Базовая
- Таймфрейм: 1m
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Высокий
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Random entry strategy with trailing stop management.
/// Biases trade direction using SMA trend filter.
/// </summary>
public class RandomTrailingStopStrategy : Strategy
{
private readonly StrategyParam<decimal> _minStopLevel;
private readonly StrategyParam<decimal> _trailingStep;
private readonly StrategyParam<int> _sleepBars;
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<DataType> _candleType;
private int _barsSinceLastTrade;
private decimal? _stopPrice;
public decimal MinStopLevel { get => _minStopLevel.Value; set => _minStopLevel.Value = value; }
public decimal TrailingStep { get => _trailingStep.Value; set => _trailingStep.Value = value; }
public int SleepBars { get => _sleepBars.Value; set => _sleepBars.Value = value; }
public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public RandomTrailingStopStrategy()
{
_minStopLevel = Param(nameof(MinStopLevel), 0.5m)
.SetGreaterThanZero()
.SetDisplay("Min Stop %", "Minimal stop distance percent", "Trading");
_trailingStep = Param(nameof(TrailingStep), 0.1m)
.SetGreaterThanZero()
.SetDisplay("Trailing Step %", "Trailing stop adjustment step percent", "Trading");
_sleepBars = Param(nameof(SleepBars), 20)
.SetGreaterThanZero()
.SetDisplay("Sleep Bars", "Pause before next trade in bars", "General");
_smaPeriod = Param(nameof(SmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "Simple moving average period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_barsSinceLastTrade = 0;
_stopPrice = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = SmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(sma, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
DrawIndicator(area, sma);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
_barsSinceLastTrade++;
if (Position == 0)
{
if (_barsSinceLastTrade < SleepBars)
return;
_stopPrice = null;
var side = GetRandomSide(candle, smaValue);
if (side == Sides.Buy)
BuyMarket();
else
SellMarket();
_barsSinceLastTrade = 0;
return;
}
var stopDist = candle.ClosePrice * MinStopLevel / 100m;
var trailDist = candle.ClosePrice * TrailingStep / 100m;
if (_stopPrice == null)
{
if (Position > 0)
_stopPrice = candle.ClosePrice - stopDist;
else
_stopPrice = candle.ClosePrice + stopDist;
return;
}
if (Position > 0)
{
var newStop = candle.ClosePrice - stopDist;
if (newStop - _stopPrice >= trailDist)
_stopPrice = newStop;
if (candle.LowPrice <= _stopPrice)
{
SellMarket();
_barsSinceLastTrade = 0;
}
}
else if (Position < 0)
{
var newStop = candle.ClosePrice + stopDist;
if (_stopPrice - newStop >= trailDist)
_stopPrice = newStop;
if (candle.HighPrice >= _stopPrice)
{
BuyMarket();
_barsSinceLastTrade = 0;
}
}
}
private Sides GetRandomSide(ICandleMessage candle, decimal smaValue)
{
var rnd = (int)(Math.Abs(candle.OpenTime.Ticks) % 5);
if (candle.ClosePrice > smaValue)
return rnd == 0 ? Sides.Sell : Sides.Buy;
else
return rnd == 1 ? Sides.Buy : Sides.Sell;
}
}
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, Sides
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class random_trailing_stop_strategy(Strategy):
def __init__(self):
super(random_trailing_stop_strategy, self).__init__()
self._min_stop_level = self.Param("MinStopLevel", 0.5) \
.SetGreaterThanZero() \
.SetDisplay("Min Stop %", "Minimal stop distance percent", "Trading")
self._trailing_step = self.Param("TrailingStep", 0.1) \
.SetGreaterThanZero() \
.SetDisplay("Trailing Step %", "Trailing stop adjustment step percent", "Trading")
self._sleep_bars = self.Param("SleepBars", 20) \
.SetGreaterThanZero() \
.SetDisplay("Sleep Bars", "Pause before next trade in bars", "General")
self._sma_period = self.Param("SmaPeriod", 50) \
.SetGreaterThanZero() \
.SetDisplay("SMA Period", "Simple moving average period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._bars_since_last_trade = 0
self._stop_price = None
@property
def min_stop_level(self):
return self._min_stop_level.Value
@property
def trailing_step(self):
return self._trailing_step.Value
@property
def sleep_bars(self):
return self._sleep_bars.Value
@property
def sma_period(self):
return self._sma_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(random_trailing_stop_strategy, self).OnReseted()
self._bars_since_last_trade = 0
self._stop_price = None
def OnStarted2(self, time):
super(random_trailing_stop_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self.sma_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
self.DrawIndicator(area, sma)
def process_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
self._bars_since_last_trade += 1
close = float(candle.ClosePrice)
sma_val = float(sma_value)
if self.Position == 0:
if self._bars_since_last_trade < self.sleep_bars:
return
self._stop_price = None
side = self._get_random_side(candle, sma_val)
if side == Sides.Buy:
self.BuyMarket()
else:
self.SellMarket()
self._bars_since_last_trade = 0
return
stop_dist = close * float(self.min_stop_level) / 100.0
trail_dist = close * float(self.trailing_step) / 100.0
if self._stop_price is None:
if self.Position > 0:
self._stop_price = close - stop_dist
else:
self._stop_price = close + stop_dist
return
if self.Position > 0:
new_stop = close - stop_dist
if new_stop - self._stop_price >= trail_dist:
self._stop_price = new_stop
if float(candle.LowPrice) <= self._stop_price:
self.SellMarket()
self._bars_since_last_trade = 0
elif self.Position < 0:
new_stop = close + stop_dist
if self._stop_price - new_stop >= trail_dist:
self._stop_price = new_stop
if float(candle.HighPrice) >= self._stop_price:
self.BuyMarket()
self._bars_since_last_trade = 0
def _get_random_side(self, candle, sma_value):
rnd = int(abs(candle.OpenTime.Ticks)) % 5
if float(candle.ClosePrice) > sma_value:
return Sides.Sell if rnd == 0 else Sides.Buy
else:
return Sides.Buy if rnd == 1 else Sides.Sell
def CreateClone(self):
return random_trailing_stop_strategy()