Auf GitHub ansehen

IU Größer-als-Range-Strategie

Ausbruchsstrategie, die Trades eröffnet, wenn der Kerzenkörper größer als die vorherige Handelsspanne der letzten Kerzen ist.

Das System vergleicht den aktuellen Kerzenkörper mit der Spanne zwischen dem höchsten und niedrigsten Eröffnungs-/Schlusskurs über einen konfigurierbaren Rückblickzeitraum. Überschreitet der Körper die vorherige Spanne, wird in Kerzenkörper-Richtung eingestiegen und das Risiko über konfigurierbare Stop-Methoden verwaltet.

Details

  • Einstiegskriterien: Kerzenkörper größer als vorherige Spanne; Richtung basiert auf dem Kerzenkörper.
  • Long/Short: Beide.
  • Ausstiegskriterien: Stop-Loss oder Take-Profit.
  • Stops: Vorherige Kerze, ATR oder Swing-Niveaus.
  • Standardwerte:
    • LookbackPeriod = 22
    • RiskToReward = 3
    • StopLossMethod = PreviousHighLow
    • AtrLength = 14
    • AtrFactor = 2m
    • SwingLength = 10
    • CandleType = TimeSpan.FromMinutes(1)
  • Filter:
    • Kategorie: Ausbruch
    • Richtung: Beide
    • Indikatoren: Highest, Lowest, ATR
    • Stops: Ja
    • Komplexität: Mittel
    • Zeitrahmen: Beliebig
    • Saisonalität: Nein
    • Neuronale Netze: Nein
    • Divergenz: Nein
    • Risikolevel: Mittel
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>
/// Breakout strategy that enters when the candle body exceeds the previous range.
/// </summary>
public class IuBiggerThanRangeStrategy : Strategy
{
	private readonly StrategyParam<int> _lookbackPeriod;
	private readonly StrategyParam<int> _riskToReward;
	private readonly StrategyParam<decimal> _atrFactor;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevRangeSize;
	private decimal _prevCandleHigh;
	private decimal _prevCandleLow;
	private decimal _stopPrice;
	private decimal _targetPrice;
	private decimal _entryPrice;
	private int _barCount;

	/// <summary>
	/// Lookback period for range calculation.
	/// </summary>
	public int LookbackPeriod
	{
		get => _lookbackPeriod.Value;
		set => _lookbackPeriod.Value = value;
	}

	/// <summary>
	/// Risk to reward ratio.
	/// </summary>
	public int RiskToReward
	{
		get => _riskToReward.Value;
		set => _riskToReward.Value = value;
	}

	/// <summary>
	/// ATR multiplier factor.
	/// </summary>
	public decimal AtrFactor
	{
		get => _atrFactor.Value;
		set => _atrFactor.Value = value;
	}

	/// <summary>
	/// Type of candles to process.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="IuBiggerThanRangeStrategy"/> class.
	/// </summary>
	public IuBiggerThanRangeStrategy()
	{
		_lookbackPeriod = Param(nameof(LookbackPeriod), 22)
			.SetDisplay("Lookback Period", "Length for range calculation.", "Parameters");

		_riskToReward = Param(nameof(RiskToReward), 3)
			.SetDisplay("Risk To Reward", "Risk to reward ratio.", "Parameters");

		_atrFactor = Param(nameof(AtrFactor), 2m)
			.SetDisplay("ATR Factor", "ATR multiplier.", "Risk Management");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles.", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRangeSize = 0m;
		_prevCandleHigh = 0m;
		_prevCandleLow = 0m;
		_stopPrice = 0m;
		_targetPrice = 0m;
		_entryPrice = 0m;
		_barCount = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevRangeSize = 0m;
		_prevCandleHigh = 0m;
		_prevCandleLow = 0m;
		_stopPrice = 0m;
		_targetPrice = 0m;
		_entryPrice = 0m;
		_barCount = 0;

		var atr = new AverageTrueRange { Length = LookbackPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(atr, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal atrValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		_barCount++;

		var rangeSize = candle.HighPrice - candle.LowPrice;
		var candleBody = Math.Abs(candle.ClosePrice - candle.OpenPrice);

		if (_barCount < LookbackPeriod)
		{
			_prevRangeSize = rangeSize;
			_prevCandleHigh = candle.HighPrice;
			_prevCandleLow = candle.LowPrice;
			return;
		}

		// Exit logic first
		if (Position > 0)
		{
			if (candle.LowPrice <= _stopPrice || candle.ClosePrice >= _targetPrice)
			{
				SellMarket();
				_stopPrice = 0m;
				_targetPrice = 0m;
				_entryPrice = 0m;
			}
		}
		else if (Position < 0)
		{
			if (candle.HighPrice >= _stopPrice || candle.ClosePrice <= _targetPrice)
			{
				BuyMarket();
				_stopPrice = 0m;
				_targetPrice = 0m;
				_entryPrice = 0m;
			}
		}

		// Entry logic
		var isBodyStrong = candleBody >= _prevRangeSize && candleBody >= atrValue * 0.8m;

		if (Position == 0 && isBodyStrong)
		{
			if (candle.ClosePrice > candle.OpenPrice && candle.ClosePrice > _prevCandleHigh)
			{
				BuyMarket();
				_entryPrice = candle.ClosePrice;
				_stopPrice = _entryPrice - atrValue * AtrFactor;
				_targetPrice = _entryPrice + (_entryPrice - _stopPrice) * RiskToReward;
			}
			else if (candle.ClosePrice < candle.OpenPrice && candle.ClosePrice < _prevCandleLow)
			{
				SellMarket();
				_entryPrice = candle.ClosePrice;
				_stopPrice = _entryPrice + atrValue * AtrFactor;
				_targetPrice = _entryPrice - (_stopPrice - _entryPrice) * RiskToReward;
			}
		}

		_prevRangeSize = rangeSize;
		_prevCandleHigh = candle.HighPrice;
		_prevCandleLow = candle.LowPrice;
	}
}