Auf GitHub ansehen

ScalpWiz Bollinger-Strategie

Überblick

Die ScalpWiz Bollinger-Strategie ist ein Gegentrendsystem, das Bollinger-Bänder verwendet, um überdehnte Preise zu erkennen. Wenn sich der Schlusskurs weit über das obere oder unter das untere Band bewegt, eröffnet die Strategie eine Position in entgegengesetzter Richtung und erwartet eine Rückkehr.

Vier Distanzebenen werden geprüft. Jede Ebene entspricht einer anderen Signalstärke und multipliziert das Handelsvolumen. Die Positionsgröße wird außerdem durch einen Risikoprozentsatz des aktuellen Portfoliowerts skaliert.

Parameter

  • BandsPeriod – Anzahl der Kerzen für die Berechnung der Bollinger-Bänder.
  • BandsDeviation – Standardabweichungs-Multiplikator für die Bänder.
  • Level1PipsLevel4Pips – Abstand vom Band in Pips, der ein Level-1–4-Signal auslöst.
  • StrengthLevel1MultiplierStrengthLevel4Multiplier – Volumenmultiplikatoren für jede Ebene.
  • RiskPercent – Prozentsatz des Portfoliowerts, der pro Signal riskiert wird.
  • CandleType – Kerzen-Zeitrahmen für die Berechnungen.

Handelslogik

  1. Abonnieren von Kerzen des ausgewählten Zeitrahmens und Berechnung der Bollinger-Bänder.
  2. Bei jeder abgeschlossenen Kerze:
    • Liegt der Schlusskurs um eine konfigurierte Levelentfernung über dem oberen Band, wird eine Short-Position eröffnet.
    • Liegt der Schlusskurs um eine konfigurierte Levelentfernung unter dem unteren Band, wird eine Long-Position eröffnet.
  3. Das Volumen wird aus dem Risikoprozentsatz und dem Signalstärke-Multiplikator berechnet.

Die Strategie wurde durch das originale MQL-Skript mcb.scalpwiz.9001.mq4 inspiriert.

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>
/// Bollinger-based reverse scalping strategy.
/// Places counter-trend orders when price deviates from the bands.
/// Position size scales with signal strength and risk percentage.
/// </summary>
public class ScalpWizBollingerStrategy : Strategy
{
	private readonly StrategyParam<int> _bandsPeriod;
	private readonly StrategyParam<decimal> _bandsDeviation;
	private readonly StrategyParam<decimal> _level1Pips;
	private readonly StrategyParam<decimal> _level2Pips;
	private readonly StrategyParam<decimal> _level3Pips;
	private readonly StrategyParam<decimal> _level4Pips;
	private readonly StrategyParam<int> _multiplier1;
	private readonly StrategyParam<int> _multiplier2;
	private readonly StrategyParam<int> _multiplier3;
	private readonly StrategyParam<int> _multiplier4;
	private readonly StrategyParam<int> _riskPercent;
	private readonly StrategyParam<DataType> _candleType;
	
	public int BandsPeriod { get => _bandsPeriod.Value; set => _bandsPeriod.Value = value; }
	public decimal BandsDeviation { get => _bandsDeviation.Value; set => _bandsDeviation.Value = value; }
	public decimal Level1Pips { get => _level1Pips.Value; set => _level1Pips.Value = value; }
	public decimal Level2Pips { get => _level2Pips.Value; set => _level2Pips.Value = value; }
	public decimal Level3Pips { get => _level3Pips.Value; set => _level3Pips.Value = value; }
	public decimal Level4Pips { get => _level4Pips.Value; set => _level4Pips.Value = value; }
	public int StrengthLevel1Multiplier { get => _multiplier1.Value; set => _multiplier1.Value = value; }
	public int StrengthLevel2Multiplier { get => _multiplier2.Value; set => _multiplier2.Value = value; }
	public int StrengthLevel3Multiplier { get => _multiplier3.Value; set => _multiplier3.Value = value; }
	public int StrengthLevel4Multiplier { get => _multiplier4.Value; set => _multiplier4.Value = value; }
	public int RiskPercent { get => _riskPercent.Value; set => _riskPercent.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	
	/// <summary>
	/// Constructor.
	/// </summary>
	public ScalpWizBollingerStrategy()
	{
		_bandsPeriod = Param(nameof(BandsPeriod), 30)
		.SetGreaterThanZero()
		.SetDisplay("Bands Period", "Number of candles for Bollinger calculation", "Bollinger")
		
		.SetOptimize(20, 40, 5);
		
		_bandsDeviation = Param(nameof(BandsDeviation), 2m)
		.SetGreaterThanZero()
		.SetDisplay("Bands Deviation", "Standard deviation multiplier", "Bollinger")
		
		.SetOptimize(1m, 3m, 0.5m);
		
		_level1Pips = Param(nameof(Level1Pips), 1m)
		.SetGreaterThanZero()
		.SetDisplay("Level1 Pips", "Deviation from band for weakest signal", "Levels");

		_level2Pips = Param(nameof(Level2Pips), 5m)
		.SetGreaterThanZero()
		.SetDisplay("Level2 Pips", "Deviation from band for level 2", "Levels");

		_level3Pips = Param(nameof(Level3Pips), 10m)
		.SetGreaterThanZero()
		.SetDisplay("Level3 Pips", "Deviation from band for level 3", "Levels");

		_level4Pips = Param(nameof(Level4Pips), 20m)
		.SetGreaterThanZero()
		.SetDisplay("Level4 Pips", "Deviation from band for strongest signal", "Levels");
		
		_multiplier1 = Param(nameof(StrengthLevel1Multiplier), 1)
		.SetGreaterThanZero()
		.SetDisplay("Strength 1 Multiplier", "Volume multiplier for level 1", "Strength");
		
		_multiplier2 = Param(nameof(StrengthLevel2Multiplier), 2)
		.SetGreaterThanZero()
		.SetDisplay("Strength 2 Multiplier", "Volume multiplier for level 2", "Strength");
		
		_multiplier3 = Param(nameof(StrengthLevel3Multiplier), 3)
		.SetGreaterThanZero()
		.SetDisplay("Strength 3 Multiplier", "Volume multiplier for level 3", "Strength");
		
		_multiplier4 = Param(nameof(StrengthLevel4Multiplier), 4)
		.SetGreaterThanZero()
		.SetDisplay("Strength 4 Multiplier", "Volume multiplier for level 4", "Strength");
		
		_riskPercent = Param(nameof(RiskPercent), 2)
		.SetGreaterThanZero()
		.SetDisplay("Risk %", "Risk percentage per trade", "General");
		
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
		.SetDisplay("Candle Type", "Type of candles to use", "General");
	}
	
	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}
	
	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		
		var bollinger = new BollingerBands
		{
			Length = BandsPeriod,
			Width = BandsDeviation
		};
		
		var subscription = SubscribeCandles(CandleType);
		
		subscription
		.BindEx(bollinger, ProcessCandle)
		.Start();
	}
	
	private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var bb = (BollingerBandsValue)value;
		
		if (bb.UpBand is not decimal upper || bb.LowBand is not decimal lower)
		return;
		
		var step = Security?.PriceStep ?? 0.0001m;
		var close = candle.ClosePrice;
		
		if (close - upper > Level4Pips * step)
		{
			SellByStrength(StrengthLevel4Multiplier, close);
		}
		else if (close - upper > Level3Pips * step)
		{
			SellByStrength(StrengthLevel3Multiplier, close);
		}
		else if (close - upper > Level2Pips * step)
		{
			SellByStrength(StrengthLevel2Multiplier, close);
		}
		else if (close - upper > Level1Pips * step)
		{
			SellByStrength(StrengthLevel1Multiplier, close);
		}
		else if (lower - close > Level4Pips * step)
		{
			BuyByStrength(StrengthLevel4Multiplier, close);
		}
		else if (lower - close > Level3Pips * step)
		{
			BuyByStrength(StrengthLevel3Multiplier, close);
		}
		else if (lower - close > Level2Pips * step)
		{
			BuyByStrength(StrengthLevel2Multiplier, close);
		}
		else if (lower - close > Level1Pips * step)
		{
			BuyByStrength(StrengthLevel1Multiplier, close);
		}
	}
	
	private void BuyByStrength(int strength, decimal price)
	{
		BuyMarket();
	}

	private void SellByStrength(int strength, decimal price)
	{
		SellMarket();
	}
}