Sombras de Candle V1 é uma estratégia de reversão de ação do preço que recria a lógica original do consultor especialista MetaTrader dentro da API de alto nível do StockSharp. O sistema procura candles com um pavio dominante forte e sombra oposta mínima durante uma sessão de trading configurável. Os trades só são permitidos durante os primeiros minutos de uma barra, emulando a execução intrabar da versão MQL enquanto ainda trabalha em candles fechados.
Lógica de trading
Assinar os candles do período configurado (padrão 5 minutos) e avaliar apenas as barras finalizadas.
Aplicar uma janela de sessão usando os parâmetros StartHour e EndHour. Se o candle abrir fora da janela, nenhum trade é considerado.
Permitir entradas somente se o candle fechar antes de OpenWithinMinutes desde o horário de abertura, prevenindo sinais tardios em barras longas.
Setup comprado: o candle deve imprimir uma sombra inferior maior que CandleSizeMinPips pips e a sombra superior deve permanecer dentro de OppositeShadowMaxPips pips. Quando as condições são satisfeitas e não há posição aberta, uma compra de mercado é enviada.
Setup vendido: o candle deve imprimir uma sombra superior maior que CandleSizeMinPips pips e a sombra inferior deve permanecer dentro de OppositeShadowMaxPips pips. Uma venda de mercado é emitida se a conta estiver flat.
Apenas um trade por candle é permitido, correspondendo à restrição original de "uma ordem por barra".
Gestão de posição
As distâncias protetoras iniciais são expressas em pips e convertidas através do parâmetro PipValue para cada instrumento.
Verificações duras de stop-loss e take-profit são realizadas em cada candle concluído. Se o máximo/mínimo do candle tocar o limiar, a posição é zerada.
O gerenciamento de trailing imita o trailing stop do MQL: uma vez que o preço avança pelo menos TrailingStopPips + TrailingStepPips, o stop é movido em incrementos de TrailingStepPips pips.
Se uma posição permanecer aberta por mais de PositionLivesBars barras, ela é fechada imediatamente. Trades lucrativos também são forçados a sair após CloseProfitsOnBar barras para garantir ganhos.
O volume do próximo trade é reduzido dividindo BaseVolume por LossReductionFactor sempre que o trade anterior fechou com perda, assim como a redução de lotes no consultor especialista original.
Parâmetros
Nome
Descrição
Padrão
PipValue
Valor monetário de um pip usado para transformar distâncias em pips em deslocamentos de preço.
0.0001
StopLossPips
Distância de stop-loss em pips. Definir como 0 para desabilitar o stop duro.
50
TakeProfitPips
Distância de take-profit em pips. Definir como 0 para desabilitar o alvo duro.
50
TrailingStopPips
Distância do trailing stop em pips. Quando 0, nenhum trailing é aplicado.
15
TrailingStepPips
Passo mínimo em pips entre ajustes do trailing stop. Deve ser positivo quando o trailing está habilitado.
5
PositionLivesBars
Número máximo de barras completadas que uma posição pode permanecer aberta antes de ser forçada a fechar.
4
CloseProfitsOnBar
Quando maior que zero, posições lucrativas são fechadas após este número de barras desde a entrada.
2
OpenWithinMinutes
Quantidade máxima de minutos após a abertura da barra quando novos trades são permitidos.
7
CandleSizeMinPips
Comprimento de pavio necessário (em pips) no lado dominante do candle.
15
OppositeShadowMaxPips
Tamanho máximo (em pips) da sombra do candle oposta.
1
StartHour
Hora de início da sessão em horário da bolsa (0–23).
6
EndHour
Hora de fim da sessão em horário da bolsa (0–23).
18
LossReductionFactor
Divisor aplicado a BaseVolume após um trade perdedor.
1.5
BaseVolume
Tamanho padrão de ordem de mercado usado para entradas.
1
CandleType
Série de candles usada para os cálculos. O padrão é um período de 5 minutos.
5 min
Notas
Sempre ajustar PipValue para corresponder ao tamanho do tick do instrumento (por exemplo 0.01 para cruzamentos JPY ou 1 para futuros de índice).
Como a estratégia trabalha com candles completados, as execuções ocorrerão no fechamento da barra. Períodos menores (1–5 minutos) replicam melhor o comportamento intrabar do consultor especialista original.
Nenhum indicador externo é necessário, tornando a estratégia fácil de executar em qualquer fonte de dados StockSharp.
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>
/// Candle Shadows V1 strategy (simplified). Detects candles with long shadows
/// (wicks) relative to body as reversal signals, filtered by EMA trend.
/// </summary>
public class CandleShadowsV1Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<decimal> _shadowRatio;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public decimal ShadowRatio
{
get => _shadowRatio.Value;
set => _shadowRatio.Value = value;
}
public CandleShadowsV1Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_emaLength = Param(nameof(EmaLength), 30)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "Trend EMA period", "Indicators");
_shadowRatio = Param(nameof(ShadowRatio), 3m)
.SetDisplay("Shadow Ratio", "Min shadow/body ratio", "Logic");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, (ICandleMessage candle, decimal emaValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var open = candle.OpenPrice;
var high = candle.HighPrice;
var low = candle.LowPrice;
var body = Math.Abs(close - open);
if (body <= 0) return;
var upperShadow = high - Math.Max(close, open);
var lowerShadow = Math.Min(close, open) - low;
// Long lower shadow (hammer) near EMA => buy signal
if (lowerShadow > body * ShadowRatio && close > emaValue && Position <= 0)
BuyMarket();
// Long upper shadow (shooting star) near EMA => sell signal
else if (upperShadow > body * ShadowRatio && close < emaValue && Position >= 0)
SellMarket();
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class candle_shadows_v1_strategy(Strategy):
def __init__(self):
super(candle_shadows_v1_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._ema_length = self.Param("EmaLength", 30) \
.SetDisplay("EMA Length", "Trend EMA period", "Indicators")
self._shadow_ratio = self.Param("ShadowRatio", 3.0) \
.SetDisplay("Shadow Ratio", "Min shadow/body ratio", "Logic")
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def ShadowRatio(self):
return self._shadow_ratio.Value
def OnStarted2(self, time):
super(candle_shadows_v1_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
ev = float(ema_value)
body = abs(close - open_p)
if body <= 0:
return
upper_shadow = high - max(close, open_p)
lower_shadow = min(close, open_p) - low
if lower_shadow > body * self.ShadowRatio and close > ev and self.Position <= 0:
self.BuyMarket()
elif upper_shadow > body * self.ShadowRatio and close < ev and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return candle_shadows_v1_strategy()