在 GitHub 上查看

5/8 EMA 交叉策略

概述

5/8 EMA 交叉策略 复刻了 MetaTrader 智能交易系统 5_8macrossv2.mq4,通过比较同一标的上的两条可配置均线生成交易信号。快速均线向上穿越慢速均线时开多单,向下穿越时开空单。本移植版本遵循 StockSharp 的高级 API,并提供可选的止盈、止损和移动止损管理。

交易逻辑

  • 在指定的蜡烛订阅上计算两条均线。默认使用 5 周期指数均线(收盘价)与 8 周期指数均线(开盘价)。
  • 当最新完成的蜡烛上,快速均线从下向上穿越慢速均线时,策略会开多仓或从空仓反手做多。若存在空仓,市价买单会自动加上空头持仓量以完成反向操作。
  • 当快速均线从上向下穿越慢速均线时,策略会开空仓或从多仓反手做空。
  • 均线的“Shift”参数模拟原脚本的水平位移。正值会将信号延后若干根已完成蜡烛;负值在本移植中被视为 0,因为实时数据无法获取未来值。

风险管理

  • 止盈止损 以点值(价格步长)表示。开仓后立即根据入场价计算目标价位,空头逻辑与多头镜像对称。
  • 移动止损 也使用点值定义,价格朝有利方向运行时不断收紧:多头只上调,空头只下调。
  • 如果在完成的蜡烛上触发任一保护条件(最高价触及止盈、最低价触及止损或移动止损),策略会通过市价单平仓并重置内部状态。

参数

名称 类型 默认值 说明
TradeVolume decimal 0.1 新开仓的下单量。若需要反手,会额外加上当前持仓量。
TakeProfitPips decimal 40 距离入场价的止盈距离(点)。设为 0 则禁用。
StopLossPips decimal 0 距离入场价的止损距离(点)。设为 0 则禁用。
TrailingStopPips decimal 0 移动止损的距离(点)。设为 0 则禁用。
FastPeriod int 5 快速均线周期。
FastShift int -1 快速均线水平位移。负值在本实现中被处理为 0。
FastMethod MovingAverageMethod Exponential 快速均线的平滑算法:Simple、Exponential、Smoothed、LinearWeighted。
FastPrice AppliedPrice Close 快速均线使用的蜡烛价格。
SlowPeriod int 8 慢速均线周期。
SlowShift int 0 慢速均线水平位移。
SlowMethod MovingAverageMethod Exponential 慢速均线的平滑算法。
SlowPrice AppliedPrice Open 慢速均线使用的蜡烛价格。
CandleType DataType TimeSpan.FromMinutes(30).TimeFrame() 用于计算的蜡烛类型。

备注

  • 策略仅在蜡烛收盘后评估信号,以避免未完成数据导致的假突破。
  • 止盈、止损与移动止损都依赖 Security.PriceStep。若标的未设置价格步长,则这些保护机制保持未激活状态。
  • 根据任务要求,此仓库未包含 Python 版本。
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>
/// 5/8 MA Cross Protect strategy - EMA(5) and EMA(8) crossover.
/// Buys when EMA(5) crosses above EMA(8).
/// Sells when EMA(5) crosses below EMA(8).
/// </summary>
public class FiveEightMaCrossProtectStrategy : 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 FiveEightMaCrossProtectStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 5)
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

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

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevFast = 0m; _prevSlow = 0m; _hasPrev = false; }

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

		if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevFast = fast;
		_prevSlow = slow;
	}
}