Die Strategie verwendet den Modified Moving Average (AMMA)-Indikator, um kurzfristige Trendwechsel zu erfassen. Sie analysiert die Richtung der AMMA-Steigung bei den letzten Kerzen und öffnet eine Position in Richtung des aufkommenden Trends, während die entgegengesetzte geschlossen wird.
Funktionsweise
Ein ModifiedMovingAverage mit einer konfigurierbaren Periode wird auf dem ausgewählten Zeitrahmen berechnet.
Bei jeder abgeschlossenen Kerze vergleicht die Strategie die letzten drei AMMA-Werte.
Wenn die Indikatorwerte eine aufsteigende Folge bilden und der neueste Wert größer als der vorherige ist, wird eine Long-Position eröffnet. Jede Short-Position wird geschlossen.
Wenn die Indikatorwerte eine absteigende Folge bilden und der neueste Wert kleiner als der vorherige ist, wird eine Short-Position eröffnet. Jede Long-Position wird geschlossen.
Parameter
CandleType – Zeitrahmen der für Berechnungen verwendeten Kerzen.
MaPeriod – Periode des modifizierten gleitenden Durchschnitts.
AllowLongEntry – Öffnen von Long-Positionen aktivieren.
AllowShortEntry – Öffnen von Short-Positionen aktivieren.
AllowLongExit – Schließen von Long-Positionen aktivieren.
AllowShortExit – Schließen von Short-Positionen aktivieren.
Hinweise
Die Strategie arbeitet nur auf abgeschlossenen Kerzen und verwendet die integrierten BuyMarket- und SellMarket-Methoden für die Orderausführung. Risikomanagement-Funktionen können extern über die Standard-Strategy-Eigenschaften hinzugefügt werden.
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>
/// AMMA Trend strategy using Modified Moving Average direction changes.
/// Buys when MMA turns up, sells when MMA turns down.
/// </summary>
public class AmmaTrendStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private decimal? _mma0;
private decimal? _mma1;
private decimal? _mma2;
private decimal? _mma3;
private readonly StrategyParam<bool> _allowLongEntry, _allowShortEntry, _allowLongExit, _allowShortExit;
private Order _pending;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
public bool AllowLongEntry { get => _allowLongEntry.Value; set => _allowLongEntry.Value = value; }
public bool AllowShortEntry { get => _allowShortEntry.Value; set => _allowShortEntry.Value = value; }
public bool AllowLongExit { get => _allowLongExit.Value; set => _allowLongExit.Value = value; }
public bool AllowShortExit { get => _allowShortExit.Value; set => _allowShortExit.Value = value; }
public AmmaTrendStrategy()
{
_allowLongEntry = Param(nameof(AllowLongEntry), true);
_allowShortEntry = Param(nameof(AllowShortEntry), true);
_allowLongExit = Param(nameof(AllowLongExit), true);
_allowShortExit = Param(nameof(AllowShortExit), true);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use for analysis", "General");
_maPeriod = Param(nameof(MaPeriod), 25)
.SetGreaterThanZero()
.SetDisplay("AMMA Period", "Period of the modified moving average", "Indicator");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_mma0 = _mma1 = _mma2 = _mma3 = null;
_pending = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_pending = null;
var mma = new SmoothedMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(mma, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, mma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal mmaValue)
{
if (candle.State != CandleStates.Finished)
return;
_mma3 = _mma2;
_mma2 = _mma1;
_mma1 = _mma0;
_mma0 = mmaValue;
if (_mma1 is null || _mma2 is null || _mma3 is null)
return;
var rising = _mma2 < _mma3 && _mma1 > _mma2 && _mma0 > _mma1;
var falling = _mma2 > _mma3 && _mma1 < _mma2 && _mma0 < _mma1;
if (!IsFormedAndOnlineAndAllowTrading() || (_pending is not null && _pending.State is not (OrderStates.Done or OrderStates.Failed))) return;
if (rising)
{
if (Position < 0m && AllowShortExit) _pending = BuyMarket(-Position + (AllowLongEntry ? Volume : 0m));
else if (Position == 0m && AllowLongEntry) _pending = BuyMarket(Volume);
}
else if (falling)
{
if (Position > 0m && AllowLongExit) _pending = SellMarket(Position + (AllowShortEntry ? Volume : 0m));
else if (Position == 0m && AllowShortEntry) _pending = SellMarket(Volume);
}
}
}
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, OrderStates
from StockSharp.Algo.Indicators import SmoothedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class amma_trend_strategy(Strategy):
def __init__(self):
super(amma_trend_strategy, self).__init__()
self._allow_long_entry = self.Param("AllowLongEntry", True)
self._allow_short_entry = self.Param("AllowShortEntry", True)
self._allow_long_exit = self.Param("AllowLongExit", True)
self._allow_short_exit = self.Param("AllowShortExit", True)
self._pending = None
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use for analysis", "General")
self._ma_period = self.Param("MaPeriod", 25) \
.SetDisplay("AMMA Period", "Period of the modified moving average", "Indicator")
self._mma0 = None
self._mma1 = None
self._mma2 = None
self._mma3 = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
def OnStarted2(self, time):
super(amma_trend_strategy, self).OnStarted2(time)
self._pending = None
self._mma0 = None
self._mma1 = None
self._mma2 = None
self._mma3 = None
mma = SmoothedMovingAverage()
mma.Length = self.MaPeriod
self.SubscribeCandles(self.CandleType) \
.Bind(mma, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, mma_val):
if candle.State != CandleStates.Finished:
return
mma_f = float(mma_val)
self._mma3 = self._mma2
self._mma2 = self._mma1
self._mma1 = self._mma0
self._mma0 = mma_f
if self._mma1 is None or self._mma2 is None or self._mma3 is None:
return
rising = self._mma2 < self._mma3 and self._mma1 > self._mma2 and self._mma0 > self._mma1
falling = self._mma2 > self._mma3 and self._mma1 < self._mma2 and self._mma0 < self._mma1
if not self.IsFormedAndOnlineAndAllowTrading() or (self._pending is not None and self._pending.State not in (OrderStates.Done, OrderStates.Failed)):
return
if rising:
if self.Position < 0 and self._allow_short_exit.Value:
self._pending = self.BuyMarket(-self.Position + (self.Volume if self._allow_long_entry.Value else 0))
elif self.Position == 0 and self._allow_long_entry.Value:
self._pending = self.BuyMarket(self.Volume)
elif falling:
if self.Position > 0 and self._allow_long_exit.Value:
self._pending = self.SellMarket(self.Position + (self.Volume if self._allow_short_entry.Value else 0))
elif self.Position == 0 and self._allow_short_entry.Value:
self._pending = self.SellMarket(self.Volume)
def OnReseted(self):
super(amma_trend_strategy, self).OnReseted()
self._pending = None
self._mma0 = None
self._mma1 = None
self._mma2 = None
self._mma3 = None
def CreateClone(self):
return amma_trend_strategy()