Ver no GitHub

Estratégia de Rompimento de CorrectedAverage

Esta estratégia opera rompimentos relativos a uma média móvel CorrectedAverage. O indicador suaviza o preço usando uma média móvel e ajusta o fator de suavização com base no desvio padrão das variações de preço.

Quando o preço fecha acima da média corrigida por um número especificado de pontos e depois recua ao nível de rompimento, a estratégia abre uma posição comprada. A lógica inversa é usada para operações vendidas. Stop-loss e take-profit são aplicados em pontos de preço absolutos.

Parâmetros

  • Candle Type – período dos candles usados para os cálculos.
  • Length – período para a média móvel e o desvio padrão.
  • MA Type – tipo de média móvel (SMA, EMA, SMMA, LWMA).
  • Level Points – distância de rompimento da média corrigida em passos de preço.
  • Stop Loss Points – distância do stop-loss do preço de entrada em passos de preço.
  • Take Profit Points – distância do take-profit do preço de entrada em passos de preço.
  • Enable Long – permitir abertura de posições compradas.
  • Enable Short – permitir abertura de posições vendidas.

Lógica de operação

  1. Calcular a média móvel e o desvio padrão.
  2. Construir a média corrigida usando valores anteriores e a relação de variância para suavizar saltos repentinos.
  3. Detectar rompimentos quando a barra anterior fecha além da média corrigida mais ou menos o nível configurado.
  4. Após um rompimento, aguardar o retorno da próxima barra ao nível de rompimento e abrir uma posição na direção do rompimento.
  5. Fechar posições opostas quando um novo sinal de rompimento aparecer.
  6. Aplicar proteções de stop-loss e take-profit.

Notas

Esta estratégia é uma conversão do script MQL Exp_CorrectedAverage.mq5. Destina-se a fins educacionais e requer testes adicionais antes do uso em operações reais.

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>
/// Strategy based on the Corrected Average breakout.
/// Monitors price relative to a corrected moving average and trades on breakouts.
/// </summary>
public class CorrectedAverageBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _length;
	private readonly StrategyParam<int> _levelPoints;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private decimal _prevCorrected;
	private decimal _prevPrevCorrected;
	private decimal _prevClose;
	private decimal _prevPrevClose;
	private bool _isInitialized;
	private decimal _level;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int Length { get => _length.Value; set => _length.Value = value; }
	public int LevelPoints { get => _levelPoints.Value; set => _levelPoints.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public CorrectedAverageBreakoutStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for calculations", "General");

		_length = Param(nameof(Length), 12)
			.SetDisplay("Length", "Period of moving average", "Indicator");

		_levelPoints = Param(nameof(LevelPoints), 300)
			.SetDisplay("Level Points", "Breakout distance in price steps", "Trading");

		_stopLossPoints = Param(nameof(StopLossPoints), 1000)
			.SetDisplay("Stop Loss Points", "Stop loss in price steps", "Risk");

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevCorrected = default;
		_prevPrevCorrected = default;
		_prevClose = default;
		_prevPrevClose = default;
		_isInitialized = default;
		_level = default;
	}

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

		var step = Security.PriceStep ?? 1m;
		_level = LevelPoints * step;

		var ma = new ExponentialMovingAverage { Length = Length };
		var std = new StandardDeviation { Length = Length };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ma, std, ProcessCandle).Start();

		StartProtection(
			new Unit(StopLossPoints * step, UnitTypes.Absolute),
			new Unit(TakeProfitPoints * step, UnitTypes.Absolute));
	}

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		decimal corrected;

		if (!_isInitialized)
		{
			corrected = maValue;
			_isInitialized = true;
		}
		else
		{
			var v1 = stdValue * stdValue;
			var v2 = (_prevCorrected - maValue) * (_prevCorrected - maValue);
			var k = (v2 < v1 || v2 == 0m) ? 0m : 1m - (v1 / v2);
			corrected = _prevCorrected + k * (maValue - _prevCorrected);
		}

		var buySignal = _prevPrevClose > _prevPrevCorrected + _level && _prevClose <= _prevCorrected + _level;
		var sellSignal = _prevPrevClose < _prevPrevCorrected - _level && _prevClose >= _prevCorrected - _level;

		if (buySignal && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (sellSignal && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevPrevCorrected = _prevCorrected;
		_prevPrevClose = _prevClose;
		_prevCorrected = corrected;
		_prevClose = candle.ClosePrice;
	}
}