Открыть на GitHub

Стратегия Exp Sinewave2 X2

Описание

Exp Sinewave2 X2 — мультифреймовая трендовая стратегия, основанная на идеях Джона Элерса. Старший таймфрейм задаёт направление, младший отвечает за точку входа и своевременный выход. Все расчёты выполняются переписанным индикатором Sinewave2, который включает адаптивный модуль CyclePeriod для сохранения совместимости с оригиналом на MQL.

Используемые индикаторы

  • Sinewave2 на старшем таймфрейме — сравнение линии Lead и основной линии определяет доминирующий тренд.
  • Sinewave2 на младшем таймфрейме — фиксирует последние пересечения и генерирует торговые сигналы в сторону тренда.

Логика работы

  1. Фильтр тренда
    • Рассчитать Sinewave2 на старшем таймфрейме.
    • Взять значения линий на SignalBarHigh баров назад.
    • Если Lead > Sine — тренд бычий, если Lead < Sine — тренд медвежий, иначе нейтральный.
  2. Сигналы входа
    • Дождаться закрытия бара младшего таймфрейма.
    • Прочитать значения Lead и Sine на смещениях SignalBarLow и SignalBarLow + 1.
    • Лонг: предыдущее пересечение было сверху вниз, текущий бар возвращает Lead ниже Sine, тренд старшего таймфрейма бычий и включён EnableBuyOpen.
    • Шорт: предыдущее пересечение было снизу вверх, текущий бар выводит Lead выше Sine, тренд старшего таймфрейма медвежий и включён EnableSellOpen.
  3. Выходы
    • Флаги EnableBuyCloseLower / EnableSellCloseLower закрывают позиции при обратном пересечении на младшем таймфрейме.
    • Флаги EnableBuyCloseTrend / EnableSellCloseTrend закрывают позицию сразу после смены тренда на старшем таймфрейме.
    • Стоп-лосс и тейк-профит проверяются по максимуму/минимуму бара с учётом расстояний StopLossPoints и TakeProfitPoints в шагах цены.
  4. Управление рисками
    • При реверсе объём заявки равен Volume + |Position|, что одновременно закрывает текущую позицию и открывает новую.
    • После входа вызывается SetRiskLevels, который конвертирует точечные параметры в абсолютные цены через Security.PriceStep (если шаг цены неизвестен, используется 1).

Параметры

Название Описание
AlphaHigh Коэффициент сглаживания Sinewave2 на старшем таймфрейме.
AlphaLow Коэффициент сглаживания Sinewave2 на младшем таймфрейме.
SignalBarHigh Число баров для оценки тренда на старшем таймфрейме.
SignalBarLow Число баров для анализа пересечений на младшем таймфрейме.
EnableBuyOpen / EnableSellOpen Разрешение на открытие длинных/коротких позиций.
EnableBuyCloseTrend / EnableSellCloseTrend Принудительное закрытие при смене тренда старшего таймфрейма.
EnableBuyCloseLower / EnableSellCloseLower Закрытие при обратном пересечении на младшем таймфрейме.
StopLossPoints Дистанция стоп-лосса в шагах цены.
TakeProfitPoints Дистанция тейк-профита в шагах цены.
HigherCandleType / LowerCandleType Типы данных (таймфреймы) для фильтра и сигналов.

Примечания

  • Стратегия работает только с закрытыми барами и игнорирует незавершённые свечи.
  • Индикаторы Sinewave2 и CyclePeriod реализованы по классической методике Элерса, что облегчает сопоставление результатов с кодом MQL.
  • При совпадении таймфреймов старшего и младшего уровней используется одна подписка на свечи, чтобы не перегружать канал данных.
  • Объём сделок задаётся свойством Volume базового класса Strategy и должен быть настроен перед запуском.
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>
/// Ehlers Sinewave X2 strategy (simplified). Uses CCI oscillator for entries.
/// </summary>
public class ExpSinewave2X2Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cciLength;
	private readonly StrategyParam<int> _emaLength;

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

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

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

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

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

		_emaLength = Param(nameof(EmaLength), 30)
			.SetGreaterThanZero()
			.SetDisplay("EMA Length", "Trend filter EMA", "Indicators");
	}

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

		var cci = new CommodityChannelIndex { Length = CciLength };
		var ema = new ExponentialMovingAverage { Length = EmaLength };

		decimal prevCci = 0;
		bool hasPrev = false;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(cci, ema, (ICandleMessage candle, decimal cciValue, decimal emaValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!hasPrev)
				{
					prevCci = cciValue;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevCci = cciValue;
					return;
				}

				// CCI crosses above -100 with price above EMA
				if (prevCci < -100 && cciValue >= -100 && candle.ClosePrice > emaValue && Position <= 0)
				{
					BuyMarket();
				}
				// CCI crosses below 100 with price below EMA
				else if (prevCci > 100 && cciValue <= 100 && candle.ClosePrice < emaValue && Position >= 0)
				{
					SellMarket();
				}

				prevCci = cciValue;
			})
			.Start();

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