Ver en GitHub

Macd Pattern Trader Todo v0.01

La estrategia replica el asesor experto "MacdPatternTraderAll v0.01" MetaTrader. Ejecuta seis patrones de entrada independientes basados ​​en MACD en el mismo flujo de velas, gestiona el riesgo con niveles adaptables de stop-loss y take-profit, realiza una toma de ganancias por etapas y, opcionalmente, aplica una regla de tamaño de martingala lenta después de ciclos perdedores.

Características principales

  • Seis configuraciones MACD: cada patrón utiliza sus propios períodos rápidos/lentos EMA y niveles de umbral (Pattern1Pattern6). Los patrones se pueden activar o desactivar de forma independiente.
  • Niveles de riesgo dinámicos: los niveles de stop-loss se derivan de máximos y mínimos recientes con compensaciones configurables, mientras que los niveles de toma de ganancias se repiten sobre bloques de barras sucesivos para reflejar la implementación original MQL.
  • Filtro de sesión: la estrategia opera solo dentro de la ventana configurable StartTime / StopTime cuando UseTimeFilter está habilitado.
  • Salidas parciales: las posiciones rentables se escalan en dos pasos una vez que los filtros EMA/SMA confirman el impulso, siguiendo la lógica ActivePosManager original.
  • Martingala lenta: cuando UseMartingale es verdadero, el tamaño de la siguiente operación se duplica después de un ciclo perdedor y se reinicia después de cualquier ciclo rentable.

Lógica de entrada por patrón

  1. Patrón 1 (etiqueta Pattern1)
    • Se arma poco después de que la línea principal MACD empuja por encima de Pattern1MaxThreshold y luego gira con una secuencia baja alta.
    • Se arma mucho después de estirarse por debajo de Pattern1MinThreshold y producir una secuencia baja más alta.
  2. Patrón 2 (etiqueta Pattern2)
    • Cuenta las oscilaciones alrededor de la línea cero. Los cortos se activan cuando falla un swing positivo cerca de Pattern2MinThreshold. Los largos aparecen cuando una oscilación negativa se desvanece cerca de Pattern2MaxThreshold. El algoritmo reproduce las comprobaciones de distancia originales comparando valores absolutos MACD (valueMin2 / valueCurr2).
  3. Patrón 3 (etiqueta Pattern3)
    • Rastrea hasta tres picos MACD descendentes (o ascendentes) para detectar un "triple gancho". Sólo cuando todos los umbrales intermedios (Pattern3MaxThreshold, Pattern3MaxLowThreshold, Pattern3MinThreshold, Pattern3MinHighThreshold) coinciden se permiten nuevas posiciones.
  4. Patrón 4 (etiqueta Pattern4)
    • Observa los picos de MACD fuera de Pattern4MaxThreshold/Pattern4MinThreshold seguidos de intentos fallidos de llegar a nuevos extremos. Se conserva un contador adicional (Pattern4AdditionalBars) por motivos de compatibilidad.
  5. Patrón 5 (etiqueta Pattern5)
    • Implementa la ruptura de la zona neutral utilizada en el asesor experto. Los pantalones cortos requieren un rebote desde debajo de Pattern5MinThreshold de vuelta dentro de la zona neutral y otro fallo. Los largos siguen la secuencia reflejada alrededor de Pattern5MaxThreshold.
  6. Patrón 6 (etiqueta Pattern6)
    • Cuenta el número de barras consecutivas por encima o por debajo de los niveles de umbral. Después de gastar más de Pattern6TriggerBars dentro del área de sobrecompra/sobreventa y regresar por debajo/por encima del umbral, la estrategia abre una operación a menos que Pattern6MaxBars bloquee la señal.

Cada patrón utiliza los métodos auxiliares TryOpenLong / TryOpenShort, lo que garantiza que las paradas y los objetivos se calculen antes de emitir cualquier orden.

Gestión de riesgos y comercio

  • Stop-loss: CalculateStopPrice escanea las velas terminadas stopBars más recientes (excluyendo la activa) y aplica el punto configurado offset. Los precios se ajustan para instrumentos de 3/5 decimales al igual que en la versión MQL.
  • Take-profit: CalculateTakeProfit recorre bloques consecutivos de takeBars velas hasta que no se encuentra ningún extremo nuevo, imitando el bucle anidado iLowest/iHighest del código original.
  • Salidas parciales: ManageActivePositions cierra un tercio de la posición con ProfitThreshold ganancia cuando el precio se confirma con ema2. Se activa una segunda salida de tamaño medio cuando el precio alcanza el filtro combinado (sma3 + ema4) / 2.
  • Salidas duras: CheckRiskManagement emite salidas completas del mercado una vez que se tocan los niveles almacenados de stop-loss o take-profit.
  • Martingale control: OnOwnTradeReceived acumula PnL realizado para el ciclo de plano a plano actual. Cuando la posición vuelve a estabilizarse, AdjustVolumeOnFlat restablece el volumen a InitialVolume después de las ganancias o lo duplica después de las pérdidas si UseMartingale está habilitado.

Parámetros

Todas las perillas de configuración están expuestas a través de propiedades StrategyParam<T> para su optimización en StockSharp Designer.

  • General: CandleType, InitialVolume, UseTimeFilter, StartTime, StopTime, UseMartingale.
  • Patrones 1 a 6: recuentos de barras de stop-loss/take-profit, compensaciones, MACD períodos rápidos/lentos y niveles de umbral que coinciden con las entradas externas del script MQL.
  • Administrador de posición: EMA/SMA longitudes (EmaPeriod1, EmaPeriod2, SmaPeriod3, EmaPeriod4) utilizadas en el filtro de salida parcial.

Todos los valores predeterminados reflejan las variables extern de MacdPatternTraderAll v0.01.

Notas de uso

  • La estrategia espera que un símbolo con PriceStep y Decimals válidos calcule las compensaciones correctamente.
  • Proporcione una serie de velas a través de CandleType (por ejemplo, TimeSpan.FromMinutes(5).TimeFrame()).
  • Cuando se activan varios patrones simultáneamente, la estrategia abrirá solo una posición porque cada llamada de entrada recalcula el volumen deseado combinado y elimina las paradas opuestas.
  • La lógica de salida por etapas funciona con posiciones agregadas, por lo que se producen cierres parciales incluso si varios patrones comparten la misma dirección comercial.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Conversion of the "MacdPatternTraderAll v0.01" expert advisor.
/// Implements six independent MACD based entry patterns, partial exits,
/// adaptive stop-loss and take-profit levels, martingale position sizing and intraday time filtering.
/// </summary>
public class MacdPatternTraderAllV001Strategy : Strategy
{
	private readonly StrategyParam<bool> _pattern1Enabled;
	private readonly StrategyParam<int> _pattern1StopLossBars;
	private readonly StrategyParam<int> _pattern1TakeProfitBars;
	private readonly StrategyParam<int> _pattern1Offset;
	private readonly StrategyParam<int> _pattern1Slow;
	private readonly StrategyParam<int> _pattern1Fast;
	private readonly StrategyParam<decimal> _pattern1MaxThreshold;
	private readonly StrategyParam<decimal> _pattern1MinThreshold;

	private readonly StrategyParam<bool> _pattern2Enabled;
	private readonly StrategyParam<int> _pattern2StopLossBars;
	private readonly StrategyParam<int> _pattern2TakeProfitBars;
	private readonly StrategyParam<int> _pattern2Offset;
	private readonly StrategyParam<int> _pattern2Slow;
	private readonly StrategyParam<int> _pattern2Fast;
	private readonly StrategyParam<decimal> _pattern2MaxThreshold;
	private readonly StrategyParam<decimal> _pattern2MinThreshold;

	private readonly StrategyParam<bool> _pattern3Enabled;
	private readonly StrategyParam<int> _pattern3StopLossBars;
	private readonly StrategyParam<int> _pattern3TakeProfitBars;
	private readonly StrategyParam<int> _pattern3Offset;
	private readonly StrategyParam<int> _pattern3Slow;
	private readonly StrategyParam<int> _pattern3Fast;
	private readonly StrategyParam<decimal> _pattern3MaxThreshold;
	private readonly StrategyParam<decimal> _pattern3MaxLowThreshold;
	private readonly StrategyParam<decimal> _pattern3MinThreshold;
	private readonly StrategyParam<decimal> _pattern3MinHighThreshold;

	private readonly StrategyParam<bool> _pattern4Enabled;
	private readonly StrategyParam<int> _pattern4StopLossBars;
	private readonly StrategyParam<int> _pattern4TakeProfitBars;
	private readonly StrategyParam<int> _pattern4Offset;
	private readonly StrategyParam<int> _pattern4Slow;
	private readonly StrategyParam<int> _pattern4Fast;
	private readonly StrategyParam<int> _pattern4AdditionalBars;
	private readonly StrategyParam<decimal> _pattern4MaxThreshold;
	private readonly StrategyParam<decimal> _pattern4MaxLowThreshold;
	private readonly StrategyParam<decimal> _pattern4MinThreshold;
	private readonly StrategyParam<decimal> _pattern4MinHighThreshold;

	private readonly StrategyParam<bool> _pattern5Enabled;
	private readonly StrategyParam<int> _pattern5StopLossBars;
	private readonly StrategyParam<int> _pattern5TakeProfitBars;
	private readonly StrategyParam<int> _pattern5Offset;
	private readonly StrategyParam<int> _pattern5Slow;
	private readonly StrategyParam<int> _pattern5Fast;
	private readonly StrategyParam<decimal> _pattern5MaxNeutralThreshold;
	private readonly StrategyParam<decimal> _pattern5MaxThreshold;
	private readonly StrategyParam<decimal> _pattern5MinNeutralThreshold;
	private readonly StrategyParam<decimal> _pattern5MinThreshold;

	private readonly StrategyParam<bool> _pattern6Enabled;
	private readonly StrategyParam<int> _pattern6StopLossBars;
	private readonly StrategyParam<int> _pattern6TakeProfitBars;
	private readonly StrategyParam<int> _pattern6Offset;
	private readonly StrategyParam<int> _pattern6Slow;
	private readonly StrategyParam<int> _pattern6Fast;
	private readonly StrategyParam<decimal> _pattern6MaxThreshold;
	private readonly StrategyParam<decimal> _pattern6MinThreshold;
	private readonly StrategyParam<int> _pattern6MaxBars;
	private readonly StrategyParam<int> _pattern6MinBars;
	private readonly StrategyParam<int> _pattern6TriggerBars;

	private readonly StrategyParam<int> _emaPeriod1;
	private readonly StrategyParam<int> _emaPeriod2;
	private readonly StrategyParam<int> _smaPeriod3;
	private readonly StrategyParam<int> _emaPeriod4;

	private readonly StrategyParam<decimal> _initialVolume;
	private readonly StrategyParam<bool> _useTimeFilter;
	private readonly StrategyParam<TimeSpan> _startTime;
	private readonly StrategyParam<TimeSpan> _stopTime;
	private readonly StrategyParam<bool> _useMartingale;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _macdHistoryLength;
	private readonly StrategyParam<int> _candleHistoryLimit;
	private readonly StrategyParam<decimal> _minPartialVolume;
	private readonly StrategyParam<decimal> _profitThreshold;

	private MovingAverageConvergenceDivergenceSignal _macd1 = null!;
	private MovingAverageConvergenceDivergenceSignal _macd2 = null!;
	private MovingAverageConvergenceDivergenceSignal _macd3 = null!;
	private MovingAverageConvergenceDivergenceSignal _macd4 = null!;
	private MovingAverageConvergenceDivergenceSignal _macd5 = null!;
	private MovingAverageConvergenceDivergenceSignal _macd6 = null!;
	private ExponentialMovingAverage _ema1 = null!;
	private ExponentialMovingAverage _ema2 = null!;
	private SimpleMovingAverage _sma3 = null!;
	private ExponentialMovingAverage _ema4 = null!;

	private readonly List<ICandleMessage> _candles = new();
	private readonly List<decimal> _macd1History = new();
	private readonly List<decimal> _macd2History = new();
	private readonly List<decimal> _macd3History = new();
	private readonly List<decimal> _macd4History = new();
	private readonly List<decimal> _macd5History = new();
	private readonly List<decimal> _macd6History = new();

	private bool _pattern1WasAbove;
	private bool _pattern1WasBelow;

	private bool _pattern2WasPositive;
	private bool _pattern2WasNegative;
	private bool _pattern2SellArmed;
	private bool _pattern2BuyArmed;

	private int _pattern3BarsBup;

	private int _pattern6BarsAbove;
	private int _pattern6BarsBelow;
	private bool _pattern6SellBlocked;
	private bool _pattern6BuyBlocked;
	private bool _pattern6SellReady;
	private bool _pattern6BuyReady;

	private decimal _currentVolume;
	private decimal _longVolume;
	private decimal _shortVolume;
	private decimal _longAveragePrice;
	private decimal _shortAveragePrice;
	private decimal _cycleRealizedPnL;
	private int _longPartialCount;
	private int _shortPartialCount;
	private decimal? _longStop;
	private decimal? _longTake;
	private decimal? _shortStop;
	private decimal? _shortTake;

	/// <summary>
	/// Enable or disable pattern #1.
	/// </summary>
	public bool Pattern1Enabled
	{
		get => _pattern1Enabled.Value;
		set => _pattern1Enabled.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #1 stop-loss search.
	/// </summary>
	public int Pattern1StopLossBars
	{
		get => _pattern1StopLossBars.Value;
		set => _pattern1StopLossBars.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #1 take-profit search.
	/// </summary>
	public int Pattern1TakeProfitBars
	{
		get => _pattern1TakeProfitBars.Value;
		set => _pattern1TakeProfitBars.Value = value;
	}

	/// <summary>
	/// Offset used when calculating the stop-loss for pattern #1.
	/// </summary>
	public int Pattern1Offset
	{
		get => _pattern1Offset.Value;
		set => _pattern1Offset.Value = value;
	}

	/// <summary>
	/// Slow EMA length for pattern #1 MACD.
	/// </summary>
	public int Pattern1Slow
	{
		get => _pattern1Slow.Value;
		set => _pattern1Slow.Value = value;
	}

	/// <summary>
	/// Fast EMA length for pattern #1 MACD.
	/// </summary>
	public int Pattern1Fast
	{
		get => _pattern1Fast.Value;
		set => _pattern1Fast.Value = value;
	}

	/// <summary>
	/// Upper MACD threshold for pattern #1.
	/// </summary>
	public decimal Pattern1MaxThreshold
	{
		get => _pattern1MaxThreshold.Value;
		set => _pattern1MaxThreshold.Value = value;
	}

	/// <summary>
	/// Lower MACD threshold for pattern #1.
	/// </summary>
	public decimal Pattern1MinThreshold
	{
		get => _pattern1MinThreshold.Value;
		set => _pattern1MinThreshold.Value = value;
	}

	/// <summary>
	/// Enable or disable pattern #2.
	/// </summary>
	public bool Pattern2Enabled
	{
		get => _pattern2Enabled.Value;
		set => _pattern2Enabled.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #2 stop-loss search.
	/// </summary>
	public int Pattern2StopLossBars
	{
		get => _pattern2StopLossBars.Value;
		set => _pattern2StopLossBars.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #2 take-profit search.
	/// </summary>
	public int Pattern2TakeProfitBars
	{
		get => _pattern2TakeProfitBars.Value;
		set => _pattern2TakeProfitBars.Value = value;
	}

	/// <summary>
	/// Offset used when calculating the stop-loss for pattern #2.
	/// </summary>
	public int Pattern2Offset
	{
		get => _pattern2Offset.Value;
		set => _pattern2Offset.Value = value;
	}

	/// <summary>
	/// Slow EMA length for pattern #2 MACD.
	/// </summary>
	public int Pattern2Slow
	{
		get => _pattern2Slow.Value;
		set => _pattern2Slow.Value = value;
	}

	/// <summary>
	/// Fast EMA length for pattern #2 MACD.
	/// </summary>
	public int Pattern2Fast
	{
		get => _pattern2Fast.Value;
		set => _pattern2Fast.Value = value;
	}

	/// <summary>
	/// Upper MACD threshold for pattern #2.
	/// </summary>
	public decimal Pattern2MaxThreshold
	{
		get => _pattern2MaxThreshold.Value;
		set => _pattern2MaxThreshold.Value = value;
	}

	/// <summary>
	/// Lower MACD threshold for pattern #2.
	/// </summary>
	public decimal Pattern2MinThreshold
	{
		get => _pattern2MinThreshold.Value;
		set => _pattern2MinThreshold.Value = value;
	}

	/// <summary>
	/// Enable or disable pattern #3.
	/// </summary>
	public bool Pattern3Enabled
	{
		get => _pattern3Enabled.Value;
		set => _pattern3Enabled.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #3 stop-loss search.
	/// </summary>
	public int Pattern3StopLossBars
	{
		get => _pattern3StopLossBars.Value;
		set => _pattern3StopLossBars.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #3 take-profit search.
	/// </summary>
	public int Pattern3TakeProfitBars
	{
		get => _pattern3TakeProfitBars.Value;
		set => _pattern3TakeProfitBars.Value = value;
	}

	/// <summary>
	/// Offset used when calculating the stop-loss for pattern #3.
	/// </summary>
	public int Pattern3Offset
	{
		get => _pattern3Offset.Value;
		set => _pattern3Offset.Value = value;
	}

	/// <summary>
	/// Slow EMA length for pattern #3 MACD.
	/// </summary>
	public int Pattern3Slow
	{
		get => _pattern3Slow.Value;
		set => _pattern3Slow.Value = value;
	}

	/// <summary>
	/// Fast EMA length for pattern #3 MACD.
	/// </summary>
	public int Pattern3Fast
	{
		get => _pattern3Fast.Value;
		set => _pattern3Fast.Value = value;
	}

	/// <summary>
	/// Upper MACD threshold for pattern #3 trend detection.
	/// </summary>
	public decimal Pattern3MaxThreshold
	{
		get => _pattern3MaxThreshold.Value;
		set => _pattern3MaxThreshold.Value = value;
	}

	/// <summary>
	/// Secondary upper MACD threshold for pattern #3.
	/// </summary>
	public decimal Pattern3MaxLowThreshold
	{
		get => _pattern3MaxLowThreshold.Value;
		set => _pattern3MaxLowThreshold.Value = value;
	}

	/// <summary>
	/// Lower MACD threshold for pattern #3.
	/// </summary>
	public decimal Pattern3MinThreshold
	{
		get => _pattern3MinThreshold.Value;
		set => _pattern3MinThreshold.Value = value;
	}

	/// <summary>
	/// Secondary lower MACD threshold for pattern #3.
	/// </summary>
	public decimal Pattern3MinHighThreshold
	{
		get => _pattern3MinHighThreshold.Value;
		set => _pattern3MinHighThreshold.Value = value;
	}

	/// <summary>
	/// Enable or disable pattern #4.
	/// </summary>
	public bool Pattern4Enabled
	{
		get => _pattern4Enabled.Value;
		set => _pattern4Enabled.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #4 stop-loss search.
	/// </summary>
	public int Pattern4StopLossBars
	{
		get => _pattern4StopLossBars.Value;
		set => _pattern4StopLossBars.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #4 take-profit search.
	/// </summary>
	public int Pattern4TakeProfitBars
	{
		get => _pattern4TakeProfitBars.Value;
		set => _pattern4TakeProfitBars.Value = value;
	}

	/// <summary>
	/// Offset used when calculating the stop-loss for pattern #4.
	/// </summary>
	public int Pattern4Offset
	{
		get => _pattern4Offset.Value;
		set => _pattern4Offset.Value = value;
	}

	/// <summary>
	/// Slow EMA length for pattern #4 MACD.
	/// </summary>
	public int Pattern4Slow
	{
		get => _pattern4Slow.Value;
		set => _pattern4Slow.Value = value;
	}

	/// <summary>
	/// Fast EMA length for pattern #4 MACD.
	/// </summary>
	public int Pattern4Fast
	{
		get => _pattern4Fast.Value;
		set => _pattern4Fast.Value = value;
	}

	/// <summary>
	/// Additional bar counter for pattern #4 (kept for compatibility).
	/// </summary>
	public int Pattern4AdditionalBars
	{
		get => _pattern4AdditionalBars.Value;
		set => _pattern4AdditionalBars.Value = value;
	}

	/// <summary>
	/// Upper MACD threshold for pattern #4.
	/// </summary>
	public decimal Pattern4MaxThreshold
	{
		get => _pattern4MaxThreshold.Value;
		set => _pattern4MaxThreshold.Value = value;
	}

	/// <summary>
	/// Secondary upper MACD threshold for pattern #4.
	/// </summary>
	public decimal Pattern4MaxLowThreshold
	{
		get => _pattern4MaxLowThreshold.Value;
		set => _pattern4MaxLowThreshold.Value = value;
	}

	/// <summary>
	/// Lower MACD threshold for pattern #4.
	/// </summary>
	public decimal Pattern4MinThreshold
	{
		get => _pattern4MinThreshold.Value;
		set => _pattern4MinThreshold.Value = value;
	}

	/// <summary>
	/// Secondary lower MACD threshold for pattern #4.
	/// </summary>
	public decimal Pattern4MinHighThreshold
	{
		get => _pattern4MinHighThreshold.Value;
		set => _pattern4MinHighThreshold.Value = value;
	}

	/// <summary>
	/// Enable or disable pattern #5.
	/// </summary>
	public bool Pattern5Enabled
	{
		get => _pattern5Enabled.Value;
		set => _pattern5Enabled.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #5 stop-loss search.
	/// </summary>
	public int Pattern5StopLossBars
	{
		get => _pattern5StopLossBars.Value;
		set => _pattern5StopLossBars.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #5 take-profit search.
	/// </summary>
	public int Pattern5TakeProfitBars
	{
		get => _pattern5TakeProfitBars.Value;
		set => _pattern5TakeProfitBars.Value = value;
	}

	/// <summary>
	/// Offset used when calculating the stop-loss for pattern #5.
	/// </summary>
	public int Pattern5Offset
	{
		get => _pattern5Offset.Value;
		set => _pattern5Offset.Value = value;
	}

	/// <summary>
	/// Slow EMA length for pattern #5 MACD.
	/// </summary>
	public int Pattern5Slow
	{
		get => _pattern5Slow.Value;
		set => _pattern5Slow.Value = value;
	}

	/// <summary>
	/// Fast EMA length for pattern #5 MACD.
	/// </summary>
	public int Pattern5Fast
	{
		get => _pattern5Fast.Value;
		set => _pattern5Fast.Value = value;
	}

	/// <summary>
	/// Neutral upper MACD threshold for pattern #5.
	/// </summary>
	public decimal Pattern5MaxNeutralThreshold
	{
		get => _pattern5MaxNeutralThreshold.Value;
		set => _pattern5MaxNeutralThreshold.Value = value;
	}

	/// <summary>
	/// Upper MACD threshold for pattern #5.
	/// </summary>
	public decimal Pattern5MaxThreshold
	{
		get => _pattern5MaxThreshold.Value;
		set => _pattern5MaxThreshold.Value = value;
	}

	/// <summary>
	/// Neutral lower MACD threshold for pattern #5.
	/// </summary>
	public decimal Pattern5MinNeutralThreshold
	{
		get => _pattern5MinNeutralThreshold.Value;
		set => _pattern5MinNeutralThreshold.Value = value;
	}

	/// <summary>
	/// Lower MACD threshold for pattern #5.
	/// </summary>
	public decimal Pattern5MinThreshold
	{
		get => _pattern5MinThreshold.Value;
		set => _pattern5MinThreshold.Value = value;
	}

	/// <summary>
	/// Enable or disable pattern #6.
	/// </summary>
	public bool Pattern6Enabled
	{
		get => _pattern6Enabled.Value;
		set => _pattern6Enabled.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #6 stop-loss search.
	/// </summary>
	public int Pattern6StopLossBars
	{
		get => _pattern6StopLossBars.Value;
		set => _pattern6StopLossBars.Value = value;
	}

	/// <summary>
	/// Number of bars for the pattern #6 take-profit search.
	/// </summary>
	public int Pattern6TakeProfitBars
	{
		get => _pattern6TakeProfitBars.Value;
		set => _pattern6TakeProfitBars.Value = value;
	}

	/// <summary>
	/// Offset used when calculating the stop-loss for pattern #6.
	/// </summary>
	public int Pattern6Offset
	{
		get => _pattern6Offset.Value;
		set => _pattern6Offset.Value = value;
	}

	/// <summary>
	/// Slow EMA length for pattern #6 MACD.
	/// </summary>
	public int Pattern6Slow
	{
		get => _pattern6Slow.Value;
		set => _pattern6Slow.Value = value;
	}

	/// <summary>
	/// Fast EMA length for pattern #6 MACD.
	/// </summary>
	public int Pattern6Fast
	{
		get => _pattern6Fast.Value;
		set => _pattern6Fast.Value = value;
	}

	/// <summary>
	/// Upper MACD threshold for pattern #6.
	/// </summary>
	public decimal Pattern6MaxThreshold
	{
		get => _pattern6MaxThreshold.Value;
		set => _pattern6MaxThreshold.Value = value;
	}

	/// <summary>
	/// Lower MACD threshold for pattern #6.
	/// </summary>
	public decimal Pattern6MinThreshold
	{
		get => _pattern6MinThreshold.Value;
		set => _pattern6MinThreshold.Value = value;
	}

	/// <summary>
	/// Maximum number of bars above/below the threshold before blocking pattern #6 signals.
	/// </summary>
	public int Pattern6MaxBars
	{
		get => _pattern6MaxBars.Value;
		set => _pattern6MaxBars.Value = value;
	}

	/// <summary>
	/// Minimum number of bars above/below the threshold before pattern #6 can reset.
	/// </summary>
	public int Pattern6MinBars
	{
		get => _pattern6MinBars.Value;
		set => _pattern6MinBars.Value = value;
	}

	/// <summary>
	/// Number of bars required before pattern #6 can trigger after crossing the threshold.
	/// </summary>
	public int Pattern6TriggerBars
	{
		get => _pattern6TriggerBars.Value;
		set => _pattern6TriggerBars.Value = value;
	}

	/// <summary>
	/// EMA period used by the position manager (first EMA).
	/// </summary>
	public int EmaPeriod1
	{
		get => _emaPeriod1.Value;
		set => _emaPeriod1.Value = value;
	}

	/// <summary>
	/// EMA period used by the position manager (second EMA).
	/// </summary>
	public int EmaPeriod2
	{
		get => _emaPeriod2.Value;
		set => _emaPeriod2.Value = value;
	}

	/// <summary>
	/// SMA period used by the position manager.
	/// </summary>
	public int SmaPeriod3
	{
		get => _smaPeriod3.Value;
		set => _smaPeriod3.Value = value;
	}

	/// <summary>
	/// EMA period used in the hybrid average for the position manager.
	/// </summary>
	public int EmaPeriod4
	{
		get => _emaPeriod4.Value;
		set => _emaPeriod4.Value = value;
	}

	/// <summary>
	/// Base volume for new entries.
	/// </summary>
	public decimal InitialVolume
	{
		get => _initialVolume.Value;
		set => _initialVolume.Value = value;
	}

	/// <summary>
	/// Flag indicating whether the trading window filter is active.
	/// </summary>
	public bool UseTimeFilter
	{
		get => _useTimeFilter.Value;
		set => _useTimeFilter.Value = value;
	}

	/// <summary>
	/// Start time of the trading window.
	/// </summary>
	public TimeSpan StartTime
	{
		get => _startTime.Value;
		set => _startTime.Value = value;
	}

	/// <summary>
	/// End time of the trading window.
	/// </summary>
	public TimeSpan StopTime
	{
		get => _stopTime.Value;
		set => _stopTime.Value = value;
	}

	/// <summary>
	/// Enable or disable martingale volume adjustment.
	/// </summary>
	public bool UseMartingale
	{
		get => _useMartingale.Value;
		set => _useMartingale.Value = value;
	}

	/// <summary>
	/// Candle type used by the strategy.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}
	/// <summary>
	/// Number of MACD values cached per pattern for hook detection.
	/// </summary>
	public int MacdHistoryLength
	{
		get => _macdHistoryLength.Value;
		set => _macdHistoryLength.Value = value;
	}

	/// <summary>
	/// Maximum number of finished candles stored for trailing calculations.
	/// </summary>
	public int CandleHistoryLimit
	{
		get => _candleHistoryLimit.Value;
		set => _candleHistoryLimit.Value = value;
	}

	/// <summary>
	/// Minimal volume allowed when performing partial exits.
	/// </summary>
	public decimal MinPartialVolume
	{
		get => _minPartialVolume.Value;
		set => _minPartialVolume.Value = value;
	}

	/// <summary>
	/// Minimal floating profit required before partial exits can trigger.
	/// </summary>
	public decimal ProfitThreshold
	{
		get => _profitThreshold.Value;
		set => _profitThreshold.Value = value;
	}


	/// <summary>
	/// Constructor.
	/// </summary>
	public MacdPatternTraderAllV001Strategy()
	{
		_pattern1Enabled = Param(nameof(Pattern1Enabled), true)
			.SetDisplay("Pattern 1", "Enable first MACD pattern", "Patterns");
		_pattern1StopLossBars = Param(nameof(Pattern1StopLossBars), 22)
			.SetGreaterThanZero()
			.SetDisplay("P1 Stop Bars", "Bars used for stop-loss search", "Pattern 1");
		_pattern1TakeProfitBars = Param(nameof(Pattern1TakeProfitBars), 32)
			.SetGreaterThanZero()
			.SetDisplay("P1 Take Bars", "Bars used for take-profit search", "Pattern 1");
		_pattern1Offset = Param(nameof(Pattern1Offset), 40)
			.SetGreaterThanZero()
			.SetDisplay("P1 Offset", "Stop-loss offset in points", "Pattern 1");
		_pattern1Slow = Param(nameof(Pattern1Slow), 13)
			.SetGreaterThanZero()
			.SetDisplay("P1 Slow EMA", "Slow EMA length for MACD", "Pattern 1");
		_pattern1Fast = Param(nameof(Pattern1Fast), 24)
			.SetGreaterThanZero()
			.SetDisplay("P1 Fast EMA", "Fast EMA length for MACD", "Pattern 1");
		_pattern1MaxThreshold = Param(nameof(Pattern1MaxThreshold), 95m)
			.SetDisplay("P1 Max", "Upper MACD threshold", "Pattern 1");
		_pattern1MinThreshold = Param(nameof(Pattern1MinThreshold), -45m)
			.SetDisplay("P1 Min", "Lower MACD threshold", "Pattern 1");

		_pattern2Enabled = Param(nameof(Pattern2Enabled), true)
			.SetDisplay("Pattern 2", "Enable second MACD pattern", "Patterns");
		_pattern2StopLossBars = Param(nameof(Pattern2StopLossBars), 2)
			.SetGreaterThanZero()
			.SetDisplay("P2 Stop Bars", "Bars used for stop-loss search", "Pattern 2");
		_pattern2TakeProfitBars = Param(nameof(Pattern2TakeProfitBars), 2)
			.SetGreaterThanZero()
			.SetDisplay("P2 Take Bars", "Bars used for take-profit search", "Pattern 2");
		_pattern2Offset = Param(nameof(Pattern2Offset), 50)
			.SetGreaterThanZero()
			.SetDisplay("P2 Offset", "Stop-loss offset in points", "Pattern 2");
		_pattern2Slow = Param(nameof(Pattern2Slow), 7)
			.SetGreaterThanZero()
			.SetDisplay("P2 Slow EMA", "Slow EMA length for MACD", "Pattern 2");
		_pattern2Fast = Param(nameof(Pattern2Fast), 17)
			.SetGreaterThanZero()
			.SetDisplay("P2 Fast EMA", "Fast EMA length for MACD", "Pattern 2");
		_pattern2MaxThreshold = Param(nameof(Pattern2MaxThreshold), 45m)
			.SetDisplay("P2 Max", "Upper MACD threshold", "Pattern 2");
		_pattern2MinThreshold = Param(nameof(Pattern2MinThreshold), -35m)
			.SetDisplay("P2 Min", "Lower MACD threshold", "Pattern 2");

		_pattern3Enabled = Param(nameof(Pattern3Enabled), true)
			.SetDisplay("Pattern 3", "Enable third MACD pattern", "Patterns");
		_pattern3StopLossBars = Param(nameof(Pattern3StopLossBars), 8)
			.SetGreaterThanZero()
			.SetDisplay("P3 Stop Bars", "Bars used for stop-loss search", "Pattern 3");
		_pattern3TakeProfitBars = Param(nameof(Pattern3TakeProfitBars), 12)
			.SetGreaterThanZero()
			.SetDisplay("P3 Take Bars", "Bars used for take-profit search", "Pattern 3");
		_pattern3Offset = Param(nameof(Pattern3Offset), 2)
			.SetGreaterThanZero()
			.SetDisplay("P3 Offset", "Stop-loss offset in points", "Pattern 3");
		_pattern3Slow = Param(nameof(Pattern3Slow), 2)
			.SetGreaterThanZero()
			.SetDisplay("P3 Slow EMA", "Slow EMA length for MACD", "Pattern 3");
		_pattern3Fast = Param(nameof(Pattern3Fast), 32)
			.SetGreaterThanZero()
			.SetDisplay("P3 Fast EMA", "Fast EMA length for MACD", "Pattern 3");
		_pattern3MaxThreshold = Param(nameof(Pattern3MaxThreshold), 15m)
			.SetDisplay("P3 Max", "Primary upper MACD threshold", "Pattern 3");
		_pattern3MaxLowThreshold = Param(nameof(Pattern3MaxLowThreshold), 40m)
			.SetDisplay("P3 Max Low", "Secondary upper MACD threshold", "Pattern 3");
		_pattern3MinThreshold = Param(nameof(Pattern3MinThreshold), -50m)
			.SetDisplay("P3 Min", "Primary lower MACD threshold", "Pattern 3");
		_pattern3MinHighThreshold = Param(nameof(Pattern3MinHighThreshold), -5m)
			.SetDisplay("P3 Min High", "Secondary lower MACD threshold", "Pattern 3");

		_pattern4Enabled = Param(nameof(Pattern4Enabled), true)
			.SetDisplay("Pattern 4", "Enable fourth MACD pattern", "Patterns");
		_pattern4StopLossBars = Param(nameof(Pattern4StopLossBars), 10)
			.SetGreaterThanZero()
			.SetDisplay("P4 Stop Bars", "Bars used for stop-loss search", "Pattern 4");
		_pattern4TakeProfitBars = Param(nameof(Pattern4TakeProfitBars), 32)
			.SetGreaterThanZero()
			.SetDisplay("P4 Take Bars", "Bars used for take-profit search", "Pattern 4");
		_pattern4Offset = Param(nameof(Pattern4Offset), 45)
			.SetGreaterThanZero()
			.SetDisplay("P4 Offset", "Stop-loss offset in points", "Pattern 4");
		_pattern4Slow = Param(nameof(Pattern4Slow), 9)
			.SetGreaterThanZero()
			.SetDisplay("P4 Slow EMA", "Slow EMA length for MACD", "Pattern 4");
		_pattern4Fast = Param(nameof(Pattern4Fast), 4)
			.SetGreaterThanZero()
			.SetDisplay("P4 Fast EMA", "Fast EMA length for MACD", "Pattern 4");
		_pattern4AdditionalBars = Param(nameof(Pattern4AdditionalBars), 10)
			.SetGreaterThanZero()
			.SetDisplay("P4 Extra Bars", "Compatibility counter, kept for completeness", "Pattern 4");
		_pattern4MaxThreshold = Param(nameof(Pattern4MaxThreshold), 165m)
			.SetDisplay("P4 Max", "Primary upper MACD threshold", "Pattern 4");
		_pattern4MaxLowThreshold = Param(nameof(Pattern4MaxLowThreshold), 1m)
			.SetDisplay("P4 Max Low", "Secondary upper MACD threshold", "Pattern 4");
		_pattern4MinThreshold = Param(nameof(Pattern4MinThreshold), -5m)
			.SetDisplay("P4 Min", "Primary lower MACD threshold", "Pattern 4");
		_pattern4MinHighThreshold = Param(nameof(Pattern4MinHighThreshold), -6m)
			.SetDisplay("P4 Min High", "Secondary lower MACD threshold", "Pattern 4");

		_pattern5Enabled = Param(nameof(Pattern5Enabled), true)
			.SetDisplay("Pattern 5", "Enable fifth MACD pattern", "Patterns");
		_pattern5StopLossBars = Param(nameof(Pattern5StopLossBars), 8)
			.SetGreaterThanZero()
			.SetDisplay("P5 Stop Bars", "Bars used for stop-loss search", "Pattern 5");
		_pattern5TakeProfitBars = Param(nameof(Pattern5TakeProfitBars), 47)
			.SetGreaterThanZero()
			.SetDisplay("P5 Take Bars", "Bars used for take-profit search", "Pattern 5");
		_pattern5Offset = Param(nameof(Pattern5Offset), 45)
			.SetGreaterThanZero()
			.SetDisplay("P5 Offset", "Stop-loss offset in points", "Pattern 5");
		_pattern5Slow = Param(nameof(Pattern5Slow), 2)
			.SetGreaterThanZero()
			.SetDisplay("P5 Slow EMA", "Slow EMA length for MACD", "Pattern 5");
		_pattern5Fast = Param(nameof(Pattern5Fast), 6)
			.SetGreaterThanZero()
			.SetDisplay("P5 Fast EMA", "Fast EMA length for MACD", "Pattern 5");
		_pattern5MaxNeutralThreshold = Param(nameof(Pattern5MaxNeutralThreshold), 5m)
			.SetDisplay("P5 Neutral Max", "Neutral upper MACD threshold", "Pattern 5");
		_pattern5MaxThreshold = Param(nameof(Pattern5MaxThreshold), 15m)
			.SetDisplay("P5 Max", "Upper MACD threshold", "Pattern 5");
		_pattern5MinNeutralThreshold = Param(nameof(Pattern5MinNeutralThreshold), -5m)
			.SetDisplay("P5 Neutral Min", "Neutral lower MACD threshold", "Pattern 5");
		_pattern5MinThreshold = Param(nameof(Pattern5MinThreshold), -30m)
			.SetDisplay("P5 Min", "Lower MACD threshold", "Pattern 5");

		_pattern6Enabled = Param(nameof(Pattern6Enabled), true)
			.SetDisplay("Pattern 6", "Enable sixth MACD pattern", "Patterns");
		_pattern6StopLossBars = Param(nameof(Pattern6StopLossBars), 26)
			.SetGreaterThanZero()
			.SetDisplay("P6 Stop Bars", "Bars used for stop-loss search", "Pattern 6");
		_pattern6TakeProfitBars = Param(nameof(Pattern6TakeProfitBars), 42)
			.SetGreaterThanZero()
			.SetDisplay("P6 Take Bars", "Bars used for take-profit search", "Pattern 6");
		_pattern6Offset = Param(nameof(Pattern6Offset), 20)
			.SetGreaterThanZero()
			.SetDisplay("P6 Offset", "Stop-loss offset in points", "Pattern 6");
		_pattern6Slow = Param(nameof(Pattern6Slow), 8)
			.SetGreaterThanZero()
			.SetDisplay("P6 Slow EMA", "Slow EMA length for MACD", "Pattern 6");
		_pattern6Fast = Param(nameof(Pattern6Fast), 4)
			.SetGreaterThanZero()
			.SetDisplay("P6 Fast EMA", "Fast EMA length for MACD", "Pattern 6");
		_pattern6MaxThreshold = Param(nameof(Pattern6MaxThreshold), 5m)
			.SetDisplay("P6 Max", "Upper MACD threshold", "Pattern 6");
		_pattern6MinThreshold = Param(nameof(Pattern6MinThreshold), -10m)
			.SetDisplay("P6 Min", "Lower MACD threshold", "Pattern 6");
		_pattern6MaxBars = Param(nameof(Pattern6MaxBars), 5)
			.SetGreaterThanZero()
			.SetDisplay("P6 Max Bars", "Maximum bar counter above/below the threshold", "Pattern 6");
		_pattern6MinBars = Param(nameof(Pattern6MinBars), 5)
			.SetGreaterThanZero()
			.SetDisplay("P6 Min Bars", "Minimum bar counter above/below the threshold", "Pattern 6");
		_pattern6TriggerBars = Param(nameof(Pattern6TriggerBars), 4)
			.SetGreaterThanZero()
			.SetDisplay("P6 Trigger Bars", "Required bars before triggering", "Pattern 6");

		_emaPeriod1 = Param(nameof(EmaPeriod1), 7)
			.SetGreaterThanZero()
			.SetDisplay("EMA 1", "First EMA length for position manager", "Management");
		_emaPeriod2 = Param(nameof(EmaPeriod2), 21)
			.SetGreaterThanZero()
			.SetDisplay("EMA 2", "Second EMA length for position manager", "Management");
		_smaPeriod3 = Param(nameof(SmaPeriod3), 98)
			.SetGreaterThanZero()
			.SetDisplay("SMA", "Simple MA length for position manager", "Management");
		_emaPeriod4 = Param(nameof(EmaPeriod4), 365)
			.SetGreaterThanZero()
			.SetDisplay("EMA 4", "Fourth EMA length for position manager", "Management");

		_initialVolume = Param(nameof(InitialVolume), 0.1m)
			.SetGreaterThanZero()
			.SetDisplay("Initial Volume", "Base volume for orders", "General");
		_useTimeFilter = Param(nameof(UseTimeFilter), true)
			.SetDisplay("Time Filter", "Enable intraday trading window", "General");
		_startTime = Param(nameof(StartTime), new TimeSpan(7, 0, 0))
			.SetDisplay("Start Time", "Trading window start", "General");
		_stopTime = Param(nameof(StopTime), new TimeSpan(17, 0, 0))
			.SetDisplay("Stop Time", "Trading window end", "General");
		_useMartingale = Param(nameof(UseMartingale), true)
			.SetDisplay("Martingale", "Enable martingale volume adjustment", "Risk");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles used for analysis", "General");
		_macdHistoryLength = Param(nameof(MacdHistoryLength), 3)
			.SetGreaterThanZero()
			.SetDisplay("MACD History", "Number of MACD values cached per pattern", "General");

		_candleHistoryLimit = Param(nameof(CandleHistoryLimit), 1000)
			.SetGreaterThanZero()
			.SetDisplay("Candle History", "Maximum stored candles for trailing logic", "General");

		_minPartialVolume = Param(nameof(MinPartialVolume), 0.01m)
			.SetGreaterThanZero()
			.SetDisplay("Min Partial Volume", "Lowest allowed volume for partial exits", "General");

		_profitThreshold = Param(nameof(ProfitThreshold), 5m)
			.SetGreaterThanZero()
			.SetDisplay("Profit Threshold", "Minimal floating profit before partial exits", "General");
	}

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

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

		_candles.Clear();
		_macd1History.Clear();
		_macd2History.Clear();
		_macd3History.Clear();
		_macd4History.Clear();
		_macd5History.Clear();
		_macd6History.Clear();

		_pattern1WasAbove = false;
		_pattern1WasBelow = false;
		_pattern2WasPositive = false;
		_pattern2WasNegative = false;
		_pattern2SellArmed = false;
		_pattern2BuyArmed = false;
		_pattern3BarsBup = 0;
		_pattern6BarsAbove = 0;
		_pattern6BarsBelow = 0;
		_pattern6SellBlocked = false;
		_pattern6BuyBlocked = false;
		_pattern6SellReady = false;
		_pattern6BuyReady = false;

		_currentVolume = InitialVolume;
		_longVolume = 0m;
		_shortVolume = 0m;
		_longAveragePrice = 0m;
		_shortAveragePrice = 0m;
		_cycleRealizedPnL = 0m;
		_longPartialCount = 0;
		_shortPartialCount = 0;
		_longStop = null;
		_longTake = null;
		_shortStop = null;
		_shortTake = null;
	}

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

		_currentVolume = InitialVolume;

		_macd1 = CreateMacd(Pattern1Fast, Pattern1Slow);
		_macd2 = CreateMacd(Pattern2Fast, Pattern2Slow);
		_macd3 = CreateMacd(Pattern3Fast, Pattern3Slow);
		_macd4 = CreateMacd(Pattern4Fast, Pattern4Slow);
		_macd5 = CreateMacd(Pattern5Fast, Pattern5Slow);
		_macd6 = CreateMacd(Pattern6Fast, Pattern6Slow);

		_ema1 = new EMA { Length = EmaPeriod1 };
		_ema2 = new EMA { Length = EmaPeriod2 };
		_sma3 = new SMA { Length = SmaPeriod3 };
		_ema4 = new EMA { Length = EmaPeriod4 };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(new IIndicator[] { _macd1, _macd2, _macd3, _macd4, _macd5, _macd6, _ema1, _ema2, _sma3, _ema4 }, ProcessCandle)
			.Start();

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

	private void ProcessCandle(
		ICandleMessage candle,
		IIndicatorValue[] values)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var macd1Value = values[0];
		var macd2Value = values[1];
		var macd3Value = values[2];
		var macd4Value = values[3];
		var macd5Value = values[4];
		var macd6Value = values[5];
		var ema1Value = values[6];
		var ema2Value = values[7];
		var sma3Value = values[8];
		var ema4Value = values[9];

		_candles.Add(candle);
		TrimCandles();

		CheckRiskManagement(candle);

		if (!macd1Value.IsFinal || !macd2Value.IsFinal || !macd3Value.IsFinal ||
			!macd4Value.IsFinal || !macd5Value.IsFinal || !macd6Value.IsFinal)
		{
			UpdateMacdHistories(macd1Value, macd2Value, macd3Value, macd4Value, macd5Value, macd6Value);
			return;
		}

		if (macd1Value is not MovingAverageConvergenceDivergenceSignalValue macd1Signal ||
			macd2Value is not MovingAverageConvergenceDivergenceSignalValue macd2Signal ||
			macd3Value is not MovingAverageConvergenceDivergenceSignalValue macd3Signal ||
			macd4Value is not MovingAverageConvergenceDivergenceSignalValue macd4Signal ||
			macd5Value is not MovingAverageConvergenceDivergenceSignalValue macd5Signal ||
			macd6Value is not MovingAverageConvergenceDivergenceSignalValue macd6Signal)
		{
			UpdateMacdHistories(macd1Value, macd2Value, macd3Value, macd4Value, macd5Value, macd6Value);
			return;
		}

		if (macd1Signal.Macd is not decimal macd1Curr ||
			macd2Signal.Macd is not decimal macd2Curr ||
			macd3Signal.Macd is not decimal macd3Curr ||
			macd4Signal.Macd is not decimal macd4Curr ||
			macd5Signal.Macd is not decimal macd5Curr ||
			macd6Signal.Macd is not decimal macd6Curr)
		{
			UpdateMacdHistories(macd1Value, macd2Value, macd3Value, macd4Value, macd5Value, macd6Value);
			return;
		}

		if (!ema2Value.IsFormed || !sma3Value.IsFormed || !ema4Value.IsFormed)
		{
			UpdateMacdHistories(macd1Value, macd2Value, macd3Value, macd4Value, macd5Value, macd6Value);
			return;
		}

		var ema2 = ema2Value.GetValue<decimal>();
		var sma3 = sma3Value.GetValue<decimal>();
		var ema4 = ema4Value.GetValue<decimal>();

		ManageActivePositions(candle, ema2, sma3, ema4);

		var allowTrade = IsFormedAndOnlineAndAllowTrading();
		var timeOk = !UseTimeFilter || IsWithinTradingWindow(candle.OpenTime.TimeOfDay);

		var macd1Prev = GetPrevious(_macd1History, 1);
		var macd1Prev2 = GetPrevious(_macd1History, 2);
		var macd2Prev = GetPrevious(_macd2History, 1);
		var macd2Prev2 = GetPrevious(_macd2History, 2);
		var macd3Prev = GetPrevious(_macd3History, 1);
		var macd3Prev2 = GetPrevious(_macd3History, 2);
		var macd4Prev = GetPrevious(_macd4History, 1);
		var macd4Prev2 = GetPrevious(_macd4History, 2);
		var macd5Prev = GetPrevious(_macd5History, 1);
		var macd5Prev2 = GetPrevious(_macd5History, 2);
		var macd6Prev = GetPrevious(_macd6History, 1);
		var macd6Prev2 = GetPrevious(_macd6History, 2);

		if (allowTrade && timeOk)
		{
			if (Pattern1Enabled && macd1Prev.HasValue && macd1Prev2.HasValue)
				ProcessPattern1(candle, macd1Curr, macd1Prev.Value, macd1Prev2.Value);

			if (Pattern2Enabled && macd2Prev.HasValue && macd2Prev2.HasValue)
				ProcessPattern2(candle, macd2Curr, macd2Prev.Value, macd2Prev2.Value);

			if (Pattern3Enabled && macd3Prev.HasValue && macd3Prev2.HasValue)
				ProcessPattern3(candle, macd3Curr, macd3Prev.Value, macd3Prev2.Value);

			if (Pattern4Enabled && macd4Prev.HasValue && macd4Prev2.HasValue)
				ProcessPattern4(candle, macd4Curr, macd4Prev.Value, macd4Prev2.Value);

			if (Pattern5Enabled && macd5Prev.HasValue && macd5Prev2.HasValue)
				ProcessPattern5(candle, macd5Curr, macd5Prev.Value, macd5Prev2.Value);

			if (Pattern6Enabled && macd6Prev.HasValue && macd6Prev2.HasValue)
				ProcessPattern6(candle, macd6Curr, macd6Prev.Value, macd6Prev2.Value);
		}

		UpdateMacdHistories(macd1Value, macd2Value, macd3Value, macd4Value, macd5Value, macd6Value);
	}

	private void ProcessPattern1(ICandleMessage candle, decimal macdcurr, decimal macdlast, decimal macdlast3)
	{
		if (macdcurr > Pattern1MaxThreshold)
			_pattern1WasAbove = true;

		if (macdcurr < 0m)
			_pattern1WasAbove = false;

		if (macdcurr < Pattern1MaxThreshold && macdcurr < macdlast && macdlast > macdlast3 && _pattern1WasAbove && macdcurr > 0m && macdlast3 < Pattern1MaxThreshold)
		{
			if (TryOpenShort(candle, Pattern1StopLossBars, Pattern1Offset, Pattern1TakeProfitBars))
			{
				_pattern1WasAbove = false;
				_longPartialCount = 0;
			}
		}

		if (macdcurr < Pattern1MinThreshold)
			_pattern1WasBelow = true;

		if (macdcurr > 0m)
			_pattern1WasBelow = false;

		if (macdcurr > Pattern1MinThreshold && macdcurr < 0m && macdcurr > macdlast && macdlast < macdlast3 && _pattern1WasBelow && macdlast3 > Pattern1MinThreshold)
		{
			if (TryOpenLong(candle, Pattern1StopLossBars, Pattern1Offset, Pattern1TakeProfitBars))
			{
				_pattern1WasBelow = false;
				_shortPartialCount = 0;
			}
		}
	}

	private void ProcessPattern2(ICandleMessage candle, decimal macdcurr, decimal macdlast, decimal macdlast3)
	{
		if (macdcurr > 0m)
		{
			_pattern2WasPositive = true;
			_pattern2SellArmed = false;
		}

		if (macdcurr > macdlast && macdlast < macdlast3 && _pattern2WasPositive && macdcurr > Pattern2MinThreshold && macdcurr < 0m && !_pattern2SellArmed)
		{
			_pattern2SellArmed = true;
		}

		var valueMin2 = Math.Abs(macdlast * 10000m);
		var valueCurr2 = Math.Abs(macdcurr * 10000m);

		if (_pattern2SellArmed && macdcurr < macdlast && macdlast > macdlast3 && macdcurr < 0m && valueMin2 <= valueCurr2)
			_pattern2WasPositive = false;

		if (_pattern2SellArmed && macdcurr < macdlast && macdlast > macdlast3 && macdcurr < 0m)
		{
			if (TryOpenShort(candle, Pattern2StopLossBars, Pattern2Offset, Pattern2TakeProfitBars))
			{
				_pattern2WasPositive = false;
				_pattern2SellArmed = false;
			}
		}

		if (macdcurr < 0m)
		{
			_pattern2WasNegative = true;
			_pattern2BuyArmed = false;
		}

		if (macdcurr < Pattern2MaxThreshold && macdcurr < macdlast && macdlast > macdlast3 && _pattern2WasNegative && macdcurr > 0m)
		{
			_pattern2BuyArmed = true;
		}

		var valueMax2 = Math.Abs(macdlast * 10000m);

		if (_pattern2BuyArmed && macdcurr > macdlast && macdlast < macdlast3 && macdcurr > 0m && valueMax2 <= valueCurr2)
			_pattern2WasNegative = false;

		if (_pattern2BuyArmed && macdcurr > macdlast && macdlast < macdlast3 && macdcurr > 0m)
		{
			if (TryOpenLong(candle, Pattern2StopLossBars, Pattern2Offset, Pattern2TakeProfitBars))
			{
				_pattern2WasNegative = false;
				_pattern2BuyArmed = false;
			}
		}
	}

	private void ProcessPattern3(ICandleMessage candle, decimal macdcurr, decimal macdlast, decimal macdlast3)
	{
		var aopSell = false;
		var aopBuy = false;

		var S3 = macdcurr > Pattern3MaxLowThreshold ? 1 : 0;
		if (macdcurr > Pattern3MaxLowThreshold)
			_pattern3BarsBup++;

		decimal max13 = 0, max23 = 0;
		var stops3 = 0;
		var stops13 = 0;

		if (S3 == 1 && macdcurr < macdlast && macdlast > macdlast3 && macdlast > max13 && stops3 == 0)
			max13 = macdlast;

		if (max13 > 0 && macdcurr < Pattern3MaxThreshold)
			stops3 = 1;

		if (macdcurr < Pattern3MaxLowThreshold)
		{
			stops3 = 0;
			max13 = 0;
			S3 = 0;
		}

		if (stops3 == 1 && macdcurr > Pattern3MaxThreshold && macdcurr < macdlast && macdlast > macdlast3 && macdlast > max13 && macdlast > max23 && stops13 == 0)
			max23 = macdlast;

		if (max23 > 0 && macdcurr < Pattern3MaxThreshold)
			stops13 = 1;

		if (macdcurr < Pattern3MaxLowThreshold)
		{
			stops13 = 0;
			max23 = 0;
		}

		if (stops13 == 1 && macdcurr < Pattern3MaxThreshold && macdlast < Pattern3MaxThreshold && macdlast3 < Pattern3MaxThreshold &&
			macdcurr < macdlast && macdlast > macdlast3 && macdlast < (decimal)max23)
			aopSell = true;

		if (macdcurr < Pattern3MaxLowThreshold)
			aopSell = false;

		if (aopSell)
		{
			if (TryOpenShort(candle, Pattern3StopLossBars, Pattern3Offset, Pattern3TakeProfitBars))
			{
				_pattern3BarsBup = 0;
				return;
			}
		}

		var bS3 = macdcurr < Pattern3MinThreshold ? 1 : 0;
		var sstops3 = 0;
		var sstops13 = 0;
		decimal min13 = 0, min23 = 0;

		if (bS3 == 1 && macdcurr > macdlast && macdlast < macdlast3 && macdlast < min13 && sstops3 == 0)
			min13 = macdlast;

		if (min13 < 0 && macdcurr > Pattern3MinThreshold)
		{
			sstops3 = 1;
			bS3 = 0;
		}

		if (macdcurr > Pattern3MinHighThreshold)
		{
			sstops3 = 0;
			min13 = 0;
			bS3 = 0;
		}

		if (sstops3 == 1 && macdcurr < Pattern3MaxThreshold && macdcurr > macdlast && macdlast < macdlast3 && macdlast < min13 && macdlast < min23 && sstops13 == 0)
			min23 = macdlast;

		if (min23 < 0 && macdcurr > Pattern3MinThreshold)
		{
			sstops13 = 1;
			sstops3 = 0;
		}

		if (macdcurr > Pattern3MinHighThreshold)
		{
			sstops13 = 0;
			min23 = 0;
		}

		if (sstops13 == 1 && macdcurr > Pattern3MinThreshold && macdlast > Pattern3MinThreshold && macdlast3 > Pattern3MinThreshold &&
			macdcurr > macdlast && macdlast < macdlast3 && macdlast > min23)
		{
			aopBuy = true;
			sstops13 = 0;
		}

		if (macdcurr > Pattern3MaxThreshold)
			aopBuy = false;

		if (aopBuy)
		{
			TryOpenLong(candle, Pattern3StopLossBars, Pattern3Offset, Pattern3TakeProfitBars);
		}
	}

	private void ProcessPattern4(ICandleMessage candle, decimal macdcurr, decimal macdlast, decimal macdlast3)
	{
		var aopSell = false;
		var aopBuy = false;
		decimal max14 = 0;
		decimal min14 = 0;
		var stops4 = 0;
		var sstop4 = 0;

		if (macdcurr > Pattern4MaxThreshold && macdcurr < macdlast && macdlast > macdlast3 && stops4 == 0)
		{
			max14 = macdlast;
			stops4 = 1;
		}

		if (macdcurr < Pattern4MaxThreshold)
		{
			stops4 = 0;
			max14 = 0;
		}

		if (stops4 == 1 && macdcurr > Pattern4MaxThreshold && macdcurr < macdlast && macdlast > macdlast3 && macdlast < max14)
			aopSell = true;

		if (macdcurr < Pattern4MaxThreshold)
			aopSell = false;

		if (aopSell)
		{
			if (TryOpenShort(candle, Pattern4StopLossBars, Pattern4Offset, Pattern4TakeProfitBars))
				return;
		}

		if (macdcurr < Pattern4MinThreshold && macdcurr > macdlast && macdlast < macdlast3 && sstop4 == 0)
		{
			min14 = macdlast;
			sstop4 = 1;
		}

		if (macdcurr > Pattern4MinThreshold)
		{
			sstop4 = 0;
			min14 = 0;
		}

		if (sstop4 == 1 && macdcurr < Pattern4MinThreshold && macdcurr > macdlast && macdlast < macdlast3 && macdlast > min14)
			aopBuy = true;

		if (macdcurr > Pattern4MaxThreshold)
			aopBuy = false;

		if (aopBuy)
		{
			TryOpenLong(candle, Pattern4StopLossBars, Pattern4Offset, Pattern4TakeProfitBars);
		}
	}

	private void ProcessPattern5(ICandleMessage candle, decimal macdcurr, decimal macdlast, decimal macdlast3)
	{
		var aopSell = false;
		var aopBuy = false;
		var stops5 = 0;
		var stopb5 = 0;
		var Sb5 = 0;
		var Ss5 = 0;

		if (macdcurr < Pattern5MinNeutralThreshold && stops5 == 0)
			stops5 = 1;

		if (macdcurr > Pattern5MinThreshold && stops5 == 1)
		{
			stops5 = 0;
			Sb5 = 1;
		}

		if (Sb5 == 1 && macdcurr < macdlast && macdlast > macdlast3 && macdcurr < Pattern5MinThreshold && macdlast > Pattern5MinThreshold)
		{
			aopSell = true;
			Sb5 = 0;
		}

		if (macdcurr > 0m)
		{
			stops5 = 0;
			aopSell = false;
			Sb5 = 0;
		}

		if (aopSell)
		{
			if (TryOpenShort(candle, Pattern5StopLossBars, Pattern5Offset, Pattern5TakeProfitBars))
				return;
		}

		if (macdcurr > Pattern5MaxNeutralThreshold && stopb5 == 0)
			stopb5 = 1;

		if (macdcurr < 0m)
		{
			stopb5 = 0;
			aopBuy = false;
			Ss5 = 0;
		}

		if (macdcurr < Pattern5MaxThreshold && stopb5 == 1)
		{
			stopb5 = 0;
			Ss5 = 1;
		}

		if (Ss5 == 1 && macdcurr > macdlast && macdlast < macdlast3 && macdcurr > Pattern5MaxThreshold && macdlast < Pattern5MaxThreshold)
		{
			aopBuy = true;
			Ss5 = 0;
		}

		if (aopBuy)
		{
			TryOpenLong(candle, Pattern5StopLossBars, Pattern5Offset, Pattern5TakeProfitBars);
		}
	}

	private void ProcessPattern6(ICandleMessage candle, decimal macdcurr, decimal macdlast, decimal macdlast3)
	{
		if (macdcurr < Pattern6MaxThreshold)
			_pattern6SellBlocked = false;

		if (macdcurr > Pattern6MaxThreshold && _pattern6BarsAbove <= Pattern6MaxBars && !_pattern6SellBlocked)
			_pattern6BarsAbove++;

		if (_pattern6BarsAbove > Pattern6MaxBars)
		{
			_pattern6BarsAbove = 0;
			_pattern6SellBlocked = true;
		}

		if (_pattern6BarsAbove < Pattern6MinBars && macdcurr < Pattern6MaxThreshold)
			_pattern6BarsAbove = 0;

		if (macdcurr < Pattern6MaxThreshold && _pattern6BarsAbove > Pattern6TriggerBars)
			_pattern6SellReady = true;

		if (_pattern6SellReady)
		{
			if (TryOpenShort(candle, Pattern6StopLossBars, Pattern6Offset, Pattern6TakeProfitBars))
			{
				_pattern6SellReady = false;
				_pattern6BarsAbove = 0;
				_pattern6SellBlocked = false;
				return;
			}
		}

		if (macdcurr > Pattern6MinThreshold)
			_pattern6BuyBlocked = false;

		if (macdcurr < Pattern6MinThreshold && _pattern6BarsBelow <= Pattern6MaxBars && !_pattern6BuyBlocked)
			_pattern6BarsBelow++;

		if (_pattern6BarsBelow > Pattern6MaxBars)
		{
			_pattern6BuyBlocked = true;
			_pattern6BarsBelow = 0;
		}

		if (_pattern6BarsBelow < Pattern6MinBars && macdcurr > Pattern6MinThreshold)
			_pattern6BarsBelow = 0;

		if (macdcurr > Pattern6MinThreshold && _pattern6BarsBelow > Pattern6TriggerBars)
			_pattern6BuyReady = true;

		if (_pattern6BuyReady)
		{
			if (TryOpenLong(candle, Pattern6StopLossBars, Pattern6Offset, Pattern6TakeProfitBars))
			{
				_pattern6BuyReady = false;
				_pattern6BarsBelow = 0;
				_pattern6BuyBlocked = false;
			}
		}
	}

	private bool TryOpenLong(ICandleMessage candle, int stopBars, int offset, int takeBars)
	{
		var stop = CalculateStopPrice(Sides.Buy, stopBars, offset);
		var take = CalculateTakeProfit(Sides.Buy, takeBars);

		if (stop == null || take == null)
			return false;

		var volume = _currentVolume + Math.Max(0m, -Position);
		if (volume <= 0m)
			return false;

		BuyMarket(volume);
		_longStop = stop;
		_longTake = take;
		_shortStop = null;
		_shortTake = null;
		_longPartialCount = 0;
		_shortPartialCount = 0;
		return true;
	}

	private bool TryOpenShort(ICandleMessage candle, int stopBars, int offset, int takeBars)
	{
		var stop = CalculateStopPrice(Sides.Sell, stopBars, offset);
		var take = CalculateTakeProfit(Sides.Sell, takeBars);

		if (stop == null || take == null)
			return false;

		var volume = _currentVolume + Math.Max(0m, Position);
		if (volume <= 0m)
			return false;

		SellMarket(volume);
		_shortStop = stop;
		_shortTake = take;
		_longStop = null;
		_longTake = null;
		_longPartialCount = 0;
		_shortPartialCount = 0;
		return true;
	}

	private decimal? CalculateStopPrice(Sides side, int stopLossBars, int offset)
	{
		if (stopLossBars <= 0 || _candles.Count < stopLossBars)
			return null;

		var step = Security?.PriceStep ?? 1m;
		var digitsAdjust = (Security?.Decimals is 3 or 5) ? 10m : 1m;
		var offsetValue = offset * step * digitsAdjust;
		var minDistance = 10m * step * digitsAdjust;
		var currentPrice = _candles[^1].ClosePrice;

		if (side == Sides.Sell)
		{
			var highest = GetSegmentExtreme(Sides.Sell, stopLossBars, 0, true);
			if (highest == null)
				return null;

			var stop = highest.Value + offsetValue;
			if (stop < currentPrice)
				stop = currentPrice + minDistance;
			return stop;
		}
		else
		{
			var lowest = GetSegmentExtreme(Sides.Buy, stopLossBars, 0, true);
			if (lowest == null)
				return null;

			var stop = lowest.Value - offsetValue;
			if (stop > currentPrice)
				stop = currentPrice - minDistance;
			return stop;
		}
	}

	private decimal? CalculateTakeProfit(Sides side, int takeProfitBars)
	{
		if (takeProfitBars <= 0)
			return null;

		var x = 0;
		var best = GetSegmentExtreme(side, takeProfitBars, x, false);
		if (best == null)
			return null;

		while (true)
		{
			x += takeProfitBars;
			var next = GetSegmentExtreme(side, takeProfitBars, x, false);
			if (next == null)
				break;

			if (side == Sides.Sell)
			{
				if (best.Value > next.Value)
				{
					best = next;
					continue;
				}
			}
			else
			{
				if (best.Value < next.Value)
				{
					best = next;
					continue;
				}
			}

			break;
		}

		return best;
	}

	private decimal? GetSegmentExtreme(Sides side, int count, int start, bool forStop)
	{
		if (count <= 0)
			return null;

		var startIndex = _candles.Count - 1 - start;
		var endIndex = startIndex - (count - 1);

		if (startIndex < 0 || endIndex < 0)
			return null;

		decimal extreme = side == Sides.Sell ? decimal.MaxValue : decimal.MinValue;

		for (var i = startIndex; i >= endIndex; i--)
		{
			var candle = _candles[i];
			var value = side == Sides.Sell ? candle.LowPrice : candle.HighPrice;

			if (side == Sides.Sell)
			{
				if (value < extreme)
					extreme = value;
			}
			else
			{
				if (value > extreme)
					extreme = value;
			}
		}

		return extreme;
	}

	private void ManageActivePositions(ICandleMessage candle, decimal ema2, decimal sma3, decimal ema4)
	{
		if (Position > 0m && _longVolume > 0m)
		{
			var profit = (candle.ClosePrice - _longAveragePrice) * _longVolume;
			if (profit > ProfitThreshold && candle.ClosePrice > ema2 && _longPartialCount == 0)
			{
				var volume = Math.Max(Math.Round(_longVolume / 3m, 2, MidpointRounding.AwayFromZero), MinPartialVolume);
				volume = Math.Min(volume, Position);
				SellMarket(volume);
				_longPartialCount++;
				return;
			}

			if (profit > ProfitThreshold && candle.HighPrice > (sma3 + ema4) / 2m && _longPartialCount == 1)
			{
				var volume = Math.Max(Math.Round(_longVolume / 2m, 2, MidpointRounding.AwayFromZero), MinPartialVolume);
				volume = Math.Min(volume, Position);
				SellMarket(volume);
				_longPartialCount++;
			}
		}
		else if (Position < 0m && _shortVolume > 0m)
		{
			var profit = (_shortAveragePrice - candle.ClosePrice) * _shortVolume;
			if (profit > ProfitThreshold && candle.ClosePrice < ema2 && _shortPartialCount == 0)
			{
				var volume = Math.Max(Math.Round(_shortVolume / 3m, 2, MidpointRounding.AwayFromZero), MinPartialVolume);
				volume = Math.Min(volume, Math.Abs(Position));
				BuyMarket(volume);
				_shortPartialCount++;
				return;
			}

			if (profit > ProfitThreshold && candle.LowPrice < (sma3 + ema4) / 2m && _shortPartialCount == 1)
			{
				var volume = Math.Max(Math.Round(_shortVolume / 2m, 2, MidpointRounding.AwayFromZero), MinPartialVolume);
				volume = Math.Min(volume, Math.Abs(Position));
				BuyMarket(volume);
				_shortPartialCount++;
			}
		}
	}

	private void CheckRiskManagement(ICandleMessage candle)
	{
		if (Position > 0m)
		{
			if (_longStop.HasValue && candle.LowPrice <= _longStop.Value)
			{
				SellMarket(Math.Abs(Position));
				_longStop = null;
				_longTake = null;
			}
			else if (_longTake.HasValue && candle.HighPrice >= _longTake.Value)
			{
				SellMarket(Math.Abs(Position));
				_longStop = null;
				_longTake = null;
			}
		}
		else if (Position < 0m)
		{
			if (_shortStop.HasValue && candle.HighPrice >= _shortStop.Value)
			{
				BuyMarket(Math.Abs(Position));
				_shortStop = null;
				_shortTake = null;
			}
			else if (_shortTake.HasValue && candle.LowPrice <= _shortTake.Value)
			{
				BuyMarket(Math.Abs(Position));
				_shortStop = null;
				_shortTake = null;
			}
		}
	}

	private void UpdateMacdHistories(IIndicatorValue macd1Value, IIndicatorValue macd2Value, IIndicatorValue macd3Value,
		IIndicatorValue macd4Value, IIndicatorValue macd5Value, IIndicatorValue macd6Value)
	{
		AppendMacdValue(_macd1History, macd1Value);
		AppendMacdValue(_macd2History, macd2Value);
		AppendMacdValue(_macd3History, macd3Value);
		AppendMacdValue(_macd4History, macd4Value);
		AppendMacdValue(_macd5History, macd5Value);
		AppendMacdValue(_macd6History, macd6Value);
	}

	private void AppendMacdValue(List<decimal> history, IIndicatorValue value)
	{
		if (value is not MovingAverageConvergenceDivergenceSignalValue macdValue)
			return;

		if (macdValue.Macd is not decimal macd)
			return;

		history.Add(macd);
		if (history.Count > MacdHistoryLength)
			history.RemoveAt(0);
	}

	private static decimal? GetPrevious(List<decimal> history, int index)
	{
		if (history.Count <= index)
			return null;

		return history[^ (index + 1)];
	}

	private void TrimCandles()
	{
		if (_candles.Count > CandleHistoryLimit)
			_candles.RemoveRange(0, _candles.Count - CandleHistoryLimit);
	}

	private bool IsWithinTradingWindow(TimeSpan time)
	{
		var start = StartTime;
		var stop = StopTime;

		if (start == stop)
			return true;

		if (start < stop)
			return time > start && time < stop;

		return time > start || time < stop;
	}

	private MovingAverageConvergenceDivergenceSignal CreateMacd(int fast, int slow)
	{
		return new MovingAverageConvergenceDivergenceSignal
		{
			Macd =
			{
				ShortMa = { Length = fast },
				LongMa = { Length = slow }
			},
			SignalMa = { Length = 1 }
		};
	}

	/// <inheritdoc />
	protected override void OnOwnTradeReceived(MyTrade trade)
	{
		base.OnOwnTradeReceived(trade);

		if (trade.Order == null)
			return;

		var volume = trade.Trade?.Volume ?? 0m;
		var price = trade.Trade?.Price ?? 0m;

		if (volume <= 0m)
			return;

		if (trade.Order.Side == Sides.Buy)
		{
			var covered = Math.Min(_shortVolume, volume);
			if (covered > 0m)
			{
				_cycleRealizedPnL += (_shortAveragePrice - price) * covered;
				_shortVolume -= covered;
				if (_shortVolume <= 0m)
				{
					_shortVolume = 0m;
					_shortAveragePrice = 0m;
					_shortStop = null;
					_shortTake = null;
					_shortPartialCount = 0;
				}
			}

			var remaining = volume - covered;
			if (remaining > 0m)
			{
				if (_longVolume == 0m)
					_cycleRealizedPnL = 0m;

				var newVolume = _longVolume + remaining;
				_longAveragePrice = (_longAveragePrice * _longVolume + price * remaining) / newVolume;
				_longVolume = newVolume;
			}
		}
		else if (trade.Order.Side == Sides.Sell)
		{
			var covered = Math.Min(_longVolume, volume);
			if (covered > 0m)
			{
				_cycleRealizedPnL += (price - _longAveragePrice) * covered;
				_longVolume -= covered;
				if (_longVolume <= 0m)
				{
					_longVolume = 0m;
					_longAveragePrice = 0m;
					_longStop = null;
					_longTake = null;
					_longPartialCount = 0;
				}
			}

			var remaining = volume - covered;
			if (remaining > 0m)
			{
				if (_shortVolume == 0m)
					_cycleRealizedPnL = 0m;

				var newVolume = _shortVolume + remaining;
				_shortAveragePrice = (_shortAveragePrice * _shortVolume + price * remaining) / newVolume;
				_shortVolume = newVolume;
			}
		}

		if (Position == 0m)
			AdjustVolumeOnFlat();
	}

	private void AdjustVolumeOnFlat()
	{
		if (_cycleRealizedPnL > 0m || !UseMartingale)
		{
			_currentVolume = InitialVolume;
		}
		else if (UseMartingale)
		{
			_currentVolume *= 2m;
		}

		_cycleRealizedPnL = 0m;
		_longPartialCount = 0;
		_shortPartialCount = 0;
		_longStop = null;
		_longTake = null;
		_shortStop = null;
		_shortTake = null;
	}
}