Ver no GitHub

Crypto Analysis Strategy

Overview

This strategy is a StockSharp port of the MetaTrader 4 expert advisor "Crypto Analysis". It hunts for breakouts that occur after price tags the outer Bollinger Band on the main trading timeframe while the market structure remains bearish (fast LWMA below the slow LWMA). The system only allows trades when a higher timeframe momentum burst and a monthly MACD filter both agree with the desired direction. Once in the market, the position is managed by a layered protection block that mirrors the original EA: pip-based stops, money-based trailing, break-even relocation, and portfolio drawdown controls.

Trading logic

  • Signal timeframe: configurable (default M15). All entry/exit rules are evaluated on these candles.
  • Volatility trigger: previous candle low must touch or pierce the lower Bollinger Band (20, 2) to prepare a long setup, while a touch of the upper band prepares a short setup.
  • Trend filter: both scenarios require the fast linear weighted moving average (LWMA, default 6) to stay below the slow LWMA (default 85), replicating the bearish bias check in the EA.
  • RSI confirmation: RSI(14) has to be above 50 for longs and below 50 for shorts.
  • Momentum burst: the maximum absolute deviation of the last three higher-timeframe Momentum(14) values from the 100 baseline must exceed the buy/sell thresholds. This captures the momentum spikes used by the MQL code.
  • Monthly MACD filter: a separate monthly (default 30-day candles) MACD (12, 26, 9) confirms direction; longs require MACD main above signal, shorts demand the opposite.
  • Entry execution: once all filters align, the strategy opens a market order. Opposite positions are flattened before reversing to keep a single net position, which mirrors the EA’s behaviour of closing opposing trades.

Position management

  • Initial stop and target: configurable distances in pips are converted from the instrument tick size using the same 5-digit/3-digit handling as the EA (0.00001 and 0.001 steps are multiplied by 10).
  • Trailing stop: after a new high (long) or low (short) forms, the stop is pulled behind price by TrailingStopPips, always respecting the best level achieved.
  • Break-even: when profit reaches BreakEvenTriggerPips, the stop is moved to the entry price plus BreakEvenOffsetPips (long) or minus the offset (short).
  • Money targets: optional absolute or percentage-based profit caps close the position as soon as the floating PnL hits the requested level.
  • Money trailing: once unrealized profit exceeds MoneyTrailTarget, the strategy tracks the peak and closes the position if the giveback equals or exceeds MoneyTrailStop.
  • Equity stop: the floating equity (current portfolio value plus unrealized PnL) is monitored; if the drawdown from the peak surpasses EquityRiskPercent, the position is flattened.

Multi-timeframe data

Three subscriptions are registered automatically:

  1. Primary candle series for the Bollinger/LWMA/RSI rules.
  2. Higher timeframe candles for the momentum filter (default H1).
  3. Monthly candles for the MACD confirmation (default 30-day bars).

Parameters

Parameter Description
OrderVolume Base order size. Opposite positions are closed before opening a new one.
UseMoneyTakeProfit Enable the absolute monetary take-profit target.
MoneyTakeProfit Profit in portfolio currency that triggers an exit when UseMoneyTakeProfit is true.
UsePercentTakeProfit Enable the percent-based take-profit target calculated from the initial equity.
PercentTakeProfit Profit percentage required to close the position when the percent target is active.
EnableMoneyTrailing Activates the money-based trailing block.
MoneyTrailTarget Profit level that starts the money trail.
MoneyTrailStop Maximum allowed profit giveback after MoneyTrailTarget has been reached.
StopLossPips Initial stop-loss distance in pips.
TakeProfitPips Initial take-profit distance in pips.
TrailingStopPips Trailing stop distance in pips.
UseBreakEven Enable the break-even stop relocation.
BreakEvenTriggerPips Pip profit required before break-even protection activates.
BreakEvenOffsetPips Additional pips added to the entry price when placing the break-even stop.
FastMaPeriod Length of the fast LWMA calculated on typical price.
SlowMaPeriod Length of the slow LWMA calculated on typical price.
MomentumPeriod Period of the Momentum indicator on the higher timeframe.
MomentumBuyThreshold Minimum momentum deviation for long entries.
MomentumSellThreshold Minimum momentum deviation for short entries.
MacdFastLength Fast EMA length for the higher timeframe MACD filter.
MacdSlowLength Slow EMA length for the higher timeframe MACD filter.
MacdSignalLength Signal length for the higher timeframe MACD filter.
UseEquityStop Enable portfolio drawdown protection.
EquityRiskPercent Allowed equity drawdown percentage before forcefully closing the position.
CandleType Primary timeframe used for entries.
MomentumCandleType Higher timeframe used for momentum confirmation.
MacdCandleType Higher timeframe used for MACD confirmation.

Notes

  • The StockSharp port keeps a single net position, matching the EA which closes opposite orders before opening a new trade.
  • All protective rules operate on closed candles to replicate the "new bar" processing in the original script.
  • When using synthetic symbols or instruments without a standard pip size, adjust StopLossPips and related parameters to the exchange’s tick value.
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;

public class CryptoAnalysisStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

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

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public CryptoAnalysisStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { 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;

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

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

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}