Diese Strategie nutzt Ausbrüche relativ zu einem Triangular Moving Average (TMA). Sie beobachtet eine konfigurierbare Kerzenserie und vergleicht den Schlusskurs der vorherigen Kerze mit dem TMA-Wert zuzüglich oder abzüglich benutzerdefinierter Offsets. Eine Long-Position wird eröffnet, wenn der vorherige Schlusskurs über TMA + UpLevel liegt, und eine Short-Position wird eröffnet, wenn er unter TMA - DownLevel liegt. Entgegengesetzte Signale kehren die Position um.
Parameter
TMA Length – Periode zur Berechnung des Triangular Moving Average.
Upper Level – Preisoffset, der zum TMA addiert wird, um Long-Signale zu erkennen.
Lower Level – Preisoffset, der vom TMA subtrahiert wird, um Short-Signale zu erkennen.
Candle Type – Zeitrahmen der von der Strategie verwendeten Kerzen.
Funktionsweise
Abonniert die ausgewählte Kerzenserie.
Bindet einen Triangular Moving Average-Indikator an die Kerzen.
Bei jeder abgeschlossenen Kerze:
Speichert die vorherigen TMA- und Schlusskurswerte.
Prüft, ob der vorherige Schlusskurs das obere oder untere Niveau überschritten hat.
Sendet Marktorders, um Positionen entsprechend zu eröffnen oder umzukehren.
Zeichnet Kerzen, Indikatorlinie und eigene Trades für die visuelle Analyse.
Hinweise
Die Strategie verwendet Marktorders ohne Stop-Loss- oder Take-Profit-Verwaltung. Sie ist für Bildungszwecke gedacht und sollte vor dem Live-Trading mit geeigneten Risikokontrollen erweitert werden.
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>
/// Strategy that enters when price breaks the Triangular Moving Average by configurable offsets.
/// </summary>
public class TmaBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<decimal> _upLevel;
private readonly StrategyParam<decimal> _downLevel;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevTma;
private decimal? _prevClose;
/// <summary>
/// Period for the Triangular Moving Average.
/// </summary>
public int Length
{
get => _length.Value;
set => _length.Value = value;
}
/// <summary>
/// Offset above the TMA to trigger a long entry.
/// </summary>
public decimal UpLevel
{
get => _upLevel.Value;
set => _upLevel.Value = value;
}
/// <summary>
/// Offset below the TMA to trigger a short entry.
/// </summary>
public decimal DownLevel
{
get => _downLevel.Value;
set => _downLevel.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize the TMA breakout strategy.
/// </summary>
public TmaBreakoutStrategy()
{
_length = Param(nameof(Length), 30)
.SetDisplay("TMA Length", "Period for the Triangular Moving Average", "Parameters")
.SetOptimize(10, 60, 10);
_upLevel = Param(nameof(UpLevel), 300m)
.SetDisplay("Upper Level", "Offset above TMA in price units", "Parameters")
.SetOptimize(100m, 500m, 100m);
_downLevel = Param(nameof(DownLevel), 300m)
.SetDisplay("Lower Level", "Offset below TMA in price units", "Parameters")
.SetOptimize(100m, 500m, 100m);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevTma = _prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var tma = new ExponentialMovingAverage { Length = Length };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(tma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, tma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal tmaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var prevTma = _prevTma;
var prevClose = _prevClose;
if (prevTma is null || prevClose is null)
{
_prevTma = tmaValue;
_prevClose = candle.ClosePrice;
return;
}
var signalUp = prevClose > prevTma + UpLevel;
var signalDn = prevClose < prevTma - DownLevel;
if (signalUp && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (signalDn && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevTma = tmaValue;
_prevClose = candle.ClosePrice;
}
}
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 tma_breakout_strategy(Strategy):
def __init__(self):
super(tma_breakout_strategy, self).__init__()
self._length = self.Param("Length", 30) \
.SetDisplay("TMA Length", "Period for the Triangular Moving Average", "Parameters")
self._up_level = self.Param("UpLevel", 300.0) \
.SetDisplay("Upper Level", "Offset above TMA in price units", "Parameters")
self._down_level = self.Param("DownLevel", 300.0) \
.SetDisplay("Lower Level", "Offset below TMA in price units", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_tma = None
self._prev_close = None
@property
def length(self):
return self._length.Value
@property
def up_level(self):
return self._up_level.Value
@property
def down_level(self):
return self._down_level.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(tma_breakout_strategy, self).OnReseted()
self._prev_tma = None
self._prev_close = None
def OnStarted2(self, time):
super(tma_breakout_strategy, self).OnStarted2(time)
tma = ExponentialMovingAverage()
tma.Length = self.length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(tma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, tma)
self.DrawOwnTrades(area)
def process_candle(self, candle, tma_value):
if candle.State != CandleStates.Finished:
return
tma_val = float(tma_value)
close = float(candle.ClosePrice)
if self._prev_tma is None or self._prev_close is None:
self._prev_tma = tma_val
self._prev_close = close
return
signal_up = self._prev_close > self._prev_tma + float(self.up_level)
signal_dn = self._prev_close < self._prev_tma - float(self.down_level)
if signal_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif signal_dn and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_tma = tma_val
self._prev_close = close
def CreateClone(self):
return tma_breakout_strategy()