Ausbruch-Strategie, konvertiert aus dem MetaTrader-Skript binario_31. Der Algorithmus berechnet zwei exponentielle gleitende Durchschnitte mit 144 Perioden auf den Hoch- und Tiefpreisen der Kerzen und bildet so einen dynamischen Kanal. Solange der aktuelle Preis innerhalb des Kanals liegt, bereitet die Strategie Stop-Einstiegsaufträge vor:
ein Kauf-Stop über dem EMA-Hoch plus einem konfigurierbaren Versatz;
ein Verkauf-Stop unter dem EMA-Tief minus demselben Versatz.
Wenn der Preis eines dieser Levels durchbricht, wird eine Position in Ausbruchsrichtung eröffnet. Ein schützender Stop wird auf der gegenüberliegenden Seite des Kanals platziert und ein Take-Profit-Ziel relativ zum Einstieg berechnet. Ein optionaler Trailing Stop kann aktiviert werden, um Gewinne zu sichern.
Parameter
EMA Length – Periode für beide EMAs auf Hoch und Tief.
Pip Difference – Abstand vom EMA-Level bis zum Ausbruchs-Einstieg in Preisschritten.
Take Profit – Abstand vom Einstieg bis zum Take Profit in Preisschritten.
Trailing Stop – Trailing-Stop-Abstand in Preisschritten. Auf null setzen, um zu deaktivieren.
Volume – Auftragsvolumen.
Candle Type – Kerzentyp, den die Strategie abonniert.
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>
/// EMA channel breakout strategy.
/// Buys when price breaks above EMA + offset, sells when below EMA - offset.
/// Uses trailing stop and take profit for exits.
/// </summary>
public class Binario31Strategy : Strategy
{
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<decimal> _channelOffset;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public decimal ChannelOffset { get => _channelOffset.Value; set => _channelOffset.Value = value; }
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public decimal StopLossVal { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Binario31Strategy()
{
_emaLength = Param(nameof(EmaLength), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period", "Indicator");
_channelOffset = Param(nameof(ChannelOffset), 50m)
.SetDisplay("Channel Offset", "Distance from EMA for channel", "Indicator");
_takeProfit = Param(nameof(TakeProfit), 2000m)
.SetDisplay("Take Profit", "Take profit distance", "Risk");
_stopLoss = Param(nameof(StopLossVal), 1500m)
.SetDisplay("Stop Loss", "Stop loss distance", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaLength };
SubscribeCandles(CandleType)
.Bind(ema, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
var upperBand = emaValue + ChannelOffset;
var lowerBand = emaValue - ChannelOffset;
// Exit management
if (Position > 0)
{
var profit = close - _entryPrice;
if ((TakeProfit > 0 && profit >= TakeProfit) || (StopLossVal > 0 && -profit >= StopLossVal))
{
SellMarket();
return;
}
}
else if (Position < 0)
{
var profit = _entryPrice - close;
if ((TakeProfit > 0 && profit >= TakeProfit) || (StopLossVal > 0 && -profit >= StopLossVal))
{
BuyMarket();
return;
}
}
// Entry: channel breakout
if (Position == 0)
{
if (close > upperBand)
{
BuyMarket();
_entryPrice = close;
}
else if (close < lowerBand)
{
SellMarket();
_entryPrice = close;
}
}
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class binario31_strategy(Strategy):
def __init__(self):
super(binario31_strategy, self).__init__()
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "EMA period", "Indicator")
self._channel_offset = self.Param("ChannelOffset", 50.0) \
.SetDisplay("Channel Offset", "Distance from EMA for channel", "Indicator")
self._take_profit = self.Param("TakeProfit", 2000.0) \
.SetDisplay("Take Profit", "Take profit distance", "Risk")
self._stop_loss = self.Param("StopLossVal", 1500.0) \
.SetDisplay("Stop Loss", "Stop loss distance", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._entry_price = 0.0
@property
def EmaLength(self):
return self._ema_length.Value
@EmaLength.setter
def EmaLength(self, value):
self._ema_length.Value = value
@property
def ChannelOffset(self):
return self._channel_offset.Value
@ChannelOffset.setter
def ChannelOffset(self, value):
self._channel_offset.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def StopLossVal(self):
return self._stop_loss.Value
@StopLossVal.setter
def StopLossVal(self, value):
self._stop_loss.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(binario31_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
self.SubscribeCandles(self.CandleType) \
.Bind(ema, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ema_val = float(ema_value)
offset = float(self.ChannelOffset)
tp = float(self.TakeProfit)
sl = float(self.StopLossVal)
upper_band = ema_val + offset
lower_band = ema_val - offset
if self.Position > 0:
profit = close - self._entry_price
if (tp > 0 and profit >= tp) or (sl > 0 and -profit >= sl):
self.SellMarket()
return
elif self.Position < 0:
profit = self._entry_price - close
if (tp > 0 and profit >= tp) or (sl > 0 and -profit >= sl):
self.BuyMarket()
return
if self.Position == 0:
if close > upper_band:
self.BuyMarket()
self._entry_price = close
elif close < lower_band:
self.SellMarket()
self._entry_price = close
def OnReseted(self):
super(binario31_strategy, self).OnReseted()
self._entry_price = 0.0
def CreateClone(self):
return binario31_strategy()