Открыть на GitHub

Стратегия ZigZag Climber

Общее описание

Советник ZigZag Climber, созданный в fxDreema, состоит всего из трёх блоков: фильтра No trade, за которым сразу следуют действия Buy now и Sell now. Как только терминал обнаруживает отсутствие открытых позиций, он моментально отправляет рыночную покупку с заранее заданными стоп-лоссом и тейк-профитом, а затем без дополнительных проверок регистрирует симметричную рыночную продажу. Оба ордера наследуют одинаковые параметры риска и задуманы как хеджированная пара.

Порт на C# воспроизводит это поведение в StockSharp: стратегия ждёт первой полностью сформированной свечи выбранного таймфрейма и отправляет заявки на покупку и продажу подряд, используя одинаковые защитные расстояния. Никаких дополнительных сигналов, сопровождения позиций или трейлинг-стопов здесь нет — ровно как в исходном проекте MQL.

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

  1. Дождаться полного формирования первой свечи настроенного таймфрейма.
  2. Если торговля разрешена и ордера ещё не выставлялись, отправить рыночную покупку фиксированным объёмом.
  3. Привязать к длинной позиции стоп-лосс и тейк-профит, указанные в пунктах MetaTrader (значения переводятся через PriceStep).
  4. Немедленно отправить рыночную продажу тем же объёмом и навесить зеркальные защитные уровни.
  5. Больше не открывать сделок в рамках текущего запуска.

Важно. MetaTrader 4 работает в хеджинговом режиме, поэтому обе стороны могут существовать одновременно. StockSharp следует модели брокера: на неттинговых счетах второй ордер закроет первый, и стратегия завершится без позиции. Используйте коннектор с поддержкой хеджинга (например, MT-шлюз с хеджевым счётом), если хотите сохранить обе ноги.

Параметры

Название Значение по умолчанию Описание
Candle Type 1 минута Таймфрейм, по закрытию свечи которого запускается единовременный вход.
Trade Volume 0.01 Фиксированный объём для обеих рыночных заявок.
Stop-Loss (pips) 99.9 Стоп-лосс в пунктах MetaTrader (автоматически учитываются 4- и 5-значные котировки).
Take-Profit (pips) 100 Тейк-профит в пунктах MetaTrader.

Все расстояния перед передачей в SetStopLoss/SetTakeProfit переводятся в цену через PriceStep и точность инструмента.

Управление рисками

Стратегия использует сервис StartProtection() и вспомогательные методы SetStopLoss/SetTakeProfit, чтобы сразу после рыночных заявок выставить защитные ордера. Трейлинг и перевод в безубыток не реализованы.

Практические замечания

  • Перед запуском выберите нужный инструмент и портфель. Для корректного пересчёта пунктов должны быть заданы PriceStep и Decimals.
  • Поскольку вход выполняется один раз, для повторного хедж-цикла необходимо перезапустить стратегию.
  • В неттинговом тестовом окружении результат будет отличаться от MetaTrader: продажа почти сразу обнулит покупку.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// ZigZag Climber strategy: Highest/Lowest channel breakout.
/// Buys when close >= highest, sells when close <= lowest.
/// </summary>
public class ZigZagClimberStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _channelPeriod;

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

	public int ChannelPeriod
	{
		get => _channelPeriod.Value;
		set => _channelPeriod.Value = value;
	}

	public ZigZagClimberStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_channelPeriod = Param(nameof(ChannelPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators");
	}

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

		var high = new Highest { Length = ChannelPeriod };
		var low = new Lowest { Length = ChannelPeriod };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (candle.ClosePrice >= high && Position <= 0)
		{
			BuyMarket();
		}
		else if (candle.ClosePrice <= low && Position >= 0)
		{
			SellMarket();
		}
	}
}