Die MA-Kanal-Strategie handelt Ausbrüche aus einem gleitenden Durchschnittskanal, der aus den Hoch- und Tiefpreisen aufgebaut ist. Eine Position wird eröffnet, wenn der Preis den Kanal in der entsprechenden Richtung verlässt, und umgekehrt, wenn sich der Trend dreht. Die Kanalgrenzen werden aus exponentiellen gleitenden Durchschnitten mit einem festen Versatz berechnet.
Das System ist für Long- und Short-Handel ausgelegt und reagiert nur auf abgeschlossene Kerzen. Ziel ist es, Trendwenden frühzeitig zu erfassen und dabei Rauschen innerhalb des Kanals zu vermeiden.
Details
Einstiegskriterien:
Long: Preis bricht über den oberen Kanal aus.
Short: Preis bricht unter den unteren Kanal aus.
Ausstiegskriterien:
Ein entgegengesetzter Ausbruch löst eine Umkehr der Position aus.
Indikatoren: Exponentielle gleitende Durchschnitte von Hoch- und Tiefpreisen mit konfigurierbarer Länge und Preisversatz.
Stops: Standardmäßig nicht verwendet; Trades werden nur bei entgegengesetzten Signalen geschlossen.
Standardwerte:
Length = 8
Offset = 10
CandleType = 1-Stunden-Kerzen
Filter:
Kategorie: Trendfolge
Richtung: Beide
Indikatoren: Einzeln
Stops: Nein
Komplexität: Einfach
Zeitrahmen: Mittelfristig
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Moderat
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>
/// Moving average channel breakout strategy.
/// Buys when price crosses above the upper channel (MA of highs + offset).
/// Sells when price crosses below the lower channel (MA of lows - offset).
/// </summary>
public class MaChannelStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<decimal> _offset;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _maHigh;
private ExponentialMovingAverage _maLow;
private int _trend;
public int Length { get => _length.Value; set => _length.Value = value; }
public decimal Offset { get => _offset.Value; set => _offset.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MaChannelStrategy()
{
_length = Param(nameof(Length), 8)
.SetDisplay("Length", "Moving average period", "Parameters")
.SetOptimize(5, 20, 1);
_offset = Param(nameof(Offset), 100m)
.SetDisplay("Offset", "Price offset from the average", "Parameters")
.SetOptimize(50m, 500m, 50m);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_maHigh = null;
_maLow = null;
_trend = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_trend = 0;
_maHigh = new ExponentialMovingAverage { Length = Length };
_maLow = new ExponentialMovingAverage { Length = Length };
Indicators.Add(_maHigh);
Indicators.Add(_maLow);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var t = candle.ServerTime;
var highResult = _maHigh.Process(new DecimalIndicatorValue(_maHigh, candle.HighPrice, t) { IsFinal = true });
var lowResult = _maLow.Process(new DecimalIndicatorValue(_maLow, candle.LowPrice, t) { IsFinal = true });
if (!_maHigh.IsFormed || !_maLow.IsFormed)
return;
var upper = highResult.GetValue<decimal>() + Offset;
var lower = lowResult.GetValue<decimal>() - Offset;
var prevTrend = _trend;
if (candle.HighPrice > upper)
_trend = 1;
else if (candle.LowPrice < lower)
_trend = -1;
if (prevTrend <= 0 && _trend > 0 && Position <= 0)
BuyMarket();
else if (prevTrend >= 0 && _trend < 0 && Position >= 0)
SellMarket();
}
}
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
from indicator_extensions import *
class ma_channel_strategy(Strategy):
def __init__(self):
super(ma_channel_strategy, self).__init__()
self._length = self.Param("Length", 8) \
.SetDisplay("Length", "Moving average period", "Parameters")
self._offset = self.Param("Offset", 100.0) \
.SetDisplay("Offset", "Price offset from the average", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "Parameters")
self._ma_high = None
self._ma_low = None
self._trend = 0
@property
def length(self):
return self._length.Value
@property
def offset(self):
return self._offset.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma_channel_strategy, self).OnReseted()
self._ma_high = None
self._ma_low = None
self._trend = 0
def OnStarted2(self, time):
super(ma_channel_strategy, self).OnStarted2(time)
self._trend = 0
self._ma_high = ExponentialMovingAverage()
self._ma_high.Length = self.length
self._ma_low = ExponentialMovingAverage()
self._ma_low.Length = self.length
self.Indicators.Add(self._ma_high)
self.Indicators.Add(self._ma_low)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
t = candle.ServerTime
high_result = process_float(self._ma_high, float(candle.HighPrice), t, True)
low_result = process_float(self._ma_low, float(candle.LowPrice), t, True)
if not self._ma_high.IsFormed or not self._ma_low.IsFormed:
return
offset_val = float(self.offset)
upper = float(high_result) + offset_val
lower = float(low_result) - offset_val
prev_trend = self._trend
high_price = float(candle.HighPrice)
low_price = float(candle.LowPrice)
if high_price > upper:
self._trend = 1
elif low_price < lower:
self._trend = -1
if prev_trend <= 0 and self._trend > 0 and self.Position <= 0:
self.BuyMarket()
elif prev_trend >= 0 and self._trend < 0 and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return ma_channel_strategy()