Strategie, die handelt, wenn der Preis erheblich von seinem gleitenden Durchschnitt abweicht
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 124%. Sie funktioniert am besten auf dem Forexmarkt.
MA Deviation steigt ein, wenn der Preis einen festgelegten Prozentsatz von seinem gleitenden Durchschnitt abweicht, und erwartet eine Rückkehr zum Mittelwert. Die Position wird geschlossen, wenn der Preis wieder in Richtung des Durchschnitts konvergiert.
Abweichungsschwellenwerte können je nach Volatilität erweitert oder verengt werden. Die Verwendung von ATR für die Positionsgröße hält das Risiko auf allen Märkten konsistent.
Details
Einstiegskriterien: Signale basierend auf MA, ATR.
Long/Short: Beide Richtungen.
Ausstiegskriterien: Gegensätzliches Signal oder Stop.
Stops: Ja.
Standardwerte:
MAPeriod = 20
DeviationPercent = 5m
AtrPeriod = 14
AtrMultiplier = 2.0m
CandleType = TimeSpan.FromMinutes(5)
Filter:
Kategorie: Trend
Richtung: Beide
Indikatoren: MA, ATR
Stops: Ja
Komplexität: Grundlegend
Zeitrahmen: Intraday (5m)
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
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>
/// Strategy that trades when price deviates significantly from its moving average.
/// Opens positions when price deviates by a specified percentage from MA
/// and closes when price returns to MA.
/// </summary>
public class MADeviationStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<decimal> _deviationPercent;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private int _cooldown;
/// <summary>
/// Period for Moving Average calculation.
/// </summary>
public int MAPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Deviation percentage from MA required for entry.
/// </summary>
public decimal DeviationPercent
{
get => _deviationPercent.Value;
set => _deviationPercent.Value = value;
}
/// <summary>
/// Type of candles used for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Initialize the MA Deviation strategy.
/// </summary>
public MADeviationStrategy()
{
_maPeriod = Param(nameof(MAPeriod), 20)
.SetDisplay("MA Period", "Period for Moving Average calculation", "Indicators")
.SetOptimize(10, 50, 5);
_deviationPercent = Param(nameof(DeviationPercent), 2m)
.SetDisplay("Deviation %", "Deviation percentage from MA required for entry", "Entry")
.SetOptimize(1m, 10m, 1m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_cooldown = 0;
var sma = new SimpleMovingAverage { Length = MAPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal maValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (maValue == 0)
return;
if (_cooldown > 0)
{
_cooldown--;
return;
}
var deviation = (candle.ClosePrice - maValue) / maValue * 100;
if (Position == 0)
{
// Price far below MA -> buy (expect reversion up)
if (deviation < -DeviationPercent)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Price far above MA -> sell (expect reversion down)
else if (deviation > DeviationPercent)
{
SellMarket();
_cooldown = CooldownBars;
}
}
else if (Position > 0)
{
// Exit long when price returns to or above MA
if (candle.ClosePrice >= maValue)
{
SellMarket();
_cooldown = CooldownBars;
}
}
else if (Position < 0)
{
// Exit short when price returns to or below MA
if (candle.ClosePrice <= maValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ma_deviation_strategy(Strategy):
"""
MA Deviation strategy.
Trades when price deviates significantly from its moving average.
"""
def __init__(self):
super(ma_deviation_strategy, self).__init__()
self._ma_period = self.Param("MAPeriod", 20).SetDisplay("MA Period", "Period for Moving Average calculation", "Indicators")
self._deviation_percent = self.Param("DeviationPercent", 2.0).SetDisplay("Deviation %", "Deviation percentage from MA required for entry", "Entry")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma_deviation_strategy, self).OnReseted()
self._cooldown = 0
def OnStarted2(self, time):
super(ma_deviation_strategy, self).OnStarted2(time)
self._cooldown = 0
sma = SimpleMovingAverage()
sma.Length = self._ma_period.Value
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.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ma_val):
if candle.State != CandleStates.Finished:
return
mv = float(ma_val)
if mv == 0:
return
if self._cooldown > 0:
self._cooldown -= 1
return
close = float(candle.ClosePrice)
deviation = (close - mv) / mv * 100.0
threshold = float(self._deviation_percent.Value)
cd = self._cooldown_bars.Value
if self.Position == 0:
if deviation < -threshold:
self.BuyMarket()
self._cooldown = cd
elif deviation > threshold:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0:
if close >= mv:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0:
if close <= mv:
self.BuyMarket()
self._cooldown = cd
def CreateClone(self):
return ma_deviation_strategy()