Ein ATR-basiertes Kanalausbruch-Scalping-System. Für jede Kerze wird der Mittelpunkt als Durchschnitt von Hoch und Tief berechnet. Die obere und untere Bande werden durch Addition und Subtraktion des Average True Range multipliziert mit einem Faktor aufgebaut. Wenn der Schlusskurs die vorherige obere Bande durchbricht, wird eine Long-Position eröffnet. Ein Durchbruch unter die untere Bande löst eine Short-Position aus. Die Banden folgen der Handelsrichtung und dienen als dynamische Stops; ein Kreuzen der gegenüberliegenden Bande kehrt die Position um.
Details
Einstiegskriterien:
Kauf: Der Schlusskurs kreuzt über die vorherige obere Bande.
Verkauf: Der Schlusskurs kreuzt unter die vorherige untere Bande.
Long/Short: Beide Richtungen.
Ausstiegskriterien:
Umkehrsignal, wenn der Preis die gegenüberliegende Bande kreuzt.
Stops: Trailing-Kanalbänder fungieren als Stops.
Filter: Keine.
Parameter
ATR Period – Anzahl der Balken für die ATR-Berechnung.
ATR Multiplier – Faktor, der auf den ATR für den Bandenabstand angewendet wird.
Candle Type – Zeitrahmen der Eingabekerzen.
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>
/// StdDev based channel breakout scalping strategy.
/// </summary>
public class ChannelScalperStrategy : Strategy
{
private readonly StrategyParam<int> _stdevPeriod;
private readonly StrategyParam<decimal> _multiplier;
private readonly StrategyParam<DataType> _candleType;
private decimal _up;
private decimal _down;
private int _direction;
private bool _isInitialized;
public int StdevPeriod { get => _stdevPeriod.Value; set => _stdevPeriod.Value = value; }
public decimal Multiplier { get => _multiplier.Value; set => _multiplier.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ChannelScalperStrategy()
{
_stdevPeriod = Param(nameof(StdevPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("StdDev Period", "Standard deviation period", "General");
_multiplier = Param(nameof(Multiplier), 1.5m)
.SetDisplay("Multiplier", "Channel width multiplier", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle Type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_up = 0;
_down = 0;
_direction = 0;
_isInitialized = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var stdev = new StandardDeviation { Length = StdevPeriod };
SubscribeCandles(CandleType).Bind(stdev, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal stdevValue)
{
if (candle.State != CandleStates.Finished || stdevValue <= 0) return;
var middle = (candle.HighPrice + candle.LowPrice) / 2;
var currentUp = middle + Multiplier * stdevValue;
var currentDown = middle - Multiplier * stdevValue;
if (!_isInitialized)
{
_up = currentUp;
_down = currentDown;
_isInitialized = true;
return;
}
if (_direction <= 0 && candle.ClosePrice > _up)
{
if (Position < 0) BuyMarket();
BuyMarket();
_direction = 1;
}
else if (_direction >= 0 && candle.ClosePrice < _down)
{
if (Position > 0) SellMarket();
SellMarket();
_direction = -1;
}
if (_direction > 0)
currentDown = Math.Max(currentDown, _down);
else if (_direction < 0)
currentUp = Math.Min(currentUp, _up);
_up = currentUp;
_down = currentDown;
}
}