Auf GitHub ansehen

Scalping-EA-Strategie

Ein einfaches Scalping-System, das ständig zwei Pending Orders aufrecht erhält: ein Buy Stop oberhalb des Marktes und ein Sell Stop darunter. Wenn der Marktpreis einer Order zu nahe kommt oder sich zu weit entfernt, wird die Order ersetzt, um einen festen Abstand vom aktuellen Preis zu wahren. Ausgeführte Orders verwenden feste Take-Profit- und Stop-Loss-Abstände.

Die Strategie stützt sich nicht auf Indikatoren und reagiert ausschließlich auf Tick-Preisänderungen.

Details

  • Einstiegskriterien:
    • Buy Stop 100 Punkte über dem Preis und Sell Stop 100 Punkte darunter platzieren.
    • Orders werden ersetzt, wenn der Abstand zum Preis zu klein oder zu groß wird.
  • Long/Short: Beide.
  • Ausstiegskriterien:
    • Jede Order trägt festen Take Profit und Stop Loss.
  • Stops: Ja, fester Abstand.
  • Filter: Keine.
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>
/// Scalping strategy using RSI overbought/oversold with EMA trend filter.
/// Buys on RSI oversold in uptrend, sells on RSI overbought in downtrend.
/// </summary>
public class ScalpingEAStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _entryPrice;

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

	public ScalpingEAStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 7)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR period for stops", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_entryPrice = 0;
	}

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

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var atr = new StandardDeviation { Length = AtrPeriod };

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

	private void ProcessCandle(ICandleMessage candle, decimal rsi, decimal ema, decimal atr)
	{
		if (candle.State != CandleStates.Finished) return;
		if (atr <= 0) return;

		var close = candle.ClosePrice;

		// Buy: RSI oversold
		if (rsi < 35 && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_entryPrice = close;
		}
		// Sell: RSI overbought
		else if (rsi > 65 && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_entryPrice = close;
		}
		// Exit long: price crosses below EMA or stop loss
		else if (Position > 0)
		{
			if (close < ema || (_entryPrice > 0 && close <= _entryPrice - atr * 2))
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		// Exit short: price crosses above EMA or stop loss
		else if (Position < 0)
		{
			if (close > ema || (_entryPrice > 0 && close >= _entryPrice + atr * 2))
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}
	}
}