Auf GitHub ansehen

Avalanche AV Strategy

Avalanche AV is a randomized martingale strategy that alternates between long and short entries with equal probability. Trades are opened only after a configurable number of finished candles, and every position inherits fixed stop-loss and take-profit levels defined in pips. When a trade closes at a loss the position size is multiplied by the martingale coefficient to chase recovery; profitable trades reset the size back to the starting volume once the account balance prints a new equity high. The strategy also enforces a maximum floating drawdown as a percentage of account balance and will close any position that breaches this threshold.

The original MQL version opened trades on ticks. The StockSharp port keeps the same probabilistic behaviour but works on candle updates, making it suitable for both backtesting and live trading with bar data.

Trading Rules

  • Decision interval: wait for the specified number of finished candles before evaluating a new signal. If a position is still open the interval continues counting but no new trade is taken.
  • Entry direction: generate a random number; values above 16384 trigger a long entry, otherwise a short entry. Positions are opened only when there is no active trade.
  • Order size: start with InitialVolume. After each losing trade the next order size becomes PreviousVolume * MartingaleMultiplier (normalized to the instrument's volume step). Winning trades reset the size to InitialVolume once the realised balance makes a new peak; otherwise the martingale expansion continues.
  • Stops and targets: stop-loss and take-profit are calculated in pips from the entry price. A pip equals the instrument's price step.
  • Floating drawdown: while a position is active, the strategy monitors unrealised PnL. If the loss exceeds MaxDrawdownPercent of the realised account balance (initial balance + realised PnL), the position is closed immediately.

Parameters

Parameter Default Description
InitialVolume 0.1 Starting trade volume.
StopLossPips 15 Stop distance in pips (0 disables the stop).
TakeProfitPips 30 Take profit distance in pips (0 disables the target).
MaxDrawdownPercent 75 Maximum tolerated floating loss as percent of balance.
MartingaleMultiplier 1.6 Volume multiplier applied after a loss.
DecisionInterval 9 Number of finished candles between new trade decisions.
CandleType 1-minute time frame Candle type driving the strategy.

Notes

  • Volume is automatically normalized to the instrument's VolumeStep, MinVolume, and MaxVolume limits. If normalization fails the size resets to the initial volume.
  • Stop-loss and take-profit levels rely on the instrument's PriceStep as one pip; verify the step for exotic symbols.
  • The drawdown protection requires both PriceStep and StepPrice to be defined; otherwise the safety check is skipped.
  • Because the strategy relies on randomness, results vary between runs even with identical market data unless the random seed is controlled externally.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Avalanche strategy using channel breakout with Highest/Lowest.
/// </summary>
public class AvalancheAvStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _period;

	private decimal? _prevHigh;
	private decimal? _prevLow;

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

	public int Period
	{
		get => _period.Value;
		set => _period.Value = value;
	}

	public AvalancheAvStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_period = Param(nameof(Period), 14)
			.SetGreaterThanZero()
			.SetDisplay("Period", "Channel period", "Indicators");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevHigh = null;
		_prevLow = null;
	}

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

		_prevHigh = null;
		_prevLow = null;

		var highest = new Highest { Length = Period };
		var lowest = new Lowest { Length = Period };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevHigh = high;
			_prevLow = low;
			return;
		}

		var close = candle.ClosePrice;

		if (_prevHigh == null || _prevLow == null)
		{
			_prevHigh = high;
			_prevLow = low;
			return;
		}

		if (close > _prevHigh.Value && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (close < _prevLow.Value && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevHigh = high;
		_prevLow = low;
	}
}