Ver en GitHub

XAng Zad C TM MM Rec Strategy

Overview

This strategy is a C# port of the MetaTrader expert advisor Exp_XAng_Zad_C_Tm_MMRec. It trades adaptive price envelopes calculated by the custom XAng Zad C indicator and adds a time-based trading window together with a simple money-management recounter. The goal is to capture breakouts when the adaptive upper and lower lines cross each other while dynamically scaling position size after a configurable number of losing trades.

Core logic

  • Indicator – the XAng Zad C indicator produces an upper and lower adaptive channel. The C# version reproduces the envelope calculation and supports several moving-average smoothers (SMA, EMA, SMMA, LWMA). Exotic smoothers from the original script fall back to EMA.
  • Entry signals – when the previous candle shows the upper line above the lower line and the current bar closes with the upper line falling below the lower line, a bullish breakout is detected. The opposite configuration produces a bearish breakout. The SignalShift parameter defines how many closed candles back should be compared.
  • Exit signals – optional flags allow closing longs when the upper line moves back under the lower line and closing shorts on the inverse event. Positions are also closed immediately when the configured trading window ends.
  • Money management – the strategy keeps a list of historical trade results. If the most recent BuyLossTrigger (or SellLossTrigger) losing trades appear within the last BuyTotalTrigger (or SellTotalTrigger) trades, the next position uses the reduced volume. Otherwise the normal volume is restored.
  • Risk control – static stop loss and take profit targets are applied in multiples of the instrument price step. If either level is reached during the candle, the position is flattened at the corresponding price.

Parameters

Name Description
NormalVolume Default order size used when there is no recent losing streak.
ReducedVolume Order size applied after a sequence of losing trades.
BuyTotalTrigger / SellTotalTrigger Number of historical trades inspected when evaluating the loss counter.
BuyLossTrigger / SellLossTrigger Required losing trades (within the above window) to switch to the reduced volume.
EnableBuyEntries / EnableSellEntries Allow long or short entries.
EnableBuyExit / EnableSellExit Allow automatic exit signals based on channel crossings.
UseTradingWindow Enable the time filter. Outside the window all positions are closed and no new orders are submitted.
WindowStart / WindowEnd Start and end times of the daily trading window (UTC). The window can span midnight.
StopLoss Stop loss distance expressed in multiples of Security.PriceStep. Set to 0 to disable.
TakeProfit Profit target distance expressed in multiples of Security.PriceStep. Set to 0 to disable.
SignalShift Number of already closed candles used for the crossover comparison.
CandleType Candle data type used for the indicator (default: 4-hour candles).
SmoothMethods Moving-average smoother inside the indicator. Unsupported values automatically use EMA.
MaLength Smoothing length for the indicator.
MaPhase Additional phase parameter retained from the original indicator (currently informational).
Ki Ratio controlling how quickly the adaptive envelopes react to price changes.
AppliedPrices Price source used to feed the indicator (close, open, median, etc.).

Notes compared to the MQL5 version

  • MetaTrader money-management helpers relied on global trade history. The C# version tracks completed trades locally and applies the same trigger logic.
  • Lot sizing is expressed directly as strategy volume. Adjust NormalVolume/ReducedVolume to match the target quantity for your venue.
  • Time windows are configured with TimeSpan values. When WindowStart equals WindowEnd, trading is disabled (matching the zero-width window behaviour of the original script).
  • The strategy assumes full position reversals and does not keep partial positions from previous signals.
  • Unsupported smoothing types (JJMA, JurX, ParMA, T3, VIDYA, AMA) default to EMA. Consider extending CreateMovingAverage if you require a specific alternative.

Usage tips

  1. Choose a candle type that matches the indicator timeframe used in MetaTrader (default: H4).
  2. Tune stop-loss and take-profit distances based on the instrument tick size to approximate the point-based values from the original EA.
  3. Optimise the money-management triggers to reflect the asset volatility and your risk tolerance.
  4. Monitor indicator behaviour on a chart (upper/lower channel lines) to confirm that the reconstructed indicator matches expectations before live trading.
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>
/// XAng Zad strategy using SMA crossover with momentum recovery.
/// </summary>
public class XAngZadCTmMmRecStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal? _prevFast;
	private decimal? _prevSlow;

	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 XAngZadCTmMmRecStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

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

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

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

		_prevFast = null;
		_prevSlow = null;

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

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		if (_prevFast == null || _prevSlow == null)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fastVal > slowVal;

		_prevFast = fastVal;
		_prevSlow = slowVal;

		if (!prevAbove && currAbove)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (prevAbove && !currAbove)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}