Ver no GitHub

Estratégia Diária She Kanskigor

Visão geral

She Kanskigor Daily Strategy é um sistema de breakout diário que reflete o consultor especialista MetaTrader original SHE_kanskigor.mq4. A estratégia avalia a direção da vela diária anterior e abre uma única posição de mercado dentro de uma janela de tempo estreita no início do novo dia de negociação. Ele monitora automaticamente a posição para fechá-la por uma distância configurável de take-profit ou stop-loss, expressa em etapas de preço do título.

Lógica de negociação

  1. Assine velas intradiárias (padrão: 1 minuto) e velas diárias para o título selecionado.
  2. Atualize a abertura e fechamento diário armazenado sempre que uma vela diária finalizada chegar.
  3. Em cada vela intradiária finalizada:
    • Redefina o sinalizador “negociado hoje” quando uma nova data do calendário começar.
    • Gerencie a posição ativa verificando se o preço de fechamento atinge os limites de stop loss ou take-profit.
    • Verifique se o horário atual está dentro da janela de negociação configurada (início padrão: 00h05, duração da janela: 5 minutos).
    • Se nenhuma posição foi aberta ainda hoje e uma vela diária anterior válida estiver disponível:
      • Opere comprado quando a abertura diária anterior for superior ao fechamento (vela de baixa).
      • Opere vendido quando a abertura diária anterior for inferior ao fechamento (vela de alta).
    • Ignore a negociação quando o dia anterior fechou inalterado.
  4. A estratégia executa saídas protetoras usando ordens de mercado assim que o preço de fechamento atinge os limites configurados.

Parâmetros

Nome Descrição Padrão
Volume Volume de pedidos usado para entradas. 0.1
Receba lucro Meta de lucro expressa em etapas de preço. Um valor de 0 desativa o destino. 35
Stop Loss Limite de perda expresso em etapas de preço. Um valor de 0 desativa a parada. 55
Hora de início Hora do dia (fuso horário de câmbio) em que a janela de entrada é iniciada. 00:05
Janela (min) Duração, em minutos, da janela de entrada. 5
Vela intradiária Tipo de dados Candle usado para processamento intradiário (padrão: velas de 1 minuto). TimeFrameCandleMessage(1m)

Notas

  • A estratégia permite apenas uma entrada por dia de negociação.
  • Os dados diários das velas devem estar disponíveis; caso contrário, a estratégia espera até que chegue uma vela completa.
  • As saídas protetoras operam sobre o preço de fechamento das velas intradiárias finalizadas.
  • O código usa StockSharp API de alto nível (SubscribeCandles com Bind) e segue os padrões de codificação do projeto (guias, comentários em inglês e metadados de parâmetros).
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>
/// Daily breakout strategy that opens a position during a short time window.
/// Uses the previous daily candle direction to decide whether to buy or sell.
/// Applies configurable take-profit and stop-loss levels expressed in price steps.
/// </summary>
public class SheKanskigorDailyStrategy : Strategy
{
	private readonly StrategyParam<TimeSpan> _startTime;
	private readonly StrategyParam<int> _tradeWindowMinutes;
	private readonly StrategyParam<decimal> _takeProfitSteps;
	private readonly StrategyParam<decimal> _stopLossSteps;
	private readonly StrategyParam<DataType> _intradayCandleType;

	private readonly DataType _dailyCandleType;

	private DateTime _currentDate;
	private bool _tradePlaced;
	private bool _dailyReady;
	private decimal _previousOpen;
	private decimal _previousClose;
	private decimal _entryPrice;

	/// <summary>
	/// Start time of the trading window.
	/// </summary>
	public TimeSpan StartTime
	{
		get => _startTime.Value;
		set => _startTime.Value = value;
	}

	/// <summary>
	/// Width of the trading window in minutes.
	/// </summary>
	public int TradeWindowMinutes
	{
		get => _tradeWindowMinutes.Value;
		set => _tradeWindowMinutes.Value = value;
	}

	/// <summary>
	/// Take-profit distance expressed in security price steps.
	/// </summary>
	public decimal TakeProfitSteps
	{
		get => _takeProfitSteps.Value;
		set => _takeProfitSteps.Value = value;
	}

	/// <summary>
	/// Stop-loss distance expressed in security price steps.
	/// </summary>
	public decimal StopLossSteps
	{
		get => _stopLossSteps.Value;
		set => _stopLossSteps.Value = value;
	}

	/// <summary>
	/// Intraday candle type used to evaluate the trading window.
	/// </summary>
	public DataType IntradayCandleType
	{
		get => _intradayCandleType.Value;
		set => _intradayCandleType.Value = value;
	}

	/// <summary>
	/// Initializes <see cref="SheKanskigorDailyStrategy"/>.
	/// </summary>
	public SheKanskigorDailyStrategy()
	{
		_takeProfitSteps = Param(nameof(TakeProfitSteps), 35m)
			.SetDisplay("Take Profit", "Profit target in steps", "Risk")
			;

		_stopLossSteps = Param(nameof(StopLossSteps), 55m)
			.SetDisplay("Stop Loss", "Loss limit in steps", "Risk")
			;

		_startTime = Param(nameof(StartTime), new TimeSpan(0, 5, 0))
			.SetDisplay("Start Time", "Time of day to evaluate entries", "Schedule");

		_tradeWindowMinutes = Param(nameof(TradeWindowMinutes), 5)
			.SetDisplay("Window (min)", "Trading window duration in minutes", "Schedule")
			;

		_intradayCandleType = Param(nameof(IntradayCandleType), TimeSpan.FromMinutes(1).TimeFrame())
			.SetDisplay("Intraday Candle", "Candle type for intraday checks", "Data");

		_dailyCandleType = TimeSpan.FromMinutes(5).TimeFrame();
	}

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

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

		_currentDate = default;
		_tradePlaced = false;
		_dailyReady = false;
		_previousOpen = 0m;
		_previousClose = 0m;
		_entryPrice = 0m;
	}

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

		var intraday = SubscribeCandles(IntradayCandleType);
		intraday.Bind(ProcessIntraday).Start();

		var daily = SubscribeCandles(_dailyCandleType);
		daily.Bind(ProcessDaily).Start();

		StartProtection(null, null);
	}

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

		// Store the direction of the last completed daily candle.
		_previousOpen = candle.OpenPrice;
		_previousClose = candle.ClosePrice;
		_dailyReady = true;
	}

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

		var openTime = candle.OpenTime;

		if (openTime.Date != _currentDate)
		{
			_currentDate = openTime.Date;
			_tradePlaced = false;
		}

		ManagePosition(candle.ClosePrice);

		var start = StartTime;
		var end = start.Add(TimeSpan.FromMinutes(TradeWindowMinutes));
		var currentTod = openTime.TimeOfDay;

		if (currentTod < start || currentTod > end)
			return;

		if (_tradePlaced)
			return;

		if (!_dailyReady)
			return;

		if (Position != 0)
		{
			_tradePlaced = true;
			return;
		}

		if (_previousOpen > _previousClose)
		{
			BuyMarket(Volume);
			_tradePlaced = true;
		}
		else if (_previousOpen < _previousClose)
		{
			SellMarket(Volume);
			_tradePlaced = true;
		}
		else
		{
			// Skip trading when the previous day closed unchanged.
			_tradePlaced = true;
		}
	}

	private void ManagePosition(decimal closePrice)
	{
		if (Position == 0)
			return;

		var step = Security?.PriceStep ?? 0m;
		if (step <= 0m || _entryPrice == 0m)
			return;

		if (Position > 0)
		{
			var target = _entryPrice + TakeProfitSteps * step;
			var stop = _entryPrice - StopLossSteps * step;

			if (TakeProfitSteps > 0m && closePrice >= target)
			{
				SellMarket(Position);
				return;
			}

			if (StopLossSteps > 0m && closePrice <= stop)
			{
				SellMarket(Position);
			}
		}
		else
		{
			var target = _entryPrice - TakeProfitSteps * step;
			var stop = _entryPrice + StopLossSteps * step;

			if (TakeProfitSteps > 0m && closePrice <= target)
			{
				BuyMarket(-Position);
				return;
			}

			if (StopLossSteps > 0m && closePrice >= stop)
			{
				BuyMarket(-Position);
			}
		}
	}

	/// <inheritdoc />
	protected override void OnOwnTradeReceived(MyTrade trade)
	{
		base.OnOwnTradeReceived(trade);

		if (trade.Order.Security != Security)
			return;

		// Track the latest fill price to evaluate protective exits.
		_entryPrice = trade.Trade.Price;
	}
}