GitHub で見る

Two MA One RSI Strategy

This strategy ports the MetaTrader 5 expert "Two MA one RSI" into StockSharp. It combines a fast and slow moving average crossover with an RSI confirmation that is evaluated on the previous closed candle. Flexible switches allow turning each comparison into either a "greater than" or "less than" rule so the setup can be inverted without touching the code.

Details

  • Entry Criteria:
    • Long signals require the fast MA to be below the slow MA two bars ago, the fast MA to be above the slow MA on the most recent closed bar, and the RSI from the previous bar to be above the upper threshold. Each comparison can be flipped through boolean parameters.
    • Short signals mirror the logic and check for the opposite MA relationships together with the RSI falling below the lower threshold.
    • Both MAs use the same averaging type; the slow period is always FastMaPeriod * SlowPeriodMultiplier. Optional horizontal shifts reproduce the MT5 behaviour where indicator values are read several candles back.
  • Long/Short: The strategy can open positions in both directions. CloseOppositePositions controls whether a new signal forces the opposite side to close before entering.
  • Exit Criteria:
    • Configurable stop-loss and take-profit in pips.
    • Optional trailing stop that only moves after price advances by at least TrailingStopPips + TrailingStepPips beyond the entry.
    • ProfitClose monitors floating P&L (using the instrument step price) and closes all positions once the target currency amount is reached.
  • Stops: When StopLossPips is zero the strategy relies purely on the trailing-stop module (if enabled). TrailingStopPips requires a positive TrailingStepPips, matching the original expert's validation.
  • Default Values:
    • FastMaPeriod = 10, SlowPeriodMultiplier = 2.
    • FastMaShift = 3, SlowMaShift = 0.
    • RsiPeriod = 10, RsiUpperLevel = 70, RsiLowerLevel = 30.
    • StopLossPips = 50, TakeProfitPips = 150, TrailingStopPips = 15, TrailingStepPips = 5.
    • MaxPositions = 10, ProfitClose = 100, TradeVolume = 1.
  • Filters: Six boolean switches (BuyPreviousFastBelowSlow, BuyCurrentFastAboveSlow, BuyRequiresRsiAboveUpper, SellPreviousFastAboveSlow, SellCurrentFastBelowSlow, SellRequiresRsiBelowLower) let the user instantly change the sense of each comparison.

Parameters

Name Description
CandleType Time-frame (or any other candle type) used for analysis.
MaType Moving-average family (simple, exponential, smoothed, weighted, volume-weighted).
FastMaPeriod Period of the fast MA.
SlowPeriodMultiplier Slow MA period multiplier (slow = fast * multiplier).
FastMaShift, SlowMaShift Horizontal shifts in candles applied when evaluating MA values.
RsiPeriod RSI length (uses the previous finished candle).
RsiUpperLevel, RsiLowerLevel RSI thresholds for long and short confirmations.
BuyPreviousFastBelowSlow, BuyCurrentFastAboveSlow, BuyRequiresRsiAboveUpper Toggle comparisons for long signals.
SellPreviousFastAboveSlow, SellCurrentFastBelowSlow, SellRequiresRsiBelowLower Toggle comparisons for short signals.
StopLossPips, TakeProfitPips Protective stop and target measured in pips (pip size derived from the security's price step).
TrailingStopPips, TrailingStepPips Trailing-stop distance and minimal improvement.
MaxPositions Maximum number of simultaneous entries per direction (0 = unlimited).
ProfitClose Currency profit target that closes all positions when reached.
CloseOppositePositions Whether to flatten the opposite side before opening a new trade.
TradeVolume Base order size; also synchronises with the strategy Volume property.

Implementation Notes

  • All decisions use finished candles only, matching the MT5 expert's "new bar" logic.
  • The pip size equals the instrument price step. If your market uses fractional pip pricing, adjust the security settings accordingly so the pip translation matches the original expert's digits_adjust logic.
  • Trailing stops only start after the price has advanced by TrailingStopPips + TrailingStepPips; the stop is then anchored TrailingStopPips away from the close and only moves when it improves by at least TrailingStepPips.
  • ProfitClose calculates floating profit using the security's PriceStep and StepPrice. Ensure those fields are configured for correct currency results.
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);
		}
	}
}