Auf GitHub ansehen

VR Setka Gitter-Strategie

Diese Strategie ist eine StockSharp-Implementierung des MetaTrader-Gittersystems "VR---SETKAa3hM". Sie eröffnet eine Abfolge von Kauf- oder Verkaufsorders basierend auf der prozentualen Abweichung vom Tagesbereich und erhöht optional das Volumen mithilfe eines Martingale-Multiplikators. Der durchschnittliche Einstiegspreis aller offenen Orders wird verfolgt, um ein einheitliches Take-Profit-Ziel zu setzen.

Parameter

  • Distance: Preisabstand in Punkten zwischen den Gitterniveaus.
  • TakeProfit: Gewinnziel in Punkten für die Erstorder.
  • Correction: Zusätzlicher Gewinn in Punkten, der zum Durchschnittspreis addiert wird, wenn mehr als eine Order offen ist.
  • SignalPercent: Prozentschwelle zur Erkennung der Abweichung vom Tagesbereich.
  • UseMartingale: Volumen mit der Anzahl offener Orders multiplizieren.
  • CandleType: Kerzen-Zeitrahmen für Signalberechnungen.

Logik

  1. Wenn eine abgeschlossene Kerze erscheint, wird der aktuelle Schlusskurs in Relation zum Tageshoch und -tief berechnet.
  2. Wenn die vorherige Kerze bullisch war und der Schlusskurs ausreichend unter dem Tageshoch liegt, wird ein Kaufgitter gestartet oder fortgesetzt.
  3. Wenn die vorherige Kerze bärisch war und der Schlusskurs ausreichend über dem Tagestief liegt, wird ein Verkaufsgitter gestartet oder fortgesetzt.
  4. Zusätzliche Orders werden platziert, wenn der Preis um Distance Punkte gegen die Position läuft.
  5. Sobald der Preis zum durchschnittlichen Einstiegspreis plus Correction für Käufe oder minus Correction für Verkäufe zurückkehrt, werden alle Positionen mit einer Market-Order geschlossen.
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>
/// EMA trend + candle direction strategy (converted from grid).
/// </summary>
public class VrSetkaGridStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEma;
	private decimal _prevClose;
	private bool _hasPrev;

	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public VrSetkaGridStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period for trend", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Base candle series", "General");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevEma = 0;
		_prevClose = 0;
		_hasPrev = false;
	}

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

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };

		SubscribeCandles(CandleType)
			.Bind(ema, ProcessCandle)
			.Start();
	}

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

		var close = candle.ClosePrice;

		if (!_hasPrev)
		{
			_prevEma = emaValue;
			_prevClose = close;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevClose <= _prevEma && close > emaValue;
		var crossDown = _prevClose >= _prevEma && close < emaValue;

		if (crossUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevEma = emaValue;
		_prevClose = close;
	}
}