在 GitHub 上查看

Elliott Trader 策略

当四小时周期的随机指标达到极值时,该策略会开启分层仓位。它先执行市价单,然后在配置好的点差上方或下方挂出一系列限价单。当达到盈利目标并且趋势由移动平均线和布林带确认后,策略将平仓。

入场规则

  • 使用随机指标(%K 长度 21,平滑 3)在 H4 K 线。
  • 当 %K ≥ Overbought
    • 市价卖出。
    • 在当前价上方按设置的点差挂出最多八个 SellLimit 订单。
  • 当 %K ≤ Oversold
    • 市价买入。
    • 在当前价下方按设置的点差挂出最多八个 BuyLimit 订单。

出场规则

  • 已实现利润达到 ProfitTarget 且价格满足趋势条件时:
    • 多单在价格高于布林带下轨且 200 周期 SMA 高于 55 周期 SMA 时平仓。
    • 空单在价格低于布林带上轨且 200 周期 SMA 低于 55 周期 SMA 时平仓。
  • 当 %K ≥ 90 且 200 周期 SMA ≤ 55 周期 SMA 时,取消所有挂出的买入限价单。
  • 当 %K ≤ 10 且 200 周期 SMA ≥ 55 周期 SMA 时,取消所有挂出的卖出限价单。

参数

  • 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;
	}
}