AI SuperTrend 策略
AI SuperTrend 策略结合 SuperTrend 指标与价格及 SuperTrend 线的加权移动平均。 当 SuperTrend 向上反转且价格 WMA 高于 SuperTrend WMA 时开多仓;相反条件下开空仓。 持仓使用基于 ATR 的动态跟踪止损进行保护。
细节
- 入场条件:
- 多头:SuperTrend 方向转为向上且价格 WMA 高于 SuperTrend WMA。
- 空头:SuperTrend 方向转为向下且价格 WMA 低于 SuperTrend WMA。
- 出场条件:
- 趋势反转或 ATR 跟踪止损。
- 止损:动态 ATR 跟踪止损。
- 默认值:
AtrPeriod= 10AtrFactor= 3PriceWmaLength= 20SuperWmaLength= 100EnableLong= trueEnableShort= true
- 过滤器:
- 类别:趋势跟随
- 方向:双向
- 指标:SuperTrend、WMA、ATR
- 止损:是
- 复杂度:中等
- 时间框架:任意
- 季节性:否
- 神经网络:否
- 背离:否
- 风险等级:中等
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()