Открыть на GitHub

Стратегия Elliott Trader

Стратегия открывает ступенчатые позиции, когда стохастик на четырехчасовых свечах достигает экстремальных значений. Сначала отправляется рыночная заявка, затем выставляется сетка лимитных заявок на заданных расстояниях. Закрытие позиций происходит при достижении целевой прибыли и подтверждении тренда скользящими средними и полосами Боллинджера.

Правила входа

  • Используется стохастический осциллятор (%K 21, сглаживание 3) на свечах H4.
  • При %K ≥ Overbought:
    • Продаем по рынку.
    • Размещаем до восьми SellLimit ордеров выше текущей цены на заданные расстояния в пунктах.
  • При %K ≤ Oversold:
    • Покупаем по рынку.
    • Размещаем до восьми BuyLimit ордеров ниже текущей цены на заданные расстояния в пунктах.

Правила выхода

  • Когда реализованная прибыль достигает ProfitTarget и цена подтверждает тренд:
    • Длинные позиции закрываются, если цена выше нижней полосы Боллинджера и SMA(200) выше SMA(55).
    • Короткие позиции закрываются, если цена ниже верхней полосы Боллинджера и SMA(200) ниже SMA(55).
  • Висячие заявки на покупку отменяются при %K ≥ 90 и SMA(200) ≤ SMA(55).
  • Висячие заявки на продажу отменяются при %K ≤ 10 и SMA(200) ≥ SMA(55).

Параметры

  • StochLength – период %K стохастика.
  • OverboughtLevel – уровень для начала продаж.
  • OversoldLevel – уровень для начала покупок.
  • ProfitTarget – требуемая прибыль для закрытия позиции.
  • Order2OffsetOrder9Offset – расстояния для дополнительных лимитных ордеров.
  • CandleType – таймфрейм свечей, по умолчанию 4 часа.

Индикаторы

  • StochasticOscillator
  • BollingerBands
  • SMA (200 и 55)
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>
/// EMA crossover strategy inspired by Elliott wave concept.
/// </summary>
public class ElliottTraderStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public ElliottTraderStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		SubscribeCandles(CandleType)
			.Bind(fast, slow, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
		var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;

		if (crossUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}