Ver en GitHub

Simple FX Crossover Strategy

Summary

  • High-level port of the MetaTrader 4 expert advisor simplefx2.mq4 (Simple FX 2.0).
  • Trades crossovers between a fast and a slow simple moving average on finished candles.
  • Keeps only one position open and flips when the dominant trend reverses.

Trading Logic

  1. Build candles using the configurable timeframe parameter.
  2. Compute two simple moving averages (fast and slow) on candle close prices.
  3. Confirm a bullish trend when both the current and the previous candle show the fast MA above the slow MA. Confirm a bearish trend when both candles show the fast MA below the slow MA.
  4. When the confirmed trend differs from the stored trend state, close any opposite position and immediately open a market order in the new direction using the configured volume.
  5. Optional stop-loss and take-profit protections expressed in price steps can be enabled. They use StockSharp's built-in protection service to emulate the MT4 risk settings.

The strategy processes only finished candles, never intrabar ticks, to stay close to the original expert advisor behaviour. Logging is provided on each new entry so that every crossover decision can be audited.

Parameters

Name Description Default Optimization
ShortPeriod Length of the fast simple moving average. 50 10 → 150 step 5
LongPeriod Length of the slow simple moving average. 200 50 → 400 step 10
Volume Order volume submitted with each market trade. 0.1 0.1 → 2 step 0.1
StopLossPoints Protective stop distance in instrument price steps (0 disables). 0
TakeProfitPoints Profit target distance in instrument price steps (0 disables). 0
CandleType Candle timeframe used for analysis. 1 hour

Notes & Differences from MT4 Version

  • The MT4 persistence file (simplefx.dat) is not required; the last trend direction is tracked in memory by the strategy state.
  • Slippage, order comment, magic number, and arrow colour options from the original expert advisor are not exposed because StockSharp handles routing differently.
  • Stop-loss and take-profit distances are interpreted in price steps (instrument ticks). Adjust them to match your broker's pip definition.
  • Only one position can be open at any time; the strategy relies on ClosePosition() before switching direction, ensuring a clean flip between long and short trades.

Usage

  1. Attach the strategy to a security/instrument and set the desired candle timeframe.
  2. Configure moving average periods and risk parameters.
  3. Start the strategy; it will subscribe to candles, manage the trend state, and submit market orders when a crossover is confirmed on two consecutive candles.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simple FX crossover strategy.
/// Uses fast and slow SMA crossover for trend detection.
/// Buys on golden cross, sells on death cross.
/// </summary>
public class SimpleFxCrossoverStrategy : Strategy
{
	private readonly StrategyParam<int> _shortPeriod;
	private readonly StrategyParam<int> _longPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevShort;
	private decimal _prevLong;
	private bool _hasPrev;

	public int ShortPeriod { get => _shortPeriod.Value; set => _shortPeriod.Value = value; }
	public int LongPeriod { get => _longPeriod.Value; set => _longPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public SimpleFxCrossoverStrategy()
	{
		_shortPeriod = Param(nameof(ShortPeriod), 10)
			.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");

		_longPeriod = Param(nameof(LongPeriod), 30)
			.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevShort = 0m;
		_prevLong = 0m;
		_hasPrev = false;
	}

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

		_hasPrev = false;

		var fast = new SimpleMovingAverage { Length = ShortPeriod };
		var slow = new SimpleMovingAverage { Length = LongPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevShort = fast;
			_prevLong = slow;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevShort <= _prevLong && fast > slow;
		var crossDown = _prevShort >= _prevLong && fast < slow;

		if (crossUp && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevShort = fast;
		_prevLong = slow;
	}
}