Esta estrategia es una adaptación directa del MetaTrader asesor experto ichimok2005 diseñado para la API de alto nivel de StockSharp. Se centra en identificar rupturas decisivas por encima o por debajo de la línea Ichimoku Senkou Span B y confirma el impulso a través de cuerpos de velas consecutivos.
Lógica de trading
Configuración larga
Evalúe las últimas Shift + 2 velas completadas (el Shift predeterminado es 1, por lo que el algoritmo observa las tres barras anteriores).
Requerir que:
La vela de referencia más antigua (Shift + 2) se abrió debajo de Senkou Span B.
La vela de referencia intermedia (Shift + 1) se abrió por encima de Senkou Span B y cerró por encima de ella.
La vela de referencia más reciente (Shift) se abrió y cerró por encima de Senkou Span B.
Las dos últimas velas de referencia son alcistas (el precio de cierre es mayor que el precio de apertura).
Asegúrese de que Ichimoku Chinkou Span no quede atrapado dentro de la nube cuando Senkou Span A esté por debajo de Senkou Span B. Esto imita el filtro de asesor experto original que evita fases de mercado congestionadas.
Si la estrategia actualmente tiene una posición corta, se cierra. De lo contrario, se abre una nueva operación larga, siempre que la señal anterior no fuera ya larga.
Configuración corta
Refleje las condiciones largas en la dirección opuesta:
La vela Shift + 2 debe abrirse sobre Senkou Span B.
La vela Shift + 1 debe abrirse y cerrarse debajo de Senkou Span B.
La vela Shift debe abrirse y cerrarse debajo de Senkou Span B.
Las dos últimas velas de referencia son bajistas (el precio de cierre es menor que el precio de apertura).
El Chinkou Span debe permanecer fuera de la nube cuando el Senkou Span A está por debajo del Senkou Span B.
Cierre cualquier posición larga existente y luego abra una nueva posición corta si la señal anterior no era corta.
Las posiciones se gestionan con las órdenes de protección de StockSharp. Stop Loss y Take Profit se miden en pasos de precio y se convierten a distancias absolutas utilizando el PriceStep del instrumento. Las órdenes de protección se registran con salidas de mercado para replicar el comportamiento MetaTrader de utilizar paradas de mercado.
Dimensionamiento de posiciones
El asesor original admitía dos modos de tamaño:
Volumen fijo (UseMoneyManagement = false): las operaciones se ejecutan con el parámetro OrderVolume (por defecto 0,1 lotes).
Gestión de dinero (UseMoneyManagement = true): la estrategia utiliza el valor actual de la cartera y el porcentaje MaximumRisk para derivar el tamaño del pedido. El resultado se ajusta al paso del lote del valor y nunca cae por debajo de un solo paso.
Parámetros
Parámetro
Descripción
Predeterminado
StopLossPoints
Distancia de stop-loss en pasos de precio.
30
TakeProfitPoints
Distancia de obtención de beneficios en pasos de precio.
60
Shift
Número de barras utilizadas como compensación al validar la estructura de ruptura.
1
OrderVolume
Tamaño de operación fijo cuando la administración del dinero está deshabilitada.
0.1
MaximumRisk
Porcentaje de cartera utilizado para dimensionar los pedidos cuando la administración del dinero está habilitada.
10
UseMoneyManagement
Permite dimensionar las posiciones en función del riesgo.
falso
TenkanPeriod
Período tenkan-sen del indicador Ichimoku.
9
KijunPeriod
Período Kijun-sen del indicador Ichimoku.
26
SenkouBPeriod
Período Senkou Span B del indicador Ichimoku.
52
CandleType
Marco de tiempo para todos los cálculos (el valor predeterminado es velas por hora).
1 hora
Notas
Sólo se procesan velas completadas, garantizando que los valores Ichimoku sean definitivos.
La estrategia realiza un seguimiento de la última dirección ejecutada (_lastSignal) para evitar repetir órdenes idénticas en señales consecutivas, coincidiendo con el comportamiento experto MetaTrader.
Si el instrumento no publica PriceStep, las distancias de stop-loss y take-profit se tratan como valores de precio absoluto.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Ichimoku2005Strategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevMid;
private bool _hasPrev;
private int _cooldownRemaining;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Ichimoku2005Strategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 52).SetDisplay("Channel Period", "Channel lookback", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 150).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = default;
_prevMid = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0;
_prevMid = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
var mid = (highest + lowest) / 2;
if (!_hasPrev) { _prevClose = close; _prevMid = mid; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevClose = close;
_prevMid = mid;
return;
}
if (_prevClose <= _prevMid && close > mid && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevClose >= _prevMid && close < mid && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevClose = close;
_prevMid = mid;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class ichimoku_2005_strategy(Strategy):
def __init__(self):
super(ichimoku_2005_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 52) \
.SetDisplay("Channel Period", "Channel lookback", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 150) \
.SetDisplay("Cooldown", "Candles between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
self._cooldown_remaining = 0
@property
def channel_period(self):
return self._channel_period.Value
@property
def cooldown_candles(self):
return self._cooldown_candles.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ichimoku_2005_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(ichimoku_2005_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
self._cooldown_remaining = 0
highest = Highest()
highest.Length = self.channel_period
lowest = Lowest()
lowest.Length = self.channel_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, self.process_candle).Start()
def process_candle(self, candle, highest, lowest):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
mid = (float(highest) + float(lowest)) / 2.0
if not self._has_prev:
self._prev_close = close
self._prev_mid = mid
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_close = close
self._prev_mid = mid
return
if self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_candles
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_candles
self._prev_close = close
self._prev_mid = mid
def CreateClone(self):
return ichimoku_2005_strategy()