Ver no GitHub

Estratégia Color Zerolag TriX OSMA

Visão Geral

Esta estratégia utiliza um oscilador TRIX OSMA de zero defasagem construído a partir de cinco períodos TRIX diferentes. Cada componente TRIX é ponderado e suavizado para formar um único oscilador que reage a mudanças de tendência com defasagem mínima. Uma posição comprada é aberta quando o oscilador vira para cima e uma posição vendida quando ele vira para baixo.

Como Funciona

  1. Calcular cinco valores TRIX usando médias móveis exponenciais triplas e a taxa de mudança.
  2. Combinar os valores TRIX com seus pesos para formar um valor de tendência rápida.
  3. Suavizar a tendência rápida duas vezes para criar um oscilador OSMA de zero defasagem.
  4. Detectar reversões de tendência comparando os dois últimos valores do oscilador.
  5. Entrar comprado em uma virada para cima e vendido em uma virada para baixo; posições opostas existentes são fechadas antes de abrir uma nova.

Parâmetros

  • Smoothing1 – fator de suavização para a tendência lenta.
  • Smoothing2 – fator de suavização para a linha OSMA.
  • Factor1..Factor5 – pesos aplicados a cada componente TRIX.
  • Period1..Period5 – períodos para os cinco cálculos TRIX.
  • CandleType – série de candles usada para cálculos.

Indicadores

  • TripleExponentialMovingAverage
  • RateOfChange
  • Combinação personalizada de TRIX OSMA de zero defasagem

Notas

A estratégia requer que todos os cinco indicadores TRIX estejam formados antes de gerar sinais. A proteção para stops e alvos é ativada via StartProtection.

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 a zero-lag TRIX OSMA oscillator.
/// Uses TRIX direction changes for trend reversal signals.
/// </summary>
public class ColorZerolagTrixOsmaStrategy : Strategy
{
	private readonly StrategyParam<int> _trixPeriod;
	private readonly StrategyParam<int> _signalPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevOsma;
	private decimal _prevPrevOsma;
	private int _count;

	public int TrixPeriod { get => _trixPeriod.Value; set => _trixPeriod.Value = value; }
	public int SignalPeriod { get => _signalPeriod.Value; set => _signalPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public ColorZerolagTrixOsmaStrategy()
	{
		_trixPeriod = Param(nameof(TrixPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("TRIX Period", "TRIX calculation period", "Indicator");

		_signalPeriod = Param(nameof(SignalPeriod), 9)
			.SetGreaterThanZero()
			.SetDisplay("Signal Period", "Signal line EMA period", "Indicator");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevOsma = 0;
		_prevPrevOsma = 0;
		_count = 0;
	}

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

		var trix = new Trix { Length = TrixPeriod };
		var signal = new ExponentialMovingAverage { Length = SignalPeriod };

		SubscribeCandles(CandleType)
			.Bind(trix, signal, ProcessCandle)
			.Start();
	}

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

		var osma = trixValue - signalValue;
		_count++;

		if (_count < 3)
		{
			_prevPrevOsma = _prevOsma;
			_prevOsma = osma;
			return;
		}

		// Buy when OSMA turns up
		var turnUp = _prevOsma < _prevPrevOsma && osma > _prevOsma;
		// Sell when OSMA turns down
		var turnDown = _prevOsma > _prevPrevOsma && osma < _prevOsma;

		if (turnUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (turnDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevPrevOsma = _prevOsma;
		_prevOsma = osma;
	}
}