Открыть на GitHub

Стратегия Layered Risk Protector

Обзор

Layered Risk Protector Strategy — это прямая конверсия советника MetaTrader «RiskManager». Алгоритм непрерывно отслеживает эквити портфеля и управляет рыночной нагрузкой с помощью индикатора Commodity Channel Index (CCI), множителей Average True Range (ATR) и послойной модели наращивания позиций. Когда риск-показатели опускаются ниже заданных порогов, стратегия автоматически переходит в режим хеджирования, фиксирует позиции при достижении целевых уровней прибыли или просадки и при необходимости закрывает их на уровне безубыточности.

Логика торговли

  • Индикаторные условия – стратегия подписывается на основную серию свечей (таймфрейм задаётся пользователем) и рассчитывает:
    • CCI с заданным периодом. Для открытия длинной позиции значение CCI должно опуститься ниже отрицательного порога, для короткой — подняться выше положительного.
    • ATR с фиксированным периодом 14 для вычисления волатильностных расстояний стоп-лосса и тейк-профита каждой открываемой ступени.
    • Скользящее среднее объёмов за последние 50 завершённых свечей. Торговля разрешается только когда среднее превышает объём предыдущей свечи — это воспроизводит фильтр «Active» из оригинала.
  • Послойные входы – максимальная нагрузка распределяется по настраиваемому количеству слоёв. Каждый новый ордер использует объём MaxVolume / Layers. Дополнительные входы блокируются, если относительное использование слоёв (Orders / Layers * 100) превышает текущий уровень «здоровья» системы.
  • Управление ордерами – каждая ступень хранит цену входа и уровни стоп-лосса/тейк-профита, рассчитанные по ATR. На каждой завершённой свече проверяются максимум и минимум для определения срабатывания защитных уровней и закрытия ордеров.
  • Режим хеджирования – если MultiPairTrading = false и уровень здоровья падает ниже HedgeLevel, стратегия запоминает текущее количество ордеров и открывает встречные позиции до выполнения требования по HedgeRatio. Когда здоровье восстанавливается выше порога, хедж автоматически отключается.
  • Контроль эквити – реализованы следующие защиты, повторяющие поведение советника:
    • Жёсткий стоп по капиталу, задаваемый параметром RiskLimit (начальный капитал минус допустимый риск).
    • Прибыльная цель как добавка к начальному капиталу.
    • Скользящий уровень «Close Equity», который после полного закрытия позиций повышается на величину CloseProfitBuffer от текущего баланса.
    • Опциональное закрытие на уровне безубыточности при достижении сохранённого значения капитала.
    • Ручной переключатель HardClose, моментально сворачивающий все позиции и приостанавливающий торговлю.

Параметры

  • AllowLong / AllowShort – разрешение на открытие длинных или коротких позиций.
  • MaxVolume – суммарный объём позиций, распределяемый между слоями.
  • Layers – максимальное число одновременно открытых слоёв.
  • CciLength / CciLevel – период и порог CCI.
  • StopLossMultiple / TakeProfitMultiple – множители ATR для расчёта стоп-лосса и тейк-профита каждого слоя.
  • CloseProfitBuffer – прибыль, добавляемая к балансу при обновлении уровня Close Equity; также используется при расчёте безубыточного капитала.
  • ManualCapital – ручное задание стартового капитала для риск-менеджмента (0 — использовать текущий баланс портфеля при запуске).
  • RiskLimit – максимально допустимая просадка от стартового капитала.
  • ProfitTarget – добавочная прибыльная цель, при достижении которой торговля приостанавливается.
  • MultiPairTrading – если true, внутреннее хеджирование не запускается даже при снижении здоровья ниже порога.
  • HedgeLevel / HedgeRatio – уровень здоровья для старта хеджирования и требуемое соотношение дополнительных ордеров в режиме хеджа.
  • CloseAtBreakEven – включает логику выхода по безубытку.
  • HardClose – принудительно закрывает позиции и блокирует торговлю, пока параметр активен.
  • CandleType – тип свечей, используемых для расчётов и принятия решений.

Примечания

  • Предполагается мгновенное исполнение рыночных ордеров; в режиме тестирования фактическая модель исполнения определяется настройками StockSharp.
  • Данные об эквити и балансе берутся из подключённого портфеля (Portfolio.CurrentValue, Portfolio.CurrentBalance). Убедитесь, что портфель синхронизирован с торгуемым инструментом.
  • Режим хеджирования открывает дополнительные сделки по тому же инструменту. Проверьте, допускает ли брокер или тестовый стенд противоположные позиции.
  • Логика безубыточности использует значение CloseProfitBuffer, повторяя оригинальный параметр MetaTrader ClosePL.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "Risk Manager Layered" MetaTrader expert.
/// Uses CCI crossover for entry with position management. CCI above level -> sell,
/// CCI below negative level -> buy, with volume-based confirmation.
/// </summary>
public class LayeredRiskProtectorStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cciLength;
	private readonly StrategyParam<decimal> _cciLevel;

	private CommodityChannelIndex _cci;
	private decimal? _prevCci;

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

	public int CciLength
	{
		get => _cciLength.Value;
		set => _cciLength.Value = value;
	}

	public decimal CciLevel
	{
		get => _cciLevel.Value;
		set => _cciLevel.Value = value;
	}

	public LayeredRiskProtectorStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Primary candle series", "General");

		_cciLength = Param(nameof(CciLength), 100)
			.SetGreaterThanZero()
			.SetDisplay("CCI Length", "CCI indicator period", "Indicators");

		_cciLevel = Param(nameof(CciLevel), 150m)
			.SetGreaterThanZero()
			.SetDisplay("CCI Level", "CCI threshold for entries", "Indicators");
	}

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

		_cci = new CommodityChannelIndex { Length = CciLength };
		_prevCci = null;

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

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

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

		if (!_cci.IsFormed)
		{
			_prevCci = cciValue;
			return;
		}

		if (_prevCci is null)
		{
			_prevCci = cciValue;
			return;
		}

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		// CCI crosses below -level -> buy
		var buyCross = _prevCci.Value >= -CciLevel && cciValue < -CciLevel;
		// CCI crosses above +level -> sell
		var sellCross = _prevCci.Value <= CciLevel && cciValue > CciLevel;

		if (buyCross)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (sellCross)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevCci = cciValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_cci = null;
		_prevCci = null;

		base.OnReseted();
	}
}