Открыть на GitHub

Стратегия Darvas Boxes System

Обзор

Стратегия реализует пробойный подход на основе классической концепции Darvas Boxes. Для построения динамического ценового диапазона используется индикатор Donchian Channels. При закрытии цены выше верхней границы коробки открывается длинная позиция. При закрытии ниже нижней границы открывается короткая позиция. Дополнительно поддерживаются уровни стоп-лосса и тейк-профита для управления рисками.

Как это работает

  1. Для каждой свечи индикатор Donchian Channels рассчитывает верхнюю и нижнюю границы на основе параметра BoxPeriod.
  2. Стратегия отслеживает предыдущие значения границ для обнаружения пробоя.
  3. Если текущая цена закрытия пересекает сверху предыдущую верхнюю границу:
    • Закрывается открытая короткая позиция (если разрешено).
    • Открывается длинная позиция (если разрешено).
  4. Если текущая цена закрытия пересекает снизу предыдущую нижнюю границу:
    • Закрывается открытая длинная позиция (если разрешено).
    • Открывается короткая позиция (если разрешено).
  5. Открытые позиции контролируются на предмет достижения стоп-лосса или тейк-профита.

Параметры

  • BoxPeriod (int): Количество свечей для расчёта коробки. По умолчанию 20.
  • StopLoss (decimal): Расстояние от цены входа до уровня стоп-лосса. По умолчанию 1000.
  • TakeProfit (decimal): Расстояние от цены входа до уровня тейк-профита. По умолчанию 2000.
  • AllowBuyEntry (bool): Разрешить открытие длинных позиций. По умолчанию true.
  • AllowSellEntry (bool): Разрешить открытие коротких позиций. По умолчанию true.
  • AllowBuyExit (bool): Разрешить закрытие длинных позиций по обратному сигналу или риску. По умолчанию true.
  • AllowSellExit (bool): Разрешить закрытие коротких позиций по обратному сигналу или риску. По умолчанию true.
  • CandleType (DataType): Тип свечей, используемых в расчётах. По умолчанию 4-часовые свечи.

Использование

  1. Подключите стратегию к инструменту и настройте параметры.
  2. Запустите стратегию. Она подпишется на нужную серию свечей и начнёт обработку данных.
  3. Сделки выполняются рыночными ордерами при выполнении условий пробоя.
  4. Стоп-лосс и тейк-профит контролируют открытые позиции.

Примечания

  • Используется высокоуровневый API с методом BindEx для получения значений индикатора.
  • Внутренние коллекции не используются; все расчёты основаны на передаваемых значениях.
  • Обрабатываются только завершённые свечи для надёжных сигналов.
  • Комментарии в коде приведены на английском языке, как требуется.
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>
/// Darvas Boxes breakout strategy using Donchian Channels.
/// Opens long position when price breaks above the upper box line.
/// Opens short position when price breaks below the lower box line.
/// </summary>
public class DarvasBoxesSystemStrategy : Strategy
{
	private readonly StrategyParam<int> _boxPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevUpper;
	private decimal _prevLower;
	private decimal _prevClose;

	public int BoxPeriod
	{
		get => _boxPeriod.Value;
		set => _boxPeriod.Value = value;
	}

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

	public DarvasBoxesSystemStrategy()
	{
		_boxPeriod = Param(nameof(BoxPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Box Period", "Period for box calculation", "Indicators")
			.SetOptimize(10, 40, 5);

		_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();
		_prevUpper = 0m;
		_prevLower = 0m;
		_prevClose = 0m;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevUpper = 0m;
		_prevLower = 0m;
		_prevClose = 0m;

		var donchian = new DonchianChannels { Length = BoxPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(donchian, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (value is not IDonchianChannelsValue box)
			return;

		if (box.UpperBand is not decimal upper || box.LowerBand is not decimal lower)
			return;

		if (_prevUpper == 0m)
		{
			_prevUpper = upper;
			_prevLower = lower;
			_prevClose = candle.ClosePrice;
			return;
		}

		var isUpBreakout = candle.ClosePrice > _prevUpper && _prevClose <= _prevUpper;
		var isDownBreakout = candle.ClosePrice < _prevLower && _prevClose >= _prevLower;

		if (isUpBreakout && Position <= 0)
			BuyMarket();
		else if (isDownBreakout && Position >= 0)
			SellMarket();

		_prevUpper = upper;
		_prevLower = lower;
		_prevClose = candle.ClosePrice;
	}
}