在 GitHub 上查看

基础均线模板策略

基础均线模板策略 是仓库 MQL/27964 中 MetaTrader 4 EA 的 StockSharp 复刻版。原始机器人依赖较高周期的移动平均线,并在上一根蜡烛穿越均线时开仓。本移植版本保留了这种简洁的核心逻辑,同时把所有关键控制暴露为参数,方便在 StockSharp 平台上直接调节或优化。

策略仅在蜡烛收盘后运行。它会取得上一根蜡烛的开盘价与收盘价,与经过平移的移动平均值进行比较:

  • 如果上一根蜡烛开在均线上方并收在下方,在没有持仓时做空。
  • 如果上一根蜡烛开在均线下方并收在上方,在没有持仓时做多。

止盈与止损以点(pip)为单位输入。启动时,策略根据标的的最小报价步长与小数位数,将这些点差转换成绝对价格距离,复现了 MetaTrader 中依据报价位数调整 Pointpip 的处理方式。

交易逻辑

  • 数据源:由 CandleType 参数决定的单一蜡烛序列(默认 4 小时)。
  • 指标:可选 SMAEMASMMALWMAMovingAverageShift 参数与 MQL iMA 函数中的 shift 相同,用于前移均线数值。
  • 开仓条件
    • 多头:上一根蜡烛开在均线下方并收在上方,且当前无持仓。
    • 空头:上一根蜡烛开在均线上方并收在下方,且当前无持仓。
  • 离场:通过 StartProtection 自动附加的止盈/止损完成。当两个距离皆为 0 时仍会开启保护模块,以便后续接入移动止损或手动平仓。
  • 持仓过滤:只允许单一仓位,与原始 PosSelect() 函数的行为一致。

参数

参数 说明 默认值
CandleType 用于产生信号的蜡烛类型。 H4(4 小时)
MovingAveragePeriod 移动平均线周期长度。 49
MovingAverageShift 均线向前平移的柱数。 0
MovingAverageMethod 均线计算方式(SimpleExponentialSmoothedLinearWeighted)。 Simple
TakeProfitPips 以点为单位的止盈距离,运行时转换为绝对价格。 38.5
StopLossPips 以点为单位的止损距离,运行时转换为绝对价格。 48.5

风险控制

通过计算得到的绝对距离会附加到每一笔市价单。由于 pip 大小由价格步长和小数位确定(当报价为 5 位或 3 位小数时会乘以 10),因此止盈止损间距能够遵循原 EA 中的最小距离限制。

移植说明

  • 原始 EA 中的 ECN 双步骤下单被替换为 StockSharp 市价单与自动保护组合,后者会在成交后立即添加止盈止损。
  • CheckVolumeValueCheckMoneyForTrade 等资金检查函数被移除,仓位大小应通过 StockSharp 的风险模块设置。
  • 日志输出改为图表绘制,方便在策略图表中直观看到移动平均线与成交情况。

该移植保持了决策逻辑不变,并使用 SubscribeCandlesBindStartProtection 等高级 API,使其成为构建更复杂均线系统的轻量模板。

namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Basic MA Template strategy: trades when price crosses a moving average.
/// Opens long when previous candle crosses above MA, short when crosses below.
/// </summary>
public class BasicMaTemplateStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _maPeriod;

	private decimal? _prevOpen;
	private decimal? _prevClose;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }

	public BasicMaTemplateStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_maPeriod = Param(nameof(MaPeriod), 49)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Moving average period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevOpen = null;
		_prevClose = null;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevOpen = null;
		_prevClose = null;
		var sma = new SimpleMovingAverage { Length = MaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(sma, ProcessCandle).Start();
	}

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

		if (_prevOpen.HasValue && _prevClose.HasValue)
		{
			if (_prevOpen.Value > sma && _prevClose.Value < sma && Position >= 0)
				SellMarket();
			else if (_prevOpen.Value < sma && _prevClose.Value > sma && Position <= 0)
				BuyMarket();
		}

		_prevOpen = candle.OpenPrice;
		_prevClose = candle.ClosePrice;
	}
}