Dieser Ordner bietet ein minimales Gerüst zum Aufbau eigener Trading-Ideen. Die
Strategie berechnet nur einen einzigen exponentiellen gleitenden Durchschnitt und
stellt eine breite Palette gängiger Parameter bereit: Long- oder Short-Trades aktivieren,
optionales Take Profit und Stop Loss sowie Optimierungsbereiche. Entwickler können ihre
eigene Einstiegs- und Ausstiegslogik in die Platzhalter einfügen, um neue Systeme
schnell zu prototypisieren.
Die Vorlage zeigt auch, wie das integrierte Schutzmodul mit prozentualen Zielen gestartet
werden kann, was das Experimentieren mit verschiedenen Risikoeinstellungen erleichtert.
Da keine echten Signale enthalten sind, soll dieses Skript nicht direkt gehandelt werden,
sondern als Ausgangspunkt für weitere Forschung dienen.
Details
Einstiegskriterien: Nicht implementiert – durch eigene Regeln ersetzen.
Long/Short: Über Parameter konfigurierbar.
Ausstiegskriterien: Nicht implementiert – durch eigene Regeln ersetzen.
Stops: Optionaler prozentualer Take Profit und Stop Loss über das Schutzmodul.
Standardwerte:
EMA-Länge = 10.
Take Profit = 1.2%, Stop Loss = 1.8% (standardmäßig deaktiviert).
Filter:
Kategorie: Vorlage
Richtung: Konfigurierbar
Indikatoren: EMA
Stops: Optional
Komplexität: Niedrig
Zeitrahmen: Beliebig
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Benutzerdefiniert
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>
/// Strategy Base - EMA trend following strategy.
/// Buys when price crosses above EMA, sells when price crosses below EMA.
/// </summary>
public class StratBaseStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _cooldownBars;
private ExponentialMovingAverage _ema;
private decimal _prevClose;
private decimal _prevEma;
private int _cooldownRemaining;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public StratBaseStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_emaLength = Param(nameof(EmaLength), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period", "Moving Averages");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ema = null;
_prevClose = 0;
_prevEma = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_ema, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ema);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal emaVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!_ema.IsFormed)
{
_prevClose = candle.ClosePrice;
_prevEma = emaVal;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevClose = candle.ClosePrice;
_prevEma = emaVal;
return;
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevClose = candle.ClosePrice;
_prevEma = emaVal;
return;
}
if (_prevClose == 0 || _prevEma == 0)
{
_prevClose = candle.ClosePrice;
_prevEma = emaVal;
return;
}
// Price crosses above EMA
var crossUp = candle.ClosePrice > emaVal && _prevClose <= _prevEma;
// Price crosses below EMA
var crossDown = candle.ClosePrice < emaVal && _prevClose >= _prevEma;
if (crossUp && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
else if (crossDown && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
_prevClose = candle.ClosePrice;
_prevEma = emaVal;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class strat_base_strategy(Strategy):
"""Strategy Base - EMA trend following strategy."""
def __init__(self):
super(strat_base_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "EMA period", "Moving Averages")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk")
self._ema = None
self._prev_close = 0.0
self._prev_ema = 0.0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(strat_base_strategy, self).OnReseted()
self._ema = None
self._prev_close = 0.0
self._prev_ema = 0.0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(strat_base_strategy, self).OnStarted2(time)
self._ema = ExponentialMovingAverage()
self._ema.Length = int(self._ema_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, ema_val):
if candle.State != CandleStates.Finished:
return
if not self._ema.IsFormed:
self._prev_close = float(candle.ClosePrice)
self._prev_ema = float(ema_val)
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_close = float(candle.ClosePrice)
self._prev_ema = float(ema_val)
return
close = float(candle.ClosePrice)
ema = float(ema_val)
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_close = close
self._prev_ema = ema
return
if self._prev_close == 0.0 or self._prev_ema == 0.0:
self._prev_close = close
self._prev_ema = ema
return
cooldown = int(self._cooldown_bars.Value)
cross_up = close > ema and self._prev_close <= self._prev_ema
cross_down = close < ema and self._prev_close >= self._prev_ema
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
self._prev_close = close
self._prev_ema = ema
def CreateClone(self):
return strat_base_strategy()