Ver no GitHub

Stochastic Martingale Estratégia de grade

Visão geral

Esta estratégia é uma versão StockSharp do MetaTrader consultor especialista rmkp_9yj4qp1gn8fucubyqnvb. Ele combina um filtro de entrada de oscilador estocástico com uma grade de média estilo martingale. O algoritmo monitora as velas finalizadas, espera que a linha do sinal estocástico saia das zonas de sobrecompra ou sobrevenda predefinidas e, em seguida, abre uma posição na direção da reversão. Quando o preço se move contra a negociação, ele adiciona ordens médias com volume duplicado em distâncias fixas de pip. Cada perna carrega sua própria meta de lucro e gerenciamento de trailing stop, permitindo que as posições aumentem de forma independente assim que o preço se recuperar.

Lógica de negociação

  • Detecção de sinal:
    • As linhas %K e %D de um oscilador estocástico configurável são avaliadas em velas concluídas.
    • Uma configuração longa é acionada quando, na vela anterior, %K estava acima de %D e %D estava abaixo do limite ZoneBuy.
    • Uma configuração curta é acionada quando, na vela anterior, %K estava abaixo de %D e %D estava acima do limite ZoneSell.
  • Execução inicial:
    • Com um sinal válido e enquanto a conta estiver estável, a estratégia envia uma ordem de mercado com o BaseVolume.
    • O preço de entrada é armazenado para gerenciar os trailing stops e posteriormente calcular a média dos pedidos.
  • Martingale média:
    • Enquanto uma posição permanece aberta, o algoritmo observa o movimento adverso do preço de StepPips em relação à última ordem preenchida.
    • Cada nova ordem média duplica o volume da perna anterior (progressão martingale clássica) e só é colocada se o número total de pernas abertas for inferior a MaxOrders e a negociação continuar permitida.
  • Gerenciamento de saída:
    • Cada etapa define um nível de lucro individual localizado a TakeProfitPips de seu preço de entrada.
    • Os trailing stops são ativados quando o lucro não realizado atinge TrailingStopPips; a âncora final é apertada sempre que os lucros se estendem ainda mais.
    • Se o preço retornar ao nível final ou atingir o nível de take-profit, a perna correspondente será fechada enquanto o restante do cluster permanecerá ativo.
    • Quando todas as pernas saem, a estratégia redefine seu estado interno e aguarda o próximo sinal estocástico.

Gestão de risco

  • A expansão martingale é limitada por MaxOrders e pelos limites de volume de segurança.
  • Os volumes são normalizados para o VolumeStep do instrumento e as restrições de volume mínimo/máximo são respeitadas.
  • Os trailing stops ajudam a proteger os lucros flutuantes de reversões totais.

Parâmetros

Nome Descrição Padrão
CandleType Assinatura de velas usada para cálculos de indicadores. Período de 15 minutos
BaseVolume Volume de pedido inicial colocado no primeiro sinal. 0.1
TakeProfitPips Distância pip entre cada preço de entrada e sua meta de lucro. 50
TrailingStopPips Distância pip usada para ativação e rastreamento do trailing stop por perna. 20
MaxOrders Número máximo de trechos médios simultâneos (incluindo a entrada inicial). 7
StepPips Movimento adverso mínimo, em pips, necessário antes de adicionar outra ordem de média. 7
KPeriod Comprimento de lookback para a linha %K estocástica. 5
DPeriod Comprimento de suavização para a linha %D estocástica. 3
Slowing Suavização adicional aplicada ao cálculo de %K. 3
ZoneBuy Limite superior que permite configurações longas quando %K está acima de %D. 30
ZoneSell Limite inferior que permite configurações curtas quando %K está abaixo de %D. 70

Notas

  • A estratégia usa o StockSharp API de alto nível com assinaturas de velas e vinculações de indicadores, mantendo a implementação próxima da lógica MetaTrader original enquanto aproveita as ferramentas de risco e visualização de StockSharp.
  • Como a média das negociações dobra o volume, certifique-se de que o volume máximo permitido do instrumento possa acomodar a escada martingale.
  • Tal como acontece com qualquer sistema martingale, a gestão adequada do capital e restrições de risco adicionais são altamente recomendadas antes da implementação numa conta real.
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>
/// Stochastic based martingale averaging strategy translated from the MetaTrader expert "rmkp_9yj4qp1gn8fucubyqnvb".
/// Adds averaging orders when price moves against the latest entry and manages each leg with trailing stops and individual take profits.
/// </summary>
public class StochasticMartingaleGridStrategy : Strategy
{
	private sealed class Entry
	{
		public decimal Price { get; set; }
		public decimal Volume { get; set; }
		public decimal? TrailingPrice { get; set; }
	}

	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _baseVolume;
	private readonly StrategyParam<decimal> _takeProfitPips;
	private readonly StrategyParam<decimal> _trailingStopPips;
	private readonly StrategyParam<int> _maxOrders;
	private readonly StrategyParam<decimal> _stepPips;
	private readonly StrategyParam<int> _kPeriod;
	private readonly StrategyParam<int> _dPeriod;
	private readonly StrategyParam<int> _slowing;
	private readonly StrategyParam<decimal> _zoneBuy;
	private readonly StrategyParam<decimal> _zoneSell;

	private List<Entry> _entries;

	private StochasticOscillator _stochastic;
	private decimal? _previousMain;
	private decimal? _previousSignal;
	private decimal _pipSize;

	/// <summary>
	/// Initializes a new instance of the <see cref="StochasticMartingaleGridStrategy"/> class.
	/// </summary>
	public StochasticMartingaleGridStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe used to evaluate stochastic values", "General");

		_baseVolume = Param(nameof(BaseVolume), 0.1m)
			.SetGreaterThanZero()
			.SetDisplay("Base Volume", "Initial order volume", "Trading")
			;

		_takeProfitPips = Param(nameof(TakeProfitPips), 50m)
			.SetGreaterThanZero()
			.SetDisplay("Take Profit (pips)", "Distance to the take profit target for each entry", "Risk")
			;

		_trailingStopPips = Param(nameof(TrailingStopPips), 20m)
			.SetGreaterThanZero()
			.SetDisplay("Trailing Stop (pips)", "Trailing stop distance applied per entry", "Risk")
			;

		_maxOrders = Param(nameof(MaxOrders), 2)
			.SetGreaterThanZero()
			.SetDisplay("Max Orders", "Maximum number of simultaneous averaging entries", "Martingale");

		_stepPips = Param(nameof(StepPips), 7m)
			.SetGreaterThanZero()
			.SetDisplay("Step (pips)", "Adverse move required before adding a new entry", "Martingale")
			;

		_kPeriod = Param(nameof(KPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("%K Period", "Stochastic %K lookback length", "Indicators")
			;

		_dPeriod = Param(nameof(DPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("%D Period", "Stochastic %D smoothing length", "Indicators")
			;

		_slowing = Param(nameof(Slowing), 3)
			.SetGreaterThanZero()
			.SetDisplay("Slowing", "Additional smoothing applied to %K", "Indicators")
			;

		_zoneBuy = Param(nameof(ZoneBuy), 50m)
			.SetDisplay("Buy Zone", "Upper limit that allows long setups when %K is above %D", "Indicators")
			;

		_zoneSell = Param(nameof(ZoneSell), 50m)
			.SetDisplay("Sell Zone", "Lower limit that allows short setups when %K is below %D", "Indicators")
			;
	}

	/// <summary>
	/// Candle type used for indicator calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initial trade volume.
	/// </summary>
	public decimal BaseVolume
	{
		get => _baseVolume.Value;
		set => _baseVolume.Value = value;
	}

	/// <summary>
	/// Take profit distance in pips applied to every entry.
	/// </summary>
	public decimal TakeProfitPips
	{
		get => _takeProfitPips.Value;
		set => _takeProfitPips.Value = value;
	}

	/// <summary>
	/// Trailing stop distance in pips applied to every entry.
	/// </summary>
	public decimal TrailingStopPips
	{
		get => _trailingStopPips.Value;
		set => _trailingStopPips.Value = value;
	}

	/// <summary>
	/// Maximum number of averaging entries.
	/// </summary>
	public int MaxOrders
	{
		get => _maxOrders.Value;
		set => _maxOrders.Value = value;
	}

	/// <summary>
	/// Step in pips required to trigger a new averaging entry.
	/// </summary>
	public decimal StepPips
	{
		get => _stepPips.Value;
		set => _stepPips.Value = value;
	}

	/// <summary>
	/// Stochastic %K period.
	/// </summary>
	public int KPeriod
	{
		get => _kPeriod.Value;
		set => _kPeriod.Value = value;
	}

	/// <summary>
	/// Stochastic %D period.
	/// </summary>
	public int DPeriod
	{
		get => _dPeriod.Value;
		set => _dPeriod.Value = value;
	}

	/// <summary>
	/// Stochastic slowing period.
	/// </summary>
	public int Slowing
	{
		get => _slowing.Value;
		set => _slowing.Value = value;
	}

	/// <summary>
	/// Maximum signal level that allows long entries.
	/// </summary>
	public decimal ZoneBuy
	{
		get => _zoneBuy.Value;
		set => _zoneBuy.Value = value;
	}

	/// <summary>
	/// Minimum signal level that allows short entries.
	/// </summary>
	public decimal ZoneSell
	{
		get => _zoneSell.Value;
		set => _zoneSell.Value = value;
	}

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

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

		_entries = null;
		_stochastic = null;
		_previousMain = null;
		_previousSignal = null;
		_pipSize = 0m;
	}

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

		_entries = new List<Entry>();
		_pipSize = Security?.PriceStep ?? 1m;

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

		Indicators.Add(_stochastic);

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

		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(1, UnitTypes.Percent));

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

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

		var stochResult = _stochastic.Process(candle);
		if (!_stochastic.IsFormed)
			return;

		if (stochResult is not StochasticOscillatorValue stoch)
			return;

		if (stoch.K is not decimal currentMain || stoch.D is not decimal currentSignal)
			return;

		if (Position != 0)
		{
			_previousMain = currentMain;
			_previousSignal = currentSignal;
			return;
		}

		if (_previousMain is decimal prevMain && _previousSignal is decimal prevSignal)
		{
			// Buy: K crosses above D in oversold zone
			if (prevMain <= prevSignal && currentMain > currentSignal && currentSignal < ZoneBuy)
				BuyMarket();
			// Sell: K crosses below D in overbought zone
			else if (prevMain >= prevSignal && currentMain < currentSignal && currentSignal > ZoneSell)
				SellMarket();
		}

		_previousMain = currentMain;
		_previousSignal = currentSignal;
	}
}