在 GitHub 上查看

Multi Strategy Combo 策略

概述

Multi Strategy Combo Strategy 是 MetaTrader 4「Multi-Strategy iFSF」EA 的 C# 版本。该策略将 MA、RSI、MACD、Stochastic、Parabolic SAR 等指标的信号进行合成,并辅以 ADX 趋势过滤、布林带区间过滤以及噪音过滤器。所有逻辑均使用 StockSharp 的高阶 SubscribeCandles().Bind(...) API 完成,不再需要手动维护指标缓冲区。只有当所有启用的指标同时给出 BUY/SELL 信号时才会触发下单,随后再通过组合过滤器确认。

核心逻辑

  • 信号合成 — 启用的 MA、RSI、MACD、Stochastic、SAR 分别给出离散多/空投票。所有投票一致时才判定为看多或看空。
  • 组合因子(1–3) — 对应原始 EA 的 Combo_Trader_Factor。不同因子决定共识信号与 ADX 趋势、布林带过滤器之间的组合方式:
    • 因子 1 偏向趋势行情;在区间阶段(且启用布林带过滤器)时使用布林带反弹信号。
    • 因子 2 要求更严格,趋势过滤与布林带过滤都必须支持当前共识。
    • 因子 3 最严格,只有在全部模块方向一致时才允许交易。
  • 趋势检测 — 在可配置的时间框架上计算 ADX,将市场划分为趋势上涨/趋势下跌/区间看涨/区间看跌。
  • 布林带过滤 — 使用 2σ 与 3σ 两组带宽。做多必须出现下轨反弹且近期 RSI 进入超卖区域;做空则相反。
  • 噪音过滤 — 以 ATR 模拟 Damiani Volatmeter,当波动率低于阈值时禁止新交易。
  • 自动平仓 — 若启用,在共识出现反向信号时立即平掉当前仓位。

指标与信号

  • 移动平均线 — 三条可配置均线(周期与算法)。模式 1–5 对应原策略的不同交叉组合。
  • RSI — 四种模式:超买/超卖、趋势、组合以及区间模式,相关阈值均可配置。
  • MACD — 四种模式:主线/信号线斜率、零轴附近交叉、组合确认以及信号线穿越零轴。
  • 随机指标 — 可选择简单的 %K/%D 交叉或带上限/下限的交叉。
  • Parabolic SAR — 可选的方向投票,可保持最后一次方向以避免同一趋势内重复触发。

风险管理

  • StopLossOffsetTakeProfitOffset 以绝对价差指定止损止盈距离。
  • 通过 StartProtection 支持追踪止损 (UseTrailingStop)。
  • 下单与持仓保护完全由 StockSharp 框架处理,无需手动 OrderSend

关键参数

  • 通用ComboFactor, CandleType
  • MAUseMa, MaMode, 三条均线的周期与算法、时间框架以及“记住上一信号”选项。
  • RSIUseRsi, RsiMode, RsiPeriod, 超买/超卖阈值、区间阈值以及记忆开关。
  • MACDUseMacd, MacdMode, 快/慢/信号 EMA 周期、时间框架以及记忆开关。
  • 随机指标UseStochastic, 平滑参数、阈值与时间框架。
  • Parabolic SARUseSar, SarStep, SarMax, 时间框架。
  • 趋势过滤UseTrendDetection, AdxPeriod, AdxLevel, 时间框架。
  • 布林带过滤UseBollingerFilter, BollingerPeriod, 中/宽带偏差、RSI 历史长度。
  • 噪音过滤UseNoiseFilter, NoiseAtrLength, NoiseThreshold, 时间框架。
  • 自动平仓与风险UseAutoClose, AllowOppositeAfterClose, StopLossOffset, TakeProfitOffset, UseTrailingStop

所有参数均通过 StrategyParam<T> 暴露,方便优化与 UI 显示。

与 MT4 EA 的差异

  • 仅使用 StockSharp 内置指标。原策略中 ZeroLag MACD 的选项被统一成内置 MACD。
  • 所有均线和振荡指标均基于 K 线收盘价,MT4 中的价格源与 Shift 参数(如 FastMa_Price, FastMa_Shift)未实现。
  • Damiani 噪音过滤器改为 ATR 判定,可通过 NoiseThreshold 调整灵敏度。
  • 不再手动管理订单,直接调用 BuyMarket/SellMarket,仓位保护由 StartProtection 完成。
  • 不包含 MT4 的图形界面与文字注释,调试信息可使用 LogInfo 查看。

使用步骤

  1. MultiStrategyComboStrategy 类添加到 StockSharp 解决方案并编译。
  2. 设置 SecurityPortfolioVolume,必要时为各指标选择不同时间框架。
  3. 根据需求调整止损/止盈距离、追踪止损及过滤阈值。
  4. 启动策略。只要所有启用模块依据所选组合因子达成一致,策略便会在 K 线收盘后下单。

转换说明

  • 全部逻辑基于高阶订阅接口实现,无手工 GetValue() 调用。
  • 源码缩进按照仓库要求使用制表符。
  • 代码中的英文注释说明了 MT4 与 StockSharp 之间的映射关系。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Multi Combo: Dual EMA crossover with RSI filter and ATR stops.
/// </summary>
public class MultiComboStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastEmaLength;
	private readonly StrategyParam<int> _slowEmaLength;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;

	public MultiComboStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_fastEmaLength = Param(nameof(FastEmaLength), 9)
			.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");

		_slowEmaLength = Param(nameof(SlowEmaLength), 21)
			.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");

		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

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

	public int FastEmaLength
	{
		get => _fastEmaLength.Value;
		set => _fastEmaLength.Value = value;
	}

	public int SlowEmaLength
	{
		get => _slowEmaLength.Value;
		set => _slowEmaLength.Value = value;
	}

	public int RsiLength
	{
		get => _rsiLength.Value;
		set => _rsiLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;

		var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
		var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastEma, slowEma, rsi, atr, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal rsiVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if (fastVal < slowVal && _prevFast >= _prevSlow)
			{
				SellMarket();
				_entryPrice = 0;
			}
			else if (close <= _entryPrice - atrVal * 2m)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (fastVal > slowVal && _prevFast <= _prevSlow)
			{
				BuyMarket();
				_entryPrice = 0;
			}
			else if (close >= _entryPrice + atrVal * 2m)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		if (Position == 0)
		{
			if (fastVal > slowVal && _prevFast <= _prevSlow && rsiVal > 45)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (fastVal < slowVal && _prevFast >= _prevSlow && rsiVal < 55)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}