200-SMA-Buffer-Strategie
Die 200-SMA-Buffer-Strategie handelt auf Basis des Abstands des Preises von einem langfristigen einfachen gleitenden Durchschnitt. Sie kauft, wenn der Schlusskurs einen bestimmten Prozentsatz über der SMA steigt, und steigt aus, wenn der Preis einen definierten Prozentsatz darunter fällt. Der Ansatz zielt darauf ab, langfristigen Momentum zu erfassen und dabei einen Puffer um den gleitenden Durchschnitt zu erlauben.
Details
- Einstiegskriterien:
- Schlusskurs > SMA * (1 + Entry %).
- Long/Short: Nur Long.
- Ausstiegskriterien:
- Schlusskurs < SMA * (1 - Exit %).
- Stops: Keine.
- Standardwerte:
SmaLength= 200EntryPercent= 5ExitPercent= 3
- Filter:
- Kategorie: Trendfolge
- Richtung: Long
- Indikatoren: SMA
- Stops: Nein
- Komplexität: Niedrig
- Zeitrahmen: Beliebig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// 200 SMA Buffer Strategy.
/// Buys when price is above SMA by entry percent.
/// Sells when price falls below SMA by exit percent.
/// Also supports short positions.
/// </summary>
public class SmaBufferStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _smaLength;
private readonly StrategyParam<decimal> _entryPercent;
private readonly StrategyParam<decimal> _exitPercent;
private readonly StrategyParam<int> _cooldownBars;
private SimpleMovingAverage _sma;
private int _cooldownRemaining;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int SmaLength
{
get => _smaLength.Value;
set => _smaLength.Value = value;
}
public decimal EntryPercent
{
get => _entryPercent.Value;
set => _entryPercent.Value = value;
}
public decimal ExitPercent
{
get => _exitPercent.Value;
set => _exitPercent.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public SmaBufferStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_smaLength = Param(nameof(SmaLength), 100)
.SetGreaterThanZero()
.SetDisplay("SMA Length", "Period of the moving average", "Parameters");
_entryPercent = Param(nameof(EntryPercent), 2m)
.SetDisplay("Entry %", "Percent above/below SMA to enter", "Parameters");
_exitPercent = Param(nameof(ExitPercent), 1m)
.SetDisplay("Exit %", "Percent toward SMA to exit", "Parameters");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sma = null;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sma = new SimpleMovingAverage { Length = SmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_sma, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _sma);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_sma.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
var price = candle.ClosePrice;
var upperEntry = smaValue * (1m + EntryPercent / 100m);
var lowerEntry = smaValue * (1m - EntryPercent / 100m);
var upperExit = smaValue * (1m + ExitPercent / 100m);
var lowerExit = smaValue * (1m - ExitPercent / 100m);
// Buy: price above upper entry threshold
if (price > upperEntry && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Sell: price below lower entry threshold
else if (price < lowerEntry && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Exit long: price drops below lower exit
else if (Position > 0 && price < lowerExit)
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short: price rises above upper exit
else if (Position < 0 && price > upperExit)
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = 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 sma_buffer_strategy(Strategy):
"""200 SMA Buffer Strategy."""
def __init__(self):
super(sma_buffer_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._sma_length = self.Param("SmaLength", 100) \
.SetDisplay("SMA Length", "Period of the moving average", "Parameters")
self._entry_percent = self.Param("EntryPercent", 2.0) \
.SetDisplay("Entry %", "Percent above/below SMA to enter", "Parameters")
self._exit_percent = self.Param("ExitPercent", 1.0) \
.SetDisplay("Exit %", "Percent toward SMA to exit", "Parameters")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._sma = None
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(sma_buffer_strategy, self).OnReseted()
self._sma = None
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(sma_buffer_strategy, self).OnStarted2(time)
self._sma = SimpleMovingAverage()
self._sma.Length = int(self._sma_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._sma, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._sma)
self.DrawOwnTrades(area)
def _on_process(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
if not self._sma.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
price = float(candle.ClosePrice)
sma_v = float(sma_value)
entry_pct = float(self._entry_percent.Value)
exit_pct = float(self._exit_percent.Value)
cooldown = int(self._cooldown_bars.Value)
upper_entry = sma_v * (1.0 + entry_pct / 100.0)
lower_entry = sma_v * (1.0 - entry_pct / 100.0)
upper_exit = sma_v * (1.0 + exit_pct / 100.0)
lower_exit = sma_v * (1.0 - exit_pct / 100.0)
if price > upper_entry and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif price < lower_entry and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
elif self.Position > 0 and price < lower_exit:
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and price > upper_exit:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
def CreateClone(self):
return sma_buffer_strategy()