GitHub で見る

This strategy ports the 1 MINUTE SCALPER MetaTrader 4 expert advisor into the StockSharp high-level API. It keeps the multi-layer trend confirmation, multi-timeframe momentum, and long-term MACD filter of the original robot while adapting risk controls to StockSharp's position-centric model.

Core Logic

  1. Trend Stack – thirteen linear weighted moving averages (LWMA 3/5/8/10/12/15/30/35/40/45/50/55/200) must align in strict order. Long trades require each shorter average to print above the next, while shorts invert the condition.
  2. Primary Trend Gate – an additional fast LWMA (default 6) must stay above the slow LWMA (default 85) for longs and below for shorts, mirroring the EA's fast-vs-slow check.
  3. Candle Structure – entries only trigger when the overlap patterns from the script are present: for longs the low two bars ago must be below the previous high, for shorts the previous low must dip under the high two bars back.
  4. Momentum Filter – a 14-period momentum indicator calculated on a higher timeframe (default 15-minute candles) must deviate from 100 by at least the configured thresholds on any of the last three values. This reproduces the MomLevelB/MomLevelS comparisons.
  5. Monthly MACD Bias – a MACD built on the selected MACD timeframe (defaults to 30-day candles as a proxy for monthly data) must show the main line above the signal line for longs or below for shorts.

Trade Management

  • Initial Protection – stop-loss and take-profit distances are expressed in instrument steps (points). When a position opens, the strategy converts these step counts to absolute prices using Security.PriceStep.
  • Break-Even Move – after price moves by BreakEvenTriggerSteps in favor, the stop is moved to the entry plus BreakEvenOffsetSteps (for shorts the mirrored logic applies). The flag is triggered once per position.
  • Step Trailing – when TrailingStopSteps is positive the stop follows the highest (or lowest) price since entry by the specified number of steps.
  • Money Trailing – once floating profit exceeds MoneyTrailTarget (currency), the strategy tracks the peak floating PnL and closes the position if the pullback equals MoneyTrailStop.
  • Money/Percent Targets – optional absolute or percentage take profits close all exposure when the floating PnL crosses the configured thresholds. The percentage target uses the initial portfolio value captured when the strategy starts.
  • Equity Stop – the strategy monitors the maximum equity (portfolio value plus open PnL). If the drawdown from that peak exceeds EquityRiskPercent, all positions are flattened, replicating the EA's AccountEquityHigh() safeguard.

Parameters

Parameter Description
Volume Order volume for new entries. Added to the absolute current position so reversals flip exposure immediately.
FastMaPeriod / SlowMaPeriod LWMA lengths for the primary trend filter.
MomentumPeriod Length of the higher timeframe momentum indicator.
MomentumBuyThreshold / MomentumSellThreshold Minimum absolute deviation from 100 required for long/short momentum confirmation.
MacdFastLength / MacdSlowLength / MacdSignalLength MACD configuration applied to MacdCandleType.
StopLossSteps / TakeProfitSteps Protective stop and target distances measured in price steps. Set to zero to disable.
TrailingStopSteps Step-based trailing stop distance (0 disables).
BreakEvenTriggerSteps / BreakEvenOffsetSteps Distance to trigger the break-even move and the offset applied when moving the stop.
UseMoneyTakeProfit, MoneyTakeProfit Enable and size the currency-based floating profit target.
UsePercentTakeProfit, PercentTakeProfit Enable and size the floating profit target as a percentage of initial equity.
EnableMoneyTrailing, MoneyTrailTarget, MoneyTrailStop Configure the floating profit trailing logic.
UseEquityStop, EquityRiskPercent Enable the drawdown stop and define the maximum drawdown percentage.
CandleType Primary working candles (defaults to 1 minute).
MomentumCandleType Higher timeframe candles for the momentum indicator (defaults to 15 minutes).
MacdCandleType Candles used for the MACD trend filter (defaults to 30 days ≈ monthly).

Differences vs. the MT4 Expert

  • StockSharp uses net positions, so the strategy always maintains a single aggregated position instead of multiple tickets up to Max_Trades. Reversals close the existing exposure before opening in the opposite direction.
  • PercentTakeProfit references the portfolio value captured at start instead of the constantly changing AccountBalance() used by MetaTrader, which avoids noisy targets when external trades modify the balance.
  • Money-based exit logic (Take_Profit_In_Money and TRAIL_PROFIT_IN_MONEY2) operates on the live floating PnL calculated from the strategy's average entry price. This matches the EA's behaviour but inside StockSharp's protection framework.
  • The platform must supply candle feeds for the selected timeframes (CandleType, MomentumCandleType, MacdCandleType). Ensure the adapters you use support the requested resolutions.

Tune the thresholds to fit your instrument and session. Narrow spreads or highly volatile pairs may require wider step distances or larger momentum thresholds to reduce noise.

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>
/// One-minute scalper strategy using fast/slow WMA crossover.
/// Buys on bullish crossover, sells on bearish crossover.
/// </summary>
public class OneMinuteScalperStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private WeightedMovingAverage _fast;
	private WeightedMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	/// <summary>
	/// Fast WMA period.
	/// </summary>
	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	/// <summary>
	/// Slow WMA period.
	/// </summary>
	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	/// <summary>
	/// Stop-loss distance in price steps.
	/// </summary>
	public int StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Take-profit distance in price steps.
	/// </summary>
	public int TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="OneMinuteScalperStrategy"/> class.
	/// </summary>
	public OneMinuteScalperStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast WMA period", "Indicator");

		_slowPeriod = Param(nameof(SlowPeriod), 85)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow WMA period", "Indicator");

		_stopLossPoints = Param(nameof(StopLossPoints), 200)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 500)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

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

		_fast = null;
		_slow = null;
		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
		_cooldown = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_fast = new WeightedMovingAverage { Length = FastPeriod };
		_slow = new WeightedMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

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

		if (!_fast.IsFormed || !_slow.IsFormed)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		if (_cooldown > 0)
		{
			_cooldown--;
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		// Check SL/TP
		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 60;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}

			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 60;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 60;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}

			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 60;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}
		}

		// WMA crossover
		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();

			BuyMarket();
			_entryPrice = close;
			_cooldown = 60;
		}
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{
			if (Position > 0)
				SellMarket();

			SellMarket();
			_entryPrice = close;
			_cooldown = 60;
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
	}
}