Ver no GitHub

Estratégia especializada em Martingail

Visão geral

Martingail Expert é uma estratégia de martingale que segue tendências e depende do oscilador Stochastic para cronometrar novas sequências de negociações. Uma vez que o indicador gera uma direção, a estratégia inicia uma escada de ordens de mercado e gerencia a exposição usando uma meta de lucro dinâmica e um esquema geométrico de dimensionamento de posição.

Lógica de negociação

  • Calcule um oscilador Stochastic na série de velas configurada. Os valores finais mais recentes de %K e %D são armazenados em cache para tomada de decisão.
  • Inicie uma nova sequência longa quando %K (previous) > %D (previous) e %D (previous) estiverem acima do limite BuyLevel.
  • Inicie uma nova sequência curta quando %K (previous) < %D (previous) e %D (previous) estiverem abaixo do limite SellLevel.
  • Depois de entrar em uma sequência, cada movimento de preço favorável igual a ProfitFactor × openOrders pips adiciona uma nova posição ao volume base.
  • Cada movimento adverso de StepPoints pips multiplica o último volume preenchido por Multiplier e envia uma ordem média na mesma direção.

Regras de saída

  • Feche toda a posição assim que o último preço de preenchimento atingir uma meta de lucro dinâmico de ProfitFactor × openOrders pips na direção favorável.
  • Redefina o estado martingale sempre que o tamanho da posição agregada retornar a zero.

Gestão de risco

A progressão martingale aumenta a exposição rapidamente quando o preço se move contra a posição. Ajuste Multiplier, StepPoints e ProfitFactor cuidadosamente para corresponder ao tamanho da conta e à volatilidade do instrumento.

Parâmetros

Nome Descrição
Volume Volume base de ordem de mercado usado para a primeira negociação e todos os complementos favoráveis.
Multiplier Fator aplicado ao último volume executado ao calcular a média durante movimentos adversos.
StepPoints Distância em pontos que aciona uma ordem média de martingale.
ProfitFactor Meta de lucro por pedido aberto expressa em pontos. A distância real é ProfitFactor × number_of_orders.
KPeriod Comprimento de lookback para a linha %K.
DPeriod Suavização do comprimento da linha %D.
Slowing Suavização adicional aplicada a %K antes de comparar com %D.
BuyLevel Valor mínimo de %D necessário para permitir uma nova sequência longa.
SellLevel Valor máximo de %D necessário para permitir uma nova sequência curta.
CandleType Série de velas usada para cálculos (padrão: período de 5 minutos).

Notas

  • Funciona melhor em pares de FX líquidos onde o tamanho do pip e a etapa de volume permitem escala granular.
  • Requer margem suficiente para suportar vários passos de martingale.
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>
/// Martingale strategy driven by stochastic oscillator crossovers.
/// Buy when K crosses above D, sell when K crosses below D.
/// Doubles down on adverse moves with martingale averaging.
/// </summary>
public class MartingailExpertSequenceStrategy : Strategy
{
	private readonly StrategyParam<int> _kPeriod;
	private readonly StrategyParam<int> _dPeriod;
	private readonly StrategyParam<decimal> _stepPoints;
	private readonly StrategyParam<decimal> _takeProfitPoints;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevK;
	private decimal? _prevD;
	private decimal _entryPrice;

	public int KPeriod { get => _kPeriod.Value; set => _kPeriod.Value = value; }
	public int DPeriod { get => _dPeriod.Value; set => _dPeriod.Value = value; }
	public decimal StepPoints { get => _stepPoints.Value; set => _stepPoints.Value = value; }
	public decimal TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MartingailExpertSequenceStrategy()
	{
		_kPeriod = Param(nameof(KPeriod), 14)
			.SetDisplay("K Period", "Stochastic K period", "Indicators");

		_dPeriod = Param(nameof(DPeriod), 3)
			.SetDisplay("D Period", "Stochastic D period", "Indicators");

		_stepPoints = Param(nameof(StepPoints), 500m)
			.SetDisplay("Step Points", "Distance for martingale averaging", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 200m)
			.SetDisplay("Take Profit", "Take profit in price steps", "Risk");

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

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

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

		_prevK = null;
		_prevD = null;
		_entryPrice = 0m;
	}

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

		_prevK = null;
		_prevD = null;

		var stoch = new StochasticOscillator
		{
			K = { Length = KPeriod },
			D = { Length = DPeriod }
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(stoch, ProcessCandle)
			.Start();
	}

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

		if (!stochValue.IsFinal)
			return;

		if (stochValue is not StochasticOscillatorValue stoch)
			return;

		if (stoch.K is not decimal k || stoch.D is not decimal d)
			return;

		var step = Security?.PriceStep ?? 1m;
		if (step <= 0) step = 1m;

		// Check take profit
		if (Position > 0 && candle.ClosePrice >= _entryPrice + TakeProfitPoints * step)
		{
			SellMarket();
			_prevK = k;
			_prevD = d;
			return;
		}
		else if (Position < 0 && candle.ClosePrice <= _entryPrice - TakeProfitPoints * step)
		{
			BuyMarket();
			_prevK = k;
			_prevD = d;
			return;
		}

		if (_prevK is not decimal prevK || _prevD is not decimal prevD)
		{
			_prevK = k;
			_prevD = d;
			return;
		}

		// Stochastic crossover signals
		var bullCross = prevK <= prevD && k > d;
		var bearCross = prevK >= prevD && k < d;

		if (Position == 0)
		{
			if (bullCross)
			{
				BuyMarket();
				_entryPrice = candle.ClosePrice;
			}
			else if (bearCross)
			{
				SellMarket();
				_entryPrice = candle.ClosePrice;
			}
		}
		else if (Position > 0 && bearCross)
		{
			SellMarket(); // Close long
			SellMarket(); // Open short
			_entryPrice = candle.ClosePrice;
		}
		else if (Position < 0 && bullCross)
		{
			BuyMarket(); // Close short
			BuyMarket(); // Open long
			_entryPrice = candle.ClosePrice;
		}

		_prevK = k;
		_prevD = d;
	}
}