Стратегия Magic Wand STSM
Трендовая система, использующая индикатор Supertrend с фильтром SMA200. Торгует по направлению Supertrend и использует его линию как стоп, устанавливая тейк-профит по заданному соотношению риск/прибыль.
Детали
- Условия входа:
- Long: Supertrend ниже цены и закрытие выше SMA200.
- Short: Supertrend выше цены и закрытие ниже SMA200.
- Направление торговли: оба направления.
- Условия выхода:
- Тейк-профит
entry ± (entry - Supertrend) * RiskReward. - Стоп-лосс по линии Supertrend.
- Тейк-профит
- Стопы: да.
- Значения по умолчанию:
Supertrend Period= 10Supertrend Multiplier= 3MA Length= 200Risk Reward= 2
- Фильтры:
- Категория: Trend Following
- Направление: Оба
- Индикаторы: Несколько
- Стопы: Да
- Сложность: Средняя
- Таймфрейм: Внутридневной
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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;
public class MagicWandStsmStrategy : Strategy
{
private readonly StrategyParam<int> _supertrendPeriod;
private readonly StrategyParam<decimal> _supertrendMultiplier;
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<decimal> _riskReward;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private AverageTrueRange _atr;
private SimpleMovingAverage _sma;
private decimal _prevHighest;
private decimal _prevLowest;
private decimal _prevSupertrend;
private decimal _prevClose;
private bool _isFirst;
private decimal _stop;
private decimal _take;
private int _barsFromTrade;
public int SupertrendPeriod { get => _supertrendPeriod.Value; set => _supertrendPeriod.Value = value; }
public decimal SupertrendMultiplier { get => _supertrendMultiplier.Value; set => _supertrendMultiplier.Value = value; }
public int MaLength { get => _maLength.Value; set => _maLength.Value = value; }
public decimal RiskReward { get => _riskReward.Value; set => _riskReward.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MagicWandStsmStrategy()
{
_supertrendPeriod = Param(nameof(SupertrendPeriod), 10);
_supertrendMultiplier = Param(nameof(SupertrendMultiplier), 3m);
_maLength = Param(nameof(MaLength), 50);
_riskReward = Param(nameof(RiskReward), 3m);
_cooldownBars = Param(nameof(CooldownBars), 80);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame());
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_atr = null;
_sma = null;
_prevHighest = 0m;
_prevLowest = 0m;
_prevSupertrend = 0m;
_prevClose = 0m;
_isFirst = true;
_stop = 0m;
_take = 0m;
_barsFromTrade = CooldownBars;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_atr = new AverageTrueRange { Length = SupertrendPeriod };
_sma = new SimpleMovingAverage { Length = MaLength };
_prevHighest = _prevLowest = _prevSupertrend = _prevClose = 0m;
_stop = _take = 0m;
_isFirst = true;
_barsFromTrade = CooldownBars;
var sub = SubscribeCandles(CandleType);
sub.Bind(_atr, _sma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal atrValue, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_atr.IsFormed || !_sma.IsFormed)
return;
var median = (candle.HighPrice + candle.LowPrice) / 2m;
var upperBand = median + SupertrendMultiplier * atrValue;
var lowerBand = median - SupertrendMultiplier * atrValue;
if (_isFirst)
{
_prevHighest = upperBand;
_prevLowest = lowerBand;
_prevSupertrend = candle.ClosePrice <= upperBand ? upperBand : lowerBand;
_prevClose = candle.ClosePrice;
_isFirst = false;
return;
}
var currentUpper = (upperBand < _prevHighest || _prevClose > _prevHighest) ? upperBand : _prevHighest;
var currentLower = (lowerBand > _prevLowest || _prevClose < _prevLowest) ? lowerBand : _prevLowest;
var supertrend = _prevSupertrend == _prevHighest
? (candle.ClosePrice <= currentUpper ? currentUpper : currentLower)
: (candle.ClosePrice >= currentLower ? currentLower : currentUpper);
var isUpTrend = candle.ClosePrice > supertrend;
_barsFromTrade++;
var canEnter = _barsFromTrade >= CooldownBars;
if (Position == 0 && canEnter)
{
if (isUpTrend && candle.ClosePrice > smaValue)
{
BuyMarket();
_stop = supertrend;
_take = candle.ClosePrice + (candle.ClosePrice - _stop) * RiskReward;
_barsFromTrade = 0;
}
else if (!isUpTrend && candle.ClosePrice < smaValue)
{
SellMarket();
_stop = supertrend;
_take = candle.ClosePrice - (_stop - candle.ClosePrice) * RiskReward;
_barsFromTrade = 0;
}
}
else if (Position > 0)
{
if (candle.LowPrice <= _stop || candle.ClosePrice >= _take)
{
SellMarket();
_barsFromTrade = 0;
}
}
else if (Position < 0)
{
if (candle.HighPrice >= _stop || candle.ClosePrice <= _take)
{
BuyMarket();
_barsFromTrade = 0;
}
}
_prevHighest = currentUpper;
_prevLowest = currentLower;
_prevSupertrend = supertrend;
_prevClose = candle.ClosePrice;
}
}
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 AverageTrueRange, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class magic_wand_stsm_strategy(Strategy):
"""
Magic Wand STSM: custom SuperTrend with SMA filter and risk/reward targets.
"""
def __init__(self):
super(magic_wand_stsm_strategy, self).__init__()
self._supertrend_period = self.Param("SupertrendPeriod", 10).SetDisplay("ST Period", "SuperTrend ATR period", "SuperTrend")
self._supertrend_mult = self.Param("SupertrendMultiplier", 3.0).SetDisplay("ST Mult", "SuperTrend multiplier", "SuperTrend")
self._ma_length = self.Param("MaLength", 50).SetDisplay("MA Length", "SMA filter period", "Indicators")
self._risk_reward = self.Param("RiskReward", 3.0).SetDisplay("Risk/Reward", "Risk/reward ratio", "Risk")
self._cooldown_bars = self.Param("CooldownBars", 80).SetDisplay("Cooldown", "Bars between trades", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Candles", "General")
self._prev_highest = 0.0
self._prev_lowest = 0.0
self._prev_supertrend = 0.0
self._prev_close = 0.0
self._is_first = True
self._stop = 0.0
self._take = 0.0
self._bars_from_trade = 80
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(magic_wand_stsm_strategy, self).OnReseted()
self._prev_highest = 0.0
self._prev_lowest = 0.0
self._prev_supertrend = 0.0
self._prev_close = 0.0
self._is_first = True
self._stop = 0.0
self._take = 0.0
self._bars_from_trade = self._cooldown_bars.Value
def OnStarted2(self, time):
super(magic_wand_stsm_strategy, self).OnStarted2(time)
self._prev_highest = 0.0
self._prev_lowest = 0.0
self._prev_supertrend = 0.0
self._prev_close = 0.0
self._is_first = True
self._stop = 0.0
self._take = 0.0
self._atr = AverageTrueRange()
self._atr.Length = self._supertrend_period.Value
self._sma = SimpleMovingAverage()
self._sma.Length = self._ma_length.Value
self._bars_from_trade = self._cooldown_bars.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._atr, self._sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, atr_val, sma_val):
if candle.State != CandleStates.Finished:
return
if not self._atr.IsFormed or not self._sma.IsFormed:
return
atr = float(atr_val)
sma = float(sma_val)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
median = (high + low) / 2.0
mult = float(self._supertrend_mult.Value)
upper_band = median + mult * atr
lower_band = median - mult * atr
if self._is_first:
self._prev_highest = upper_band
self._prev_lowest = lower_band
self._prev_supertrend = upper_band if close <= upper_band else lower_band
self._prev_close = close
self._is_first = False
return
current_upper = upper_band if (upper_band < self._prev_highest or self._prev_close > self._prev_highest) else self._prev_highest
current_lower = lower_band if (lower_band > self._prev_lowest or self._prev_close < self._prev_lowest) else self._prev_lowest
if self._prev_supertrend == self._prev_highest:
supertrend = current_upper if close <= current_upper else current_lower
else:
supertrend = current_lower if close >= current_lower else current_upper
is_up_trend = close > supertrend
self._bars_from_trade += 1
can_enter = self._bars_from_trade >= self._cooldown_bars.Value
rr = float(self._risk_reward.Value)
if self.Position == 0 and can_enter:
if is_up_trend and close > sma:
self.BuyMarket()
self._stop = supertrend
self._take = close + (close - self._stop) * rr
self._bars_from_trade = 0
elif not is_up_trend and close < sma:
self.SellMarket()
self._stop = supertrend
self._take = close - (self._stop - close) * rr
self._bars_from_trade = 0
elif self.Position > 0:
if low <= self._stop or close >= self._take:
self.SellMarket()
self._bars_from_trade = 0
elif self.Position < 0:
if high >= self._stop or close <= self._take:
self.BuyMarket()
self._bars_from_trade = 0
self._prev_highest = current_upper
self._prev_lowest = current_lower
self._prev_supertrend = supertrend
self._prev_close = close
def CreateClone(self):
return magic_wand_stsm_strategy()