在 GitHub 上查看

Expert MACD EURUSD 1 Hour 策略

概述

该策略是 MetaTrader 5 指标顾问 Expert MACD EURUSD 1 Hour 的 C# 翻译版本。策略在一小时K线图上运行,使用 MACD 指标(快速、慢速和信号周期分别为 5 / 15 / 3)。当 MACD 主线越过零轴并且信号线同步确认时,策略认为出现强劲动量并开仓。策略使用追踪止损保护持仓,当 MACD 斜率反转时平仓。

参数

  • FastLength – MACD 快速 EMA 周期(默认 5)。
  • SlowLength – MACD 慢速 EMA 周期(默认 15)。
  • SignalLength – MACD 信号线周期(默认 3)。
  • TrailingPoints – 追踪止损距离(默认 25 点)。
  • CandleType – 使用的K线类型与时间框架(默认 1 小时)。
  • 订单数量由策略的 Volume 属性控制。

交易逻辑

做多条件

  1. 信号线:mac8 > mac7 > mac6mac6 < mac5(信号线上升)。
  2. 主线:mac4 > mac3 < mac2 < mac1(主线下跌后反弹)。
  3. mac2 < -0.00020mac4 < 0mac1 > 0.00020 —— 主线向上穿越零轴。
  4. 若满足上述条件且没有多头持仓,则市价买入。

做空条件

  1. 信号线:mac8 < mac7 < mac6mac6 > mac5(信号线下降)。
  2. 主线:mac4 < mac3 > mac2 > mac1(主线上涨后回落)。
  3. mac2 > 0.00020mac4 > 0mac1 < -0.00035 —— 主线向下穿越零轴。
  4. 若满足上述条件且没有空头持仓,则市价卖出。

退出规则

  • 当当前主线值低于前一个值时,平掉多头。
  • 当当前主线值高于前一个值时,平掉空头。
  • 追踪止损在每根K线更新,价格触及止损线时平仓。

备注

该示例展示了如何使用 StockSharp 高级 API、指标绑定以及手动管理追踪止损。策略仅用于学习目的,仅包含固定 Volume 参数的简单仓位管理。

using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// MACD based strategy converted from MetaTrader 5 Expert Advisor.
/// Uses MACD indicator with custom pattern checks on recent values and optional trailing stop.
/// </summary>
public class ExpertMacdEurusd1HourStrategy : Strategy
{
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<int> _signalLength;
	private readonly StrategyParam<decimal> _trailingPoints;
	private readonly StrategyParam<DataType> _candleType;
	private ExponentialMovingAverage _fastEma;
	private ExponentialMovingAverage _slowEma;
	private ExponentialMovingAverage _signalEma;

	private decimal _main0, _main1;
	private decimal _signal0, _signal1;
	private int _counter;

	/// <summary>
	/// Fast EMA length for MACD.
	/// </summary>
	public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }

	/// <summary>
	/// Slow EMA length for MACD.
	/// </summary>
	public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }

	/// <summary>
	/// Signal line length for MACD.
	/// </summary>
	public int SignalLength { get => _signalLength.Value; set => _signalLength.Value = value; }

	/// <summary>
	/// Trailing stop distance in price points.
	/// </summary>
	public decimal TrailingPoints { get => _trailingPoints.Value; set => _trailingPoints.Value = value; }

	/// <summary>
	/// Candle type for analysis.
	/// </summary>
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	/// <summary>
	/// Initialize strategy with default parameters.
	/// </summary>
	public ExpertMacdEurusd1HourStrategy()
	{
		_fastLength = Param(nameof(FastLength), 12)
			.SetDisplay("Fast Length", "Fast EMA length for MACD", "Parameters")
			;

		_slowLength = Param(nameof(SlowLength), 26)
			.SetDisplay("Slow Length", "Slow EMA length for MACD", "Parameters")
			;

		_signalLength = Param(nameof(SignalLength), 9)
			.SetDisplay("Signal Length", "Signal length for MACD", "Parameters")
			;

		_trailingPoints = Param(nameof(TrailingPoints), 25m)
			.SetDisplay("Trailing Points", "Trailing stop distance in points", "Risk");

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

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_main0 = _main1 = 0m;
		_signal0 = _signal1 = 0m;
		_counter = 0;
		_fastEma = null;
		_slowEma = null;
		_signalEma = null;
	}

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

		_fastEma = new ExponentialMovingAverage { Length = FastLength };
		_slowEma = new ExponentialMovingAverage { Length = SlowLength };
		_signalEma = new ExponentialMovingAverage { Length = SignalLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ProcessCandle)
			.Start();

		StartProtection(
			new Unit(2000m, UnitTypes.Absolute),
			new Unit(1000m, UnitTypes.Absolute));

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

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

		var fast = _fastEma.Process(candle.ClosePrice, candle.CloseTime, true).ToDecimal();
		var slow = _slowEma.Process(candle.ClosePrice, candle.CloseTime, true).ToDecimal();
		if (!_fastEma.IsFormed || !_slowEma.IsFormed)
			return;

		var main = fast - slow;
		var signal = _signalEma.Process(main, candle.CloseTime, true).ToDecimal();
		if (!_signalEma.IsFormed)
			return;

		// shift stored values
		_main1 = _main0;
		_main0 = main;

		_signal1 = _signal0;
		_signal0 = signal;

		if (_counter < 3)
		{
			_counter++;
			return;
		}

		var buySignal = _main1 <= _signal1 && _main0 > _signal0 && _main0 < 0m;
		var sellSignal = _main1 >= _signal1 && _main0 < _signal0 && _main0 > 0m;

		if (buySignal && Position <= 0)
			BuyMarket();
		else if (sellSignal && Position >= 0)
			SellMarket();
	}
}