Открыть на GitHub

Стратегия Noah 10 Pips 2006

Краткое описание

  • Полностью повторяет алгоритм советника Noah10pips2006 для MetaTrader 4 в инфраструктуре StockSharp.
  • Использует диапазон предыдущей сессии для построения каналов и выставления стоп-заявок около средней цены.
  • Поддерживает фиксацию прибыли, последующее трейлинг-сопровождение и однократный реверс после закрытия первой позиции.

Алгоритм работы

  1. Расчёт диапазона
    В начале нового торгового дня (с учётом параметра TimeZoneOffset) стратегия запоминает максимум и минимум предыдущей сессии и рассчитывает:
    • Среднюю точку диапазона.
    • Буферные уровни на расстоянии 20 пунктов (pips) выше и ниже.
    • Зону входа: если диапазон ≤ 160 пунктов, используется фиксированные ±40 пунктов, иначе 25% от ширины диапазона.
  2. Первая заявка
    После наступления торгового окна проверяется последний закрытый бар:
    • Закрытие между средней и верхним буфером → размещается стоп-заявка на продажу по средней.
    • Закрытие между нижним буфером и средней → размещается стоп-заявка на покупку по средней.
      Заявки выставляются только при ширине зоны выше MinimumRangePips.
  3. Дополнительная заявка
    Если активна только одна стоп-заявка, добавляется противоположная по соответствующему буферному уровню, чтобы подготовиться к пробою в любую сторону.
  4. Сопровождение позиции
    • После срабатывания ордера выставляются защитные стоп-лосс и тейк-профит.
    • При достижении прибыли TrailSecureProfitPips стоп переносится на уровень, обеспечивающий SecureProfitPips.
    • При включённом TrailingStopPips стоп далее сопровождает цену с указанным шагом.
  5. Завершение дня
    Вне торгового окна и по пятничному дедлайну (FridayEndHour) все заявки и позиции закрываются.
  6. Реверс
    После закрытия первой позиции при отсутствии фиксации прибыли стратегия открывает рыночную позицию в противоположную сторону — так же, как оригинальный советник.

Основные параметры

  • CandleType — тип свечей для вычислений, по умолчанию 1 час.
  • TimeZoneOffset — смещение времени данных в часах.
  • StartHour/StartMinute, EndHour/EndMinute — границы торгового окна.
  • FridayEndHour, TradeFriday — настройка торговли по пятницам и принудительного закрытия.
  • StopLossPips, TakeProfitPips — дистанции защитных ордеров.
  • SecureProfitPips, TrailSecureProfitPips, TrailingStopPips — логика фиксации прибыли и трейлинг-стопа.
  • MinimumRangePips — минимальная ширина диапазона для постановки заявок.
  • MinVolume, MaxVolume, MaximumRiskPercent, FixedVolume — управление объёмом, эквивалент функции LotsRisk в MT4.

Практические рекомендации

  • Для риск-менеджмента инструмент должен иметь корректные PriceStep и StepPrice; иначе включите FixedVolume и задайте объём вручную.
  • Изменение защитных уровней происходит на закрытии свечи; при необходимости используйте более мелкий таймфрейм.
  • Константы 20/40 пунктов рассчитаны под четырёхзнаковый Forex. Для других инструментов адаптируйте параметры.
  • Графические объекты из MT4 не переносятся автоматически; их можно добавить через возможности графика StockSharp.
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>
/// Noah 10 Pips 2006 - session breakout strategy.
/// Tracks the previous session's high/low range.
/// Buys on breakout above the midpoint, sells on breakout below.
/// Uses Highest/Lowest indicators as channel reference.
/// </summary>
public class Noah10Pips2006Strategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevHigh;
	private decimal _prevLow;
	private decimal _prevMid;
	private decimal _prevClose;
	private bool _hasPrev;

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

	public Noah10Pips2006Strategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 24)
			.SetDisplay("Channel Period", "Lookback for high/low channel", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevHigh = 0m;
		_prevLow = 0m;
		_prevMid = 0m;
		_prevClose = 0m;
		_hasPrev = false;
	}

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

		_hasPrev = false;

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

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

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

		var close = candle.ClosePrice;
		var mid = (high + low) / 2m;

		if (!_hasPrev)
		{
			_prevHigh = high;
			_prevLow = low;
			_prevMid = mid;
			_prevClose = close;
			_hasPrev = true;
			return;
		}

		// Breakout above channel high - buy
		if (_prevClose <= _prevHigh && close > high && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Breakout below channel low - sell
		else if (_prevClose >= _prevLow && close < low && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
		// Cross above midpoint from below - buy signal
		else if (_prevClose <= _prevMid && close > mid && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Cross below midpoint from above - sell signal
		else if (_prevClose >= _prevMid && close < mid && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevHigh = high;
		_prevLow = low;
		_prevMid = mid;
		_prevClose = close;
	}
}