A estratégia One Two Three negocia rompimentos do oscilador Chaikin após um período prolongado de acumulação plana. Ela emula o especialista original do MetaTrader 5 combinando uma linha de acumulação/distribuição com dois EMAs, validando que a pressão do mercado permaneceu neutra por várias barras, e depois entrando em uma forte onda de momentum Chaikin. O port do StockSharp mantém o dimensionamento de lotes, gerenciamento de stops e lógica de trailing configuráveis através de parâmetros de estratégia.
Conceito
Construir o oscilador Chaikin como a diferença entre uma média móvel exponencial rápida e uma lenta aplicada à linha de acumulação/distribuição derivada das velas recebidas.
Rastrear as últimas BarsCount leituras do oscilador e classificar as barras onde o valor absoluto de Chaikin permanece dentro de FlatLevel.
Permitir a negociação apenas quando mais de FlatPercent por cento dessas leituras armazenadas permaneceram dentro do intervalo plano, sinalizando uma acumulação tranquila.
Quando uma nova vela terminar, entrar na direção do impulso Chaikin se sua magnitude exceder OpenLevel.
Regras de entrada
Comprado: O oscilador Chaikin na vela recém-fechada é maior ou igual a OpenLevel e a posição líquida atual é não positiva.
Vendido: O oscilador Chaikin na vela recém-fechada é menor ou igual ao OpenLevel negativo e a posição líquida atual é não negativa.
As ordens são emitidas a mercado. Se a estratégia mantiver uma posição oposta, o tamanho da ordem é aumentado para neutralizar a exposição existente antes de estabelecer a nova negociação.
Regras de saída
Um stop-loss fixo (StopLossPips) e take-profit (TakeProfitPips) são traduzidos em offsets de preço usando o passo de preço do instrumento (1 pip = 1 passo de preço) e aplicados imediatamente após a entrada.
Um trailing stop opcional ajusta o stop de proteção assim que o preço se move a favor da negociação em pelo menos TrailingStopPips + TrailingStepPips. O novo stop é colocado exatamente TrailingStopPips do fechamento atual enquanto requer o buffer de passo para evitar o aperto prematuro.
Se o stop ou o alvo for tocado dentro do intervalo da vela completada, a posição é fechada a mercado.
Gestão de risco e dinheiro
OrderVolume controla a quantidade enviada com cada ordem de mercado. A estratégia adiciona ou subtrai automaticamente o tamanho da posição atual ao mudar de direção para que as reversões ocorram em uma única negociação.
Definir qualquer um dos parâmetros baseados em pips como zero desativa esse componente (por exemplo, um take-profit zero mantém as negociações abertas até que o stop ou o sinal oposto ocorra).
Parâmetros
OrderVolume – Volume base para entradas.
StopLossPips – Distância, em pips, entre o preço de entrada e o stop de proteção.
TakeProfitPips – Distância, em pips, entre o preço de entrada e o alvo de lucro.
TrailingStopPips – Distância, em pips, mantida entre o preço e o trailing stop. Definir como zero para desabilitar o trailing.
TrailingStepPips – Ganho mínimo em pips além da distância de trailing necessário antes que o stop seja movido novamente.
FastLength – Período do EMA rápido no oscilador Chaikin.
SlowLength – Período do EMA lento no oscilador Chaikin.
FlatLevel – Valor absoluto de Chaikin que ainda conta como comportamento de mercado plano.
OpenLevel – Magnitude de Chaikin necessária para acionar uma nova negociação assim que a condição plana for satisfeita.
BarsCount – Número de valores recentes de Chaikin a avaliar ao calcular a proporção plana.
FlatPercent – Porcentagem mínima dos valores armazenados que devem permanecer dentro do intervalo plano para permitir a negociação.
CandleType – Tipo de dados de vela ou período que alimenta os cálculos do indicador.
Notas
A lógica de trailing espelha o especialista do MetaTrader: se TrailingStopPips for diferente de zero, mantenha TrailingStepPips positivo para evitar um stop estagnado.
Como as estratégias do StockSharp trabalham com o passo de preço do instrumento, as distâncias baseadas em pips assumem que um pip equivale a um passo de preço; ajuste os valores do parâmetro de acordo para instrumentos com diferentes tamanhos de tick.
A estratégia processa apenas velas completadas e não tenta reagir dentro da barra, correspondendo ao especialista original que executa em novas aberturas de barra.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class OneTwoThreeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast, _prevSlow;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public OneTwoThreeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 5).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 13).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null; _prevSlow = null;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fast > slow;
_prevFast = fast; _prevSlow = slow;
if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
}
}
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 one_two_three_strategy(Strategy):
def __init__(self):
super(one_two_three_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 5) \
.SetDisplay("Fast EMA", "Fast period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 13) \
.SetDisplay("Slow EMA", "Slow period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(one_two_three_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(one_two_three_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return one_two_three_strategy()