Ver no GitHub

Estratégia simples de nuvem personalizada WPR

Visão geral

A WPR Custom Cloud Simple Strategy é uma versão StockSharp do MetaTrader consultor especialista WPR Custom Cloud Simple.mq5. O EA monitora o oscilador %R de Larry Williams e abre negociações quando o indicador sai do território de sobrevenda ou sobrecompra. Esta versão C# mantém o design original de negociação apenas em novas velas, revertendo a posição quando um sinal oposto aparece e evita quaisquer ordens de stop-loss ou take-profit exatamente como a implementação de referência.

Lógica de negociação

  1. Assine o período configurado (CandleType) e alimente um indicador WilliamsR com as velas recebidas.
  2. Espere até que a vela acabe; a estratégia nunca atua em barras incompletas.
  3. Armazene os dois últimos valores %R concluídos. Eles espelham as leituras wpr[1] e wpr[2] de MetaTrader.
  4. Gere sinais em cruzamentos:
    • Configuração longa: a barra anterior fecha acima de OversoldLevel enquanto a barra anterior estava abaixo do nível. Isso recria a condição de "saída de sobrevenda" (wpr[2] < level e wpr[1] > level) do EA.
    • Configuração curta: a barra anterior fecha abaixo de OverboughtLevel enquanto a barra anterior estava acima dela, correspondendo à verificação original wpr[2] > level e wpr[1] < level.
  5. Quando uma configuração longa aparecer, nivele qualquer exposição curta e compre um volume líquido. Quando uma configuração curta for acionada, alise o lado comprado e venda um volume líquido. Como StockSharp funciona com posições líquidas, enviar BuyMarket/SellMarket com Volume + |Position| replica perfeitamente o fluxo de fechamento e reversão da conta de hedge de MetaTrader.
  6. Nenhuma saída adicional é usada; um novo cruzamento oposto é a única maneira de fechar negociações, assim como no consultor original.

Parâmetros

Nome Tipo Padrão MetaTrader contraparte Descrição
WprPeriod int 14 Inp_WPR_Period Comprimento de lookback para o cálculo de Williams %R.
OverboughtLevel decimal -20 Inp_WPR_Level1 Limite que define o território de sobrecompra. Cruzar abaixo desencadeia shorts.
OversoldLevel decimal -80 Inp_WPR_Level2 Limite que define o território de sobrevenda. Cruzar acima desencadeia compras.
CandleType DataType Período de 1 hora InpWorkingPeriod Série de velas usada para atualizar o indicador e avaliar sinais.
Volume decimal Volume base da estratégia InpLots Tamanho do lote para ordens de mercado. A estratégia compensa automaticamente a posição líquida atual antes de abrir uma nova negociação.

Diferenças do original EA

  • StockSharp opera com posições líquidas. O fechamento da exposição oposta é feito aumentando o volume de ordens de mercado, de forma que o comportamento corresponda ao modelo de hedge sem estruturas contábeis extras como STRUCT_POSITION.
  • Todas as classes auxiliares de gerenciamento de pedidos (CTrade, CPositionInfo, verificações de margem, etc.) são substituídas pelos controles de risco integrados do StockSharp. A estratégia depende de Strategy.Volume e dos metadados da exchange em vez de cálculos manuais de margem livre.
  • O registro é simplificado. A versão StockSharp evita instruções Print detalhadas porque o API de alto nível já fornece atualizações de status do pedido.
  • As ordens de proteção são omitidas intencionalmente para refletir o design de "fechamento no sinal oposto" da fonte EA.

Dicas de uso

  • Ajuste CandleType para o mesmo período de tempo usado em MetaTrader para manter a frequência de cruzamento comparável.
  • Williams %R limites são valores negativos. Mover OverboughtLevel para mais perto de zero torna as entradas curtas mais raras, enquanto empurrar OversoldLevel em direção a -100 torna as entradas longas mais raras.
  • A estratégia assume que Volume já está alinhado com o passo mínimo e as regras de compensação do corretor. Ajuste o volume base na interface do usuário ou por meio de código antes de iniciar a negociação ao vivo.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Williams %R cloud breakout strategy converted from the MetaTrader expert advisor.
/// Looks for %R crossings above -80 to go long and below -20 to go short.
/// Positions are reversed when an opposite signal appears.
/// </summary>
public class WprCustomCloudSimpleStrategy : Strategy
{
	private readonly StrategyParam<int> _wprPeriod;
	private readonly StrategyParam<decimal> _overboughtLevel;
	private readonly StrategyParam<decimal> _oversoldLevel;
	private readonly StrategyParam<DataType> _candleType;

	private WilliamsR _williamsR;
	private decimal? _previousWpr;
	private decimal? _olderWpr;

	public int WprPeriod
	{
		get => _wprPeriod.Value;
		set => _wprPeriod.Value = value;
	}

	public decimal OverboughtLevel
	{
		get => _overboughtLevel.Value;
		set => _overboughtLevel.Value = value;
	}

	public decimal OversoldLevel
	{
		get => _oversoldLevel.Value;
		set => _oversoldLevel.Value = value;
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public WprCustomCloudSimpleStrategy()
	{
		_wprPeriod = Param(nameof(WprPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("WPR Period", "Williams %R lookback length", "Williams %R");

		_overboughtLevel = Param(nameof(OverboughtLevel), -10m)
			.SetDisplay("Overbought Level", "%R level that marks overbought conditions", "Williams %R");

		_oversoldLevel = Param(nameof(OversoldLevel), -90m)
			.SetDisplay("Oversold Level", "%R level that marks oversold conditions", "Williams %R");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe used for Williams %R", "Data");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_williamsR = new WilliamsR { Length = WprPeriod };
		_previousWpr = null;
		_olderWpr = null;

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

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

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

		if (!_williamsR.IsFormed)
		{
			_olderWpr = _previousWpr;
			_previousWpr = wprValue;
			return;
		}

		if (_previousWpr is not null && _olderWpr is not null)
		{
			var prev = _previousWpr.Value;
			var prevPrev = _olderWpr.Value;

			var crossedAboveOversold = prevPrev < OversoldLevel && prev > OversoldLevel;
			var crossedBelowOverbought = prevPrev > OverboughtLevel && prev < OverboughtLevel;

			var volume = Volume;
			if (volume <= 0)
				volume = 1;

			if (crossedAboveOversold)
			{
				if (Position <= 0)
					BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
			}
			else if (crossedBelowOverbought)
			{
				if (Position >= 0)
					SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
			}
		}

		_olderWpr = _previousWpr;
		_previousWpr = wprValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_williamsR = null;
		_previousWpr = null;
		_olderWpr = null;

		base.OnReseted();
	}
}