在 GitHub 上查看

PivotEMA3RLHv4 策略

概述

PivotEMA3RLHv4 是一套趋势策略,将日内枢轴价位与短周期动量过滤器结合使用。策略监控基于开盘价和收盘价的 3 周期指数移动平均线(EMA),并借助 Heiken Ashi 蜡烛确认方向,同时利用多组 ATR 指标判断波动率是否在放大。策略仅在所选周期的蜡烛收盘后做出交易决策。

交易逻辑

  1. 枢轴过滤:上一根 K 线的开盘价 EMA(3) 必须位于枢轴价位之下(做多)或之上(做空),当前 EMA(3) 需要越过枢轴并站在交易方向一侧。
  2. Heiken Ashi 确认:当前 Heiken Ashi 蜡烛需为阳线(做多)或阴线(做空)。
  3. 动量检查:基于收盘价的 EMA(3) 必须比开盘价 EMA 更强,方向与预期交易一致。
  4. 波动扩张:ATR(4)、ATR(8)、ATR(12)、ATR(24) 至少有一个数值高于上一根蜡烛,同时 ATR(1)(真实波幅)在本根或上一根蜡烛出现增加。
  5. 仓位管理:同一时间只允许一笔仓位。止损和止盈在策略内部计算,一旦价格触发即以市价单执行。

当出现反向条件时立即平仓;若止损、止盈或选定的追踪止损被触发,也会提前离场。

参数

参数 说明
CandleType 策略使用的工作周期。
StopLossPips 初始止损距离(点)。0 表示关闭。
TakeProfitPips 止盈距离(点)。0 表示关闭。
UseTrailingStop 是否启用追踪止损。
TrailingStopType 追踪模式:1 表示固定距离,2 表示价格先移动 TrailingStopPips 后再锁定利润,3 表示三段式管理。
TrailingStopPips 模式 2 使用的追踪距离。
FirstMovePips / FirstStopLossPips 模式 3 第一阶段的触发距离与新止损位置。
SecondMovePips / SecondStopLossPips 模式 3 第二阶段的触发距离与新止损位置。
ThirdMovePips / TrailingStop3Pips 模式 3 第三阶段的触发距离与随后使用的追踪距离。

追踪止损模式

  • 模式 1:保持止损与当前价格之间的距离不大于初始风险。
  • 模式 2:当盈利达到 TrailingStopPips 时,将止损移动到固定距离,并持续跟随。
  • 模式 3:最多三个阶段——前两段锁定固定利润,第三段转化为常规追踪止损。

备注

  • 策略会订阅日线数据,根据上一交易日的最高价、最低价和收盘价计算当日枢轴。
  • 所有指标都在蜡烛收盘后更新,确保在实时交易和回测环境中表现一致。
  • 原始的 MetaTrader EA 使用服务器端止损,本移植版本通过程序模拟,并在条件满足时发送市价单平仓。
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>
/// Pivot EMA strategy using fast and slow EMA crossover.
/// Buy when fast EMA crosses above slow EMA.
/// Sell when fast EMA crosses below slow EMA.
/// </summary>
public class PivotEma3RlhV4Strategy : 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 PivotEma3RlhV4Strategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 3)
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 21)
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).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();

		_prevFast = 0m;
		_prevSlow = 0m;
		_hasPrev = false;
	}

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

		_hasPrev = false;

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

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

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

		if (!_hasPrev)
		{
			_prevFast = fast;
			_prevSlow = slow;
			_hasPrev = true;
			return;
		}

		var bullCross = _prevFast <= _prevSlow && fast > slow;
		var bearCross = _prevFast >= _prevSlow && fast < slow;

		if (Position <= 0 && bullCross)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (Position >= 0 && bearCross)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevFast = fast;
		_prevSlow = slow;
	}
}