在 GitHub 上查看

Two MA One RSI 策略

该策略将 MetaTrader 5 专家顾问 “Two MA one RSI” 移植到 StockSharp。它通过快慢两条均线的交叉配合前一根 K 线的 RSI 信号生成交易,并提供多个布尔开关来快速反转比较条件。

细节

  • 入场条件
    • 多头:两根之前快线低于慢线,上一根快线高于慢线,同时前一根 RSI 高于上轨。三个条件均可通过布尔参数调整方向。
    • 空头:逻辑完全相反,检查快慢均线位置与 RSI 是否跌破下轨。
    • 两条均线共享同一种类型,慢线周期恒等于 FastMaPeriod * SlowPeriodMultiplierFastMaShift/SlowMaShift 参数重现 MT5 中的水平偏移效果。
  • 方向:可做多也可做空。CloseOppositePositions 控制在出现反向信号时是否先平掉对冲仓位。
  • 出场条件
    • 固定止损/止盈(以点数计)。
    • 可选的跟踪止损,只有当价格至少前进 TrailingStopPips + TrailingStepPips 点后才会移动,并始终保持与收盘价的距离为 TrailingStopPips
    • ProfitClose 监控浮动盈亏(使用合约的价格步长与步值)并在达到目标货币金额后平掉所有仓位。
  • 止损管理StopLossPips = 0 时仅依赖跟踪止损。启用跟踪功能必须保证 TrailingStepPips > 0,与原版规则一致。
  • 默认值FastMaPeriod = 10SlowPeriodMultiplier = 2FastMaShift = 3SlowMaShift = 0RsiPeriod = 10RsiUpperLevel = 70RsiLowerLevel = 30StopLossPips = 50TakeProfitPips = 150TrailingStopPips = 15TrailingStepPips = 5MaxPositions = 10ProfitClose = 100TradeVolume = 1
  • 过滤器:六个布尔开关(BuyPreviousFastBelowSlowBuyCurrentFastAboveSlowBuyRequiresRsiAboveUpperSellPreviousFastAboveSlowSellCurrentFastBelowSlowSellRequiresRsiBelowLower)可即时改变各项比较关系。

参数

名称 说明
CandleType 使用的 K 线类型或时间框架。
MaType 均线类型(SMA、EMA、Smoothed、WMA、VWMA)。
FastMaPeriod 快线周期。
SlowPeriodMultiplier 慢线周期倍率(慢线周期 = 快线周期 × 倍率)。
FastMaShift, SlowMaShift 水平偏移量(以 K 线数计算)。
RsiPeriod RSI 计算周期(读取上一根完成的 K 线)。
RsiUpperLevel, RsiLowerLevel RSI 上/下阈值。
BuyPreviousFastBelowSlow, BuyCurrentFastAboveSlow, BuyRequiresRsiAboveUpper 多头信号开关。
SellPreviousFastAboveSlow, SellCurrentFastBelowSlow, SellRequiresRsiBelowLower 空头信号开关。
StopLossPips, TakeProfitPips 止损与止盈点数(基于合约价格步长估算)。
TrailingStopPips, TrailingStepPips 跟踪止损距离与最小推进。
MaxPositions 每个方向最多允许的持仓数(0 表示无限制)。
ProfitClose 浮动收益达到该货币金额时强制平仓。
CloseOppositePositions 是否在开新仓前先平掉反向仓位。
TradeVolume 基础下单手数,同时写入策略的 Volume 属性。

实现说明

  • 所有判断都基于已完成的 K 线,完全贴合 MT5 版本只在新柱开启时触发的逻辑。
  • 点值直接使用证券的价格步长。如交易品种采用 1/10 点报价,请在证券设置中调整步长以模拟原策略的 digits_adjust 处理。
  • 跟踪止损只在价格推进 TrailingStopPips + TrailingStepPips 后才生效,并且只有当新的止损价优于旧值至少 TrailingStepPips 才会更新。
  • ProfitClose 通过 PriceStepStepPrice 计算盈亏,务必确认这些字段配置正确。
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Two MA one RSI strategy (simplified).
/// EMA crossover filtered by RSI levels.
/// </summary>
public class TwoMaOneRsiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _rsiPeriod;

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public TwoMaOneRsiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candles", "General");

		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI length", "Indicators");
	}

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

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

		decimal prevFast = 0, prevSlow = 0;
		bool hasPrev = false;

		var subscription = SubscribeCandles(CandleType);
		// Use Bind with fast, slow - RSI computed separately via cross-feed
		subscription
			.Bind(fast, slow, (ICandleMessage candle, decimal fastValue, decimal slowValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!hasPrev)
				{
					prevFast = fastValue;
					prevSlow = slowValue;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevFast = fastValue;
					prevSlow = slowValue;
					return;
				}

				// Golden cross + RSI not overbought
				if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
				{
					BuyMarket();
				}
				// Death cross + RSI not oversold
				else if (prevFast >= prevSlow && fastValue < slowValue && Position >= 0)
				{
					SellMarket();
				}

				prevFast = fastValue;
				prevSlow = slowValue;
			})
			.Start();

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