ATR-Mean-Reversion-Strategie
Die ATR-Mean-Reversion-Strategie misst, wie weit sich der Preis von einem gleitenden Durchschnitt relativ zur jüngsten Volatilität entfernt. Der ATR bietet eine adaptive Messgröße, sodass sich die Schwellen in aktiven Perioden ausdehnen und sich zusammenziehen, wenn die Märkte ruhig werden.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 109%. Sie funktioniert am besten auf dem Kryptomarkt.
Eine Long-Konfiguration entsteht, wenn der Preis um mehr als Multiplier mal den ATR unter dem gleitenden Durchschnitt schließt. Eine Short-Konfiguration erscheint, wenn der Preis um denselben Abstand über dem gleitenden Durchschnitt schließt. Positionen werden beendet, sobald der Preis zum gleitenden Durchschnitt zurückkehrt.
Diese Technik ist für kurzfristige Trader gedacht, die erwarten, dass die Preise nach übermäßigen Bewegungen umkehren. Der ATR-basierte Stop hält das Risiko proportional zu den aktuellen Marktbedingungen.
Details
- Einstiegskriterien:
- Long: Schluss < MA - Multiplier * ATR
- Short: Schluss > MA + Multiplier * ATR
- Long/Short: Beide Seiten.
- Ausstiegskriterien:
- Long: Ausstieg, wenn Schluss >= MA
- Short: Ausstieg, wenn Schluss <= MA
- Stops: Ja, Stop-Loss standardmäßig bei etwa
2*ATR. - Standardwerte:
MaPeriod= 20AtrPeriod= 14Multiplier= 2.0mCandleType= TimeSpan.FromMinutes(5)
- Filter:
- Kategorie: Mean Reversion
- Richtung: Beide
- Indikatoren: MA, ATR
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Intraday
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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>
/// ATR Mean Reversion strategy.
/// Trades when price deviates from its average by a multiple of ATR.
/// </summary>
public class AtrMeanReversionStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriodParam;
private readonly StrategyParam<int> _atrPeriodParam;
private readonly StrategyParam<decimal> _multiplierParam;
private readonly StrategyParam<DataType> _candleTypeParam;
private SimpleMovingAverage _sma;
private AverageTrueRange _atr;
/// <summary>
/// Moving average period.
/// </summary>
public int MaPeriod
{
get => _maPeriodParam.Value;
set => _maPeriodParam.Value = value;
}
/// <summary>
/// ATR indicator period.
/// </summary>
public int AtrPeriod
{
get => _atrPeriodParam.Value;
set => _atrPeriodParam.Value = value;
}
/// <summary>
/// ATR multiplier for entry threshold.
/// </summary>
public decimal Multiplier
{
get => _multiplierParam.Value;
set => _multiplierParam.Value = value;
}
/// <summary>
/// Candle type for strategy.
/// </summary>
public DataType CandleType
{
get => _candleTypeParam.Value;
set => _candleTypeParam.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AtrMeanReversionStrategy()
{
_maPeriodParam = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Period for Moving Average", "Parameters")
.SetOptimize(10, 50, 10);
_atrPeriodParam = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "Period for ATR indicator", "Parameters")
.SetOptimize(7, 21, 7);
_multiplierParam = Param(nameof(Multiplier), 2.0m)
.SetRange(0.1m, decimal.MaxValue)
.SetDisplay("ATR Multiplier", "ATR multiplier for entry threshold", "Parameters")
.SetOptimize(1.0m, 3.0m, 0.5m);
_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle type for strategy", "Common");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sma = null;
_atr = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
_sma = new SMA { Length = MaPeriod };
_atr = new AverageTrueRange { Length = AtrPeriod };
// Create subscription and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_sma, _atr, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _sma);
DrawIndicator(area, _atr);
DrawOwnTrades(area);
}
// Enable position protection
StartProtection(
takeProfit: new Unit(0, UnitTypes.Absolute), // No take profit
stopLoss: new Unit(2, UnitTypes.Absolute) // Stop loss at 2*ATR
);
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue, decimal atrValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Calculate entry thresholds
var upperThreshold = smaValue + Multiplier * atrValue;
var lowerThreshold = smaValue - Multiplier * atrValue;
// Long setup - price below lower threshold
if (candle.ClosePrice < lowerThreshold && Position <= 0)
{
// Buy signal - price has deviated too much below average
BuyMarket(Volume + Math.Abs(Position));
}
// Short setup - price above upper threshold
else if (candle.ClosePrice > upperThreshold && Position >= 0)
{
// Sell signal - price has deviated too much above average
SellMarket(Volume + Math.Abs(Position));
}
// Exit long position when price returns to average
else if (Position > 0 && candle.ClosePrice >= smaValue)
{
// Close long position
SellMarket(Position);
}
// Exit short position when price returns to average
else if (Position < 0 && candle.ClosePrice <= smaValue)
{
// Close short position
BuyMarket(Math.Abs(Position));
}
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import SimpleMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class atr_mean_reversion_strategy(Strategy):
"""
ATR Mean Reversion strategy.
Trades when price deviates from its average by a multiple of ATR.
"""
def __init__(self):
super(atr_mean_reversion_strategy, self).__init__()
# Initialize strategy parameters
self._maPeriod = self.Param("MaPeriod", 20) \
.SetDisplay("MA Period", "Period for Moving Average", "Parameters") \
.SetCanOptimize(True) \
.SetOptimize(10, 50, 10)
self._atrPeriod = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "Period for ATR indicator", "Parameters") \
.SetCanOptimize(True) \
.SetOptimize(7, 21, 7)
self._multiplier = self.Param("Multiplier", 2.0) \
.SetRange(0.1, float('inf')) \
.SetDisplay("ATR Multiplier", "ATR multiplier for entry threshold", "Parameters") \
.SetCanOptimize(True) \
.SetOptimize(1.0, 3.0, 0.5)
self._candleType = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Candle type for strategy", "Common")
# Indicators
self._sma = None
self._atr = None
@property
def MaPeriod(self):
"""Moving average period."""
return self._maPeriod.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._maPeriod.Value = value
@property
def AtrPeriod(self):
"""ATR indicator period."""
return self._atrPeriod.Value
@AtrPeriod.setter
def AtrPeriod(self, value):
self._atrPeriod.Value = value
@property
def Multiplier(self):
"""ATR multiplier for entry threshold."""
return self._multiplier.Value
@Multiplier.setter
def Multiplier(self, value):
self._multiplier.Value = value
@property
def CandleType(self):
"""Candle type for strategy."""
return self._candleType.Value
@CandleType.setter
def CandleType(self, value):
self._candleType.Value = value
def OnReseted(self):
super(atr_mean_reversion_strategy, self).OnReseted()
self._sma = None
self._atr = None
def OnStarted2(self, time):
super(atr_mean_reversion_strategy, self).OnStarted2(time)
# Create indicators
self._sma = SimpleMovingAverage()
self._sma.Length = self.MaPeriod
self._atr = AverageTrueRange()
self._atr.Length = self.AtrPeriod
# Create subscription and bind indicators
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._sma, self._atr, self.ProcessCandle).Start()
# Setup chart visualization if available
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._sma)
self.DrawIndicator(area, self._atr)
self.DrawOwnTrades(area)
# Enable position protection
self.StartProtection(
takeProfit=Unit(0, UnitTypes.Absolute),
stopLoss=Unit(2, UnitTypes.Absolute)
)
def ProcessCandle(self, candle, sma_value, atr_value):
if candle.State != CandleStates.Finished:
return
# Calculate entry thresholds
upper_threshold = sma_value + self.Multiplier * atr_value
lower_threshold = sma_value - self.Multiplier * atr_value
# Long setup - price below lower threshold
if candle.ClosePrice < lower_threshold and self.Position <= 0:
# Buy signal - price has deviated too much below average
self.BuyMarket(self.Volume + Math.Abs(self.Position))
# Short setup - price above upper threshold
elif candle.ClosePrice > upper_threshold and self.Position >= 0:
# Sell signal - price has deviated too much above average
self.SellMarket(self.Volume + Math.Abs(self.Position))
# Exit long position when price returns to average
elif self.Position > 0 and candle.ClosePrice >= sma_value:
# Close long position
self.SellMarket(self.Position)
# Exit short position when price returns to average
elif self.Position < 0 and candle.ClosePrice <= sma_value:
# Close short position
self.BuyMarket(Math.Abs(self.Position))
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return atr_mean_reversion_strategy()