Auf GitHub ansehen

Up-Gap-Strategie mit Verzögerung

Diese Strategie eröffnet eine Long-Position, wenn die Sitzung mit einer Aufwärtslücke über einem Schwellenwert öffnet und eine bestimmte Anzahl von Bars seit dem vorherigen Einstieg vergangen ist. Die Position wird für eine feste Anzahl von Bars gehalten.

Details

  • Einstiegskriterien: Aufwärtslücke größer als Schwellenwert und Verzögerungsperiode erfüllt
  • Long/Short: Long
  • Ausstiegskriterien: nach Ablauf der Halteperiode
  • Stops: Nein
  • Standardwerte:
    • GapThreshold = 1
    • DelayPeriods = 0
    • HoldingPeriods = 7
  • Filter:
    • Kategorie: Muster
    • Richtung: Long
    • Indikatoren: Keine
    • Stops: Nein
    • Komplexität: Grundlegend
    • Zeitrahmen: Intraday
    • Saisonalität: Nein
    • Neuronale Netze: Nein
    • Divergenz: Nein
    • Risikolevel: Mittel
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>
/// Up Gap With Delay strategy using RSI momentum with EMA trend filter.
/// </summary>
public class UpGapWithDelayStrategy : Strategy
{
	private readonly StrategyParam<decimal> _gapThreshold;
	private readonly StrategyParam<int> _delayPeriods;
	private readonly StrategyParam<int> _holdingPeriods;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevRsi;
	private decimal _prevFast;
	private decimal _prevSlow;
	private int _cooldown;

	public decimal GapThreshold { get => _gapThreshold.Value; set => _gapThreshold.Value = value; }
	public int DelayPeriods { get => _delayPeriods.Value; set => _delayPeriods.Value = value; }
	public int HoldingPeriods { get => _holdingPeriods.Value; set => _holdingPeriods.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public UpGapWithDelayStrategy()
	{
		_gapThreshold = Param(nameof(GapThreshold), 0.1m)
			.SetDisplay("Gap Threshold (%)", "Minimum gap size", "General");

		_delayPeriods = Param(nameof(DelayPeriods), 0)
			.SetDisplay("Delay Periods", "Bars to wait", "General");

		_holdingPeriods = Param(nameof(HoldingPeriods), 7)
			.SetGreaterThanZero()
			.SetDisplay("Holding Periods", "Bars to hold", "General");

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

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRsi = 0;
		_prevFast = 0;
		_prevSlow = 0;
		_cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var rsi = new RelativeStrengthIndex { Length = 14 };
		var emaFast = new ExponentialMovingAverage { Length = 8 };
		var emaSlow = new ExponentialMovingAverage { Length = 21 };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, emaFast, emaSlow, ProcessCandle).Start();

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

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

		if (_prevRsi == 0 || _prevFast == 0 || _prevSlow == 0)
		{
			_prevRsi = rsiVal;
			_prevFast = emaFast;
			_prevSlow = emaSlow;
			return;
		}

		if (_cooldown > 0)
		{
			_cooldown--;
			_prevRsi = rsiVal;
			_prevFast = emaFast;
			_prevSlow = emaSlow;
			return;
		}

		var hist = emaFast - emaSlow;
		var histUp = hist > 0m;
		var histDown = hist < 0m;

		var rsiCrossUp = _prevRsi <= 50m && rsiVal > 50m;
		var rsiCrossDown = _prevRsi >= 50m && rsiVal < 50m;

		// Exit
		if (Position > 0 && rsiCrossDown)
		{
			SellMarket();
			_cooldown = 80;
		}
		else if (Position < 0 && rsiCrossUp)
		{
			BuyMarket();
			_cooldown = 80;
		}

		// Entry
		if (Position == 0)
		{
			if (rsiCrossUp && histUp)
			{
				BuyMarket();
				_cooldown = 80;
			}
			else if (rsiCrossDown && histDown)
			{
				SellMarket();
				_cooldown = 80;
			}
		}

		_prevRsi = rsiVal;
		_prevFast = emaFast;
		_prevSlow = emaSlow;
	}
}