Estrategia AI SuperTrend
La estrategia AI SuperTrend combina el indicador SuperTrend con medias móviles ponderadas del precio y de la línea SuperTrend. Se abre una operación larga cuando el SuperTrend gira hacia arriba y la WMA del precio se mueve por encima de la WMA del SuperTrend. Se abre una operación corta en las condiciones opuestas. Las posiciones están protegidas con un trailing stop dinámico basado en ATR.
Detalles
- Criterios de entrada:
- Largo: La dirección de SuperTrend cambia hacia arriba y la WMA del precio está por encima de la WMA del SuperTrend.
- Corto: La dirección de SuperTrend cambia hacia abajo y la WMA del precio está por debajo de la WMA del SuperTrend.
- Criterios de salida:
- Reversión de tendencia o trailing stop ATR.
- Stops: Trailing stop ATR dinámico.
- Valores predeterminados:
AtrPeriod= 10AtrFactor= 3PriceWmaLength= 20SuperWmaLength= 100EnableLong= trueEnableShort= true
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: SuperTrend, WMA, ATR
- Stops: Sí
- Complejidad: Moderado
- Marco temporal: Cualquiera
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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>
/// AI SuperTrend strategy.
/// Goes long when the SuperTrend flips up while the WMA of price is above the WMA of the SuperTrend line, and short on the
/// mirrored setup, reversing an opposite position. A position is closed when the SuperTrend turns against it or when price
/// hits an ATR trailing stop that follows the close at AtrFactor times ATR.
/// </summary>
public class AiSuperTrendStrategy : Strategy
{
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrFactor;
private readonly StrategyParam<int> _priceWmaLength;
private readonly StrategyParam<int> _superWmaLength;
private readonly StrategyParam<bool> _enableLong;
private readonly StrategyParam<bool> _enableShort;
private readonly StrategyParam<DataType> _candleType;
private WeightedMovingAverage _superWma;
private bool? _prevIsUpTrend;
private decimal _trailingStop;
/// <summary>
/// ATR period of the SuperTrend and the trailing stop.
/// </summary>
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
/// <summary>
/// ATR multiplier of the SuperTrend and the trailing stop.
/// </summary>
public decimal AtrFactor
{
get => _atrFactor.Value;
set => _atrFactor.Value = value;
}
/// <summary>
/// Period of the price WMA.
/// </summary>
public int PriceWmaLength
{
get => _priceWmaLength.Value;
set => _priceWmaLength.Value = value;
}
/// <summary>
/// Period of the WMA of the SuperTrend line.
/// </summary>
public int SuperWmaLength
{
get => _superWmaLength.Value;
set => _superWmaLength.Value = value;
}
/// <summary>
/// Allow long entries.
/// </summary>
public bool EnableLong
{
get => _enableLong.Value;
set => _enableLong.Value = value;
}
/// <summary>
/// Allow short entries.
/// </summary>
public bool EnableShort
{
get => _enableShort.Value;
set => _enableShort.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AiSuperTrendStrategy()
{
_atrPeriod = Param(nameof(AtrPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period of the SuperTrend and the trailing stop", "SuperTrend");
_atrFactor = Param(nameof(AtrFactor), 3m)
.SetGreaterThanZero()
.SetDisplay("ATR Factor", "ATR multiplier of the SuperTrend and the trailing stop", "SuperTrend");
_priceWmaLength = Param(nameof(PriceWmaLength), 20)
.SetGreaterThanZero()
.SetDisplay("Price WMA Length", "Period of the price WMA", "Filter");
_superWmaLength = Param(nameof(SuperWmaLength), 100)
.SetGreaterThanZero()
.SetDisplay("SuperTrend WMA Length", "Period of the WMA of the SuperTrend line", "Filter");
_enableLong = Param(nameof(EnableLong), true)
.SetDisplay("Enable Long", "Allow long entries", "Trading");
_enableShort = Param(nameof(EnableShort), true)
.SetDisplay("Enable Short", "Allow short entries", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_superWma = null;
_prevIsUpTrend = null;
_trailingStop = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevIsUpTrend = null;
_trailingStop = 0m;
var superTrend = new SuperTrend { Length = AtrPeriod, Multiplier = AtrFactor };
var priceWma = new WeightedMovingAverage { Length = PriceWmaLength };
var atr = new AverageTrueRange { Length = AtrPeriod };
_superWma = new WeightedMovingAverage { Length = SuperWmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(superTrend, priceWma, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, superTrend);
DrawIndicator(area, priceWma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue superTrendValue, IIndicatorValue priceWmaValue, IIndicatorValue atrValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!superTrendValue.IsFormed || superTrendValue is not SuperTrendIndicatorValue st)
return;
var superWma = _superWma.Process(st.ToDecimal(), candle.ServerTime, true).ToDecimal();
var isUpTrend = st.IsUpTrend;
var prevIsUpTrend = _prevIsUpTrend;
_prevIsUpTrend = isUpTrend;
if (prevIsUpTrend is not bool prevUp || !priceWmaValue.IsFormed || !atrValue.IsFormed || !_superWma.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var priceWma = priceWmaValue.ToDecimal();
var atr = atrValue.ToDecimal();
var close = candle.ClosePrice;
var distance = AtrFactor * atr;
var flipUp = !prevUp && isUpTrend;
var flipDown = prevUp && !isUpTrend;
if (EnableLong && flipUp && priceWma > superWma && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_trailingStop = close - distance;
}
else if (EnableShort && flipDown && priceWma < superWma && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_trailingStop = close + distance;
}
else if (Position > 0)
{
if (candle.LowPrice <= _trailingStop || !isUpTrend)
SellMarket(Position);
else
_trailingStop = Math.Max(_trailingStop, close - distance);
}
else if (Position < 0)
{
if (candle.HighPrice >= _trailingStop || isUpTrend)
BuyMarket(-Position);
else
_trailingStop = Math.Min(_trailingStop, close + distance);
}
}
}
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 SuperTrend, WeightedMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class ai_super_trend_strategy(Strategy):
"""
AI SuperTrend strategy.
Goes long when the SuperTrend flips up while the WMA of price is above the WMA of the SuperTrend line, and short on the
mirrored setup, reversing an opposite position. A position is closed when the SuperTrend turns against it or when price
hits an ATR trailing stop that follows the close at AtrFactor times ATR.
"""
def __init__(self):
super(ai_super_trend_strategy, self).__init__()
self._atr_period = self.Param("AtrPeriod", 10) \
.SetGreaterThanZero() \
.SetDisplay("ATR Period", "ATR period of the SuperTrend and the trailing stop", "SuperTrend")
self._atr_factor = self.Param("AtrFactor", 3.0) \
.SetGreaterThanZero() \
.SetDisplay("ATR Factor", "ATR multiplier of the SuperTrend and the trailing stop", "SuperTrend")
self._price_wma_length = self.Param("PriceWmaLength", 20) \
.SetGreaterThanZero() \
.SetDisplay("Price WMA Length", "Period of the price WMA", "Filter")
self._super_wma_length = self.Param("SuperWmaLength", 100) \
.SetGreaterThanZero() \
.SetDisplay("SuperTrend WMA Length", "Period of the WMA of the SuperTrend line", "Filter")
self._enable_long = self.Param("EnableLong", True) \
.SetDisplay("Enable Long", "Allow long entries", "Trading")
self._enable_short = self.Param("EnableShort", True) \
.SetDisplay("Enable Short", "Allow short entries", "Trading")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._super_wma = None
self._prev_is_up_trend = None
self._trailing_stop = 0.0
@property
def CandleType(self):
return self._candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType)]
def OnReseted(self):
super(ai_super_trend_strategy, self).OnReseted()
self._super_wma = None
self._prev_is_up_trend = None
self._trailing_stop = 0.0
def OnStarted2(self, time):
super(ai_super_trend_strategy, self).OnStarted2(time)
self._prev_is_up_trend = None
self._trailing_stop = 0.0
super_trend = SuperTrend()
super_trend.Length = self._atr_period.Value
super_trend.Multiplier = self._atr_factor.Value
price_wma = WeightedMovingAverage()
price_wma.Length = self._price_wma_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_period.Value
self._super_wma = WeightedMovingAverage()
self._super_wma.Length = self._super_wma_length.Value
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(super_trend, price_wma, atr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, super_trend)
self.DrawIndicator(area, price_wma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, super_trend_value, price_wma_value, atr_value):
if candle.State != CandleStates.Finished:
return
if not super_trend_value.IsFormed:
return
super_line = float(to_decimal(super_trend_value))
super_wma = float(to_decimal(process_float(self._super_wma, super_line, candle.ServerTime, True)))
is_up_trend = bool(super_trend_value.IsUpTrend)
prev_up = self._prev_is_up_trend
self._prev_is_up_trend = is_up_trend
if prev_up is None or not price_wma_value.IsFormed or not atr_value.IsFormed or not self._super_wma.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
price_wma = float(to_decimal(price_wma_value))
atr = float(to_decimal(atr_value))
close = float(candle.ClosePrice)
distance = float(self._atr_factor.Value) * atr
flip_up = not prev_up and is_up_trend
flip_down = prev_up and not is_up_trend
if self._enable_long.Value and flip_up and price_wma > super_wma and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._trailing_stop = close - distance
elif self._enable_short.Value and flip_down and price_wma < super_wma and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._trailing_stop = close + distance
elif self.Position > 0:
if float(candle.LowPrice) <= self._trailing_stop or not is_up_trend:
self.SellMarket(self.Position)
else:
self._trailing_stop = max(self._trailing_stop, close - distance)
elif self.Position < 0:
if float(candle.HighPrice) >= self._trailing_stop or is_up_trend:
self.BuyMarket(-self.Position)
else:
self._trailing_stop = min(self._trailing_stop, close + distance)
def CreateClone(self):
return ai_super_trend_strategy()