La estrategia One Two Three negocia rupturas del oscilador Chaikin después de un período extendido de acumulación plana. Emula el experto original de MetaTrader 5 combinando una línea de acumulación/distribución con dos EMA, validando que la presión del mercado ha permanecido neutral durante varias barras, y luego entrando en una fuerte oleada de impulso Chaikin. El port de StockSharp mantiene el dimensionamiento de lotes, la gestión de stops y la lógica de trailing configurables a través de parámetros de estrategia.
Concepto
Construir el oscilador Chaikin como la diferencia entre una media móvil exponencial rápida y una lenta aplicada a la línea de acumulación/distribución derivada de las velas entrantes.
Rastrear las últimas BarsCount lecturas del oscilador y clasificar las barras donde el valor absoluto de Chaikin se mantiene dentro de FlatLevel.
Permitir el trading solo cuando más de FlatPercent por ciento de esas lecturas almacenadas se mantuvieron dentro del rango plano, señalando una acumulación tranquila.
Cuando se termina una nueva vela, entrar en la dirección del impulso Chaikin si su magnitud supera OpenLevel.
Reglas de entrada
Largo: El oscilador Chaikin en la vela recién cerrada es mayor o igual a OpenLevel y la posición neta actual es no positiva.
Corto: El oscilador Chaikin en la vela recién cerrada es menor o igual al OpenLevel negativo y la posición neta actual es no negativa.
Las órdenes se emiten al mercado. Si la estrategia mantiene una posición opuesta, el tamaño de la orden se incrementa para aplanar la exposición existente antes de establecer la nueva operación.
Reglas de salida
Un stop-loss fijo (StopLossPips) y take-profit (TakeProfitPips) se traducen en desplazamientos de precio usando el paso de precio del instrumento (1 pip = 1 paso de precio) y se aplican inmediatamente después de la entrada.
Un trailing stop opcional ajusta el stop protector una vez que el precio se mueve a favor de la operación al menos TrailingStopPips + TrailingStepPips. El nuevo stop se coloca exactamente TrailingStopPips alejado del cierre actual mientras se requiere el buffer de paso para evitar el ajuste prematuro.
Si el stop o el objetivo son tocados dentro del rango de la vela completada, la posición se cierra al mercado.
Gestión de riesgo y dinero
OrderVolume controla la cantidad enviada con cada orden de mercado. La estrategia suma o resta automáticamente el tamaño de posición actual al cambiar de dirección para que las reversiones ocurran en una sola operación.
Establecer cualquiera de los parámetros basados en pips a cero deshabilita ese componente (por ejemplo, un take-profit de cero mantiene las operaciones abiertas hasta que el stop o la señal opuesta ocurra).
Parámetros
OrderVolume – Volumen base para entradas.
StopLossPips – Distancia, en pips, entre el precio de entrada y el stop protector.
TakeProfitPips – Distancia, en pips, entre el precio de entrada y el objetivo de ganancia.
TrailingStopPips – Distancia, en pips, mantenida entre el precio y el trailing stop. Establecer a cero para deshabilitar el trailing.
TrailingStepPips – Ganancia mínima en pips más allá de la distancia de trailing requerida antes de que el stop se mueva nuevamente.
FastLength – Período de la EMA rápida en el oscilador Chaikin.
SlowLength – Período de la EMA lenta en el oscilador Chaikin.
FlatLevel – Valor absoluto de Chaikin que aún cuenta como comportamiento de mercado plano.
OpenLevel – Magnitud de Chaikin requerida para activar una nueva operación una vez que se satisface la condición plana.
BarsCount – Número de valores recientes de Chaikin a evaluar al calcular la ratio plana.
FlatPercent – Porcentaje mínimo de los valores almacenados que deben mantenerse dentro del rango plano para permitir el trading.
CandleType – Tipo de datos de vela o marco temporal que alimenta los cálculos del indicador.
Notas
La lógica de trailing refleja el experto de MetaTrader: si TrailingStopPips es distinto de cero, mantenga TrailingStepPips positivo para evitar un stop estancado.
Debido a que las estrategias de StockSharp trabajan con el paso de precio del instrumento, las distancias basadas en pips asumen que un pip equivale a un paso de precio; ajuste los valores del parámetro en consecuencia para instrumentos con diferentes tamaños de tick.
La estrategia procesa únicamente velas completadas y no intenta reaccionar dentro de la barra, coincidiendo con el experto original que ejecuta en nuevas aperturas 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()