Die Strategie handelt rund um einen einfachen gleitenden Durchschnitt (SMA) mit einem zusätzlichen Glättungsversatz. Sie versucht, Preisabweichungen vom gleitenden Durchschnitt zu nutzen, indem sie Positionen eröffnet, wenn der Schlusskurs einen Versatzabstand vom Durchschnitt überschreitet.
Funktionsweise
Berechnung eines SMA des gewählten Kerzentyps.
Wenn keine offene Position vorhanden ist:
Short-Position eröffnen, wenn der Schlusskurs unter SMA + Smoothing liegt.
Long-Position eröffnen, wenn der Schlusskurs über SMA - Smoothing liegt.
Bei einer offenen Short-Position:
Position schließen, wenn der Schlusskurs über SMA + Smoothing steigt.
Bei einer offenen Long-Position:
Position schließen, wenn der Schlusskurs unter SMA - Smoothing fällt.
Die Strategie verwendet Marktaufträge und arbeitet nur mit abgeschlossenen Kerzen.
Parameter
MA Period – Rückblickperiode für den SMA.
Smoothing – Preisversatz, der beim Generieren von Signalen zum SMA addiert oder subtrahiert wird.
Candle Type – Zeitrahmen der für Berechnungen verwendeten Kerzen.
Hinweise
Diese Konvertierung basiert auf dem originalen MQL4-Skript smoothingaverage.mq4.
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>
/// Moving average strategy with smoothing offset.
/// </summary>
public class SmoothingAverageStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<decimal> _smoothing;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private int _cooldown;
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public decimal Smoothing
{
get => _smoothing.Value;
set => _smoothing.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public SmoothingAverageStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 200)
.SetDisplay("MA Period", "Moving average period", "MA")
;
_smoothing = Param(nameof(Smoothing), 1400m)
.SetDisplay("Smoothing", "Price offset from moving average", "General")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 36)
.SetDisplay("Cooldown Bars", "Bars to wait between new signals", "General")
;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// create moving average indicator
var sma = new SimpleMovingAverage { Length = MaPeriod };
// subscribe to candles
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 (_cooldown > 0)
{
_cooldown--;
return;
}
var price = candle.ClosePrice;
var offset = (Security.PriceStep ?? 1m) * Smoothing;
if (Position == 0)
{
if (price >= maValue + offset)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (price <= maValue - offset)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
else if (Position < 0 && price <= maValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && price >= maValue)
{
SellMarket();
_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, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class smoothing_average_strategy(Strategy):
def __init__(self):
super(smoothing_average_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 200) \
.SetDisplay("MA Period", "Moving average period", "MA")
self._smoothing = self.Param("Smoothing", 1400.0) \
.SetDisplay("Smoothing", "Price offset from moving average", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 36) \
.SetDisplay("Cooldown Bars", "Bars to wait between new signals", "General")
self._cooldown = 0
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
@property
def Smoothing(self):
return self._smoothing.Value
@Smoothing.setter
def Smoothing(self, value):
self._smoothing.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def CooldownBars(self):
return self._cooldown_bars.Value
@CooldownBars.setter
def CooldownBars(self, value):
self._cooldown_bars.Value = value
def OnStarted2(self, time):
super(smoothing_average_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(sma, self.ProcessCandle) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, ma_value):
if candle.State != CandleStates.Finished:
return
if self._cooldown > 0:
self._cooldown -= 1
return
price = float(candle.ClosePrice)
ma_val = float(ma_value)
step_raw = self.Security.PriceStep
step = float(step_raw) if step_raw is not None else 1.0
offset = step * float(self.Smoothing)
if self.Position == 0:
if price >= ma_val + offset:
self.SellMarket()
self._cooldown = self.CooldownBars
elif price <= ma_val - offset:
self.BuyMarket()
self._cooldown = self.CooldownBars
elif self.Position < 0 and price <= ma_val:
self.BuyMarket()
self._cooldown = self.CooldownBars
elif self.Position > 0 and price >= ma_val:
self.SellMarket()
self._cooldown = self.CooldownBars
def OnReseted(self):
super(smoothing_average_strategy, self).OnReseted()
self._cooldown = 0
def CreateClone(self):
return smoothing_average_strategy()