AIS2 Trading Robot 20005 es un asesor experto en ruptura intradiaria escrito originalmente para MetaTrader 4. El puerto recrea su lógica de marcos de tiempo múltiples además de la estrategia de alto nivel de StockSharp API. La estrategia espera rupturas de impulso por encima o por debajo del punto medio de la vela de marco temporal superior anterior, aplica distancias dinámicas de toma de ganancias y stop-loss derivadas del rango de esa vela y administra posiciones con un marco temporal secundario más rápido que impulsa un stop dinámico.
La conversión se centra en la transparencia y el control manual: las posiciones se abren con órdenes de mercado, los niveles de protección se aplican dentro de la propia estrategia y una pausa comercial configurable evita reingresos rápidos. El tamaño de las posiciones basado en acciones refleja la lógica de "reserva" original, permitiendo a los usuarios asignar una fracción del valor de la cartera a cada operación manteniendo intacto un colchón de capital.
Lógica principal
Análisis del marco de tiempo principal – En cada vela finalizada del marco de tiempo principal (predeterminado 15 minutos), la estrategia calcula:
Punto medio de la vela (High + Low) / 2.
Distancias de obtención de beneficios y stop-loss basadas en rangos (range * TakeFactor y range * StopFactor).
Aproximación del diferencial actual, buffers de parada/congelación y un paso de seguimiento mínimo.
Condiciones de ruptura: las entradas largas requieren tanto un cierre por encima del punto medio como que el precio de venta actual rompa el máximo anterior más el diferencial. Los pantalones cortos reflejan la condición de los mínimos. Las órdenes se bloquean si las distancias de parada/objetivo calculadas no cumplen con las restricciones a nivel de corredor.
Gestión de riesgos: el tamaño de la posición se deriva del capital de la cartera: OrderReserve define la fracción negociable, mientras que AccountReserve mantiene una parte intacta. Si el capital disponible o los límites del corredor no permiten la operación, se omite la configuración.
Gestión comercial: el período de tiempo más rápido (predeterminado 1 minuto) actualiza continuamente la distancia de seguimiento. A medida que el precio avanza, el stop migra a favor de la operación una vez que el rango secundario lo justifica. Alcanzar el objetivo o el stop da como resultado una salida inmediata del mercado.
Barreras operativas: un temporizador de enfriamiento (TradingPauseSeconds) replica la pausa comercial MQL original. La estrategia también se suscribe al libro de órdenes para capturar valores de oferta/demanda en vivo; cuando no está disponible, vuelve a cerrar la vela.
Parámetros
Parámetro
Descripción
Predeterminado
PrimaryCandleType
Se utiliza un marco de tiempo más alto para generar señales de entrada.
velas de 15 minutos
SecondaryCandleType
Plazo más bajo para los cálculos del trailing stop.
velas de 1 minuto
TakeFactor
Multiplicador aplicado al rango de velas principal para construir una distancia de toma de ganancias.
1.7
StopFactor
Multiplicador aplicado al rango de vela principal para construir una distancia de stop-loss.
1.7
TrailFactor
Multiplicador aplicado al rango de velas secundarias para actualizaciones finales.
0,5
AccountReserve
Fracción del capital mantenido en reserva (no utilizado para negociar).
0,20
OrderReserve
Fracción del capital total asignado por operación antes de los colchones.
0,04
BaseVolume
Volumen de operaciones de respaldo cuando no se puede calcular el tamaño del riesgo.
1 lote
StopBufferTicks
Se agregaron ticks adicionales a las verificaciones de cumplimiento a nivel de parada del corredor.
0
FreezeBufferTicks
Marcas adicionales que evitan que las actualizaciones frecuentes se detengan cerca de los niveles de congelación.
0
TrailStepMultiplier
Multiplicador aplicado al diferencial al validar los pasos finales.
1
TradingPauseSeconds
Enfriamiento entre operaciones consecutivas.
5 segundos
Todos los parámetros numéricos exponen SetCanOptimize() (cuando sea significativo) para que puedan participar en StockSharp escenarios de optimización.
Notas de uso
Adjunte la estrategia a un valor y asegúrese de que los datos del libro de pedidos/Nivel 1 estén disponibles para una detección precisa del diferencial. Sin cotizaciones activas, la lógica aún se ejecuta mediante cierres de velas, pero las validaciones de parada se vuelven conservadoras.
Establece PrimaryCandleType/SecondaryCandleType en los períodos de tiempo que existen en tu feed de datos. El puerto utiliza SubscribeCandles y vincula los controladores a través del nivel alto de StockSharp API.
El trailing stop es virtual (gestionado internamente); no se envían órdenes de parada al corredor. Si necesita paradas del lado del servidor, extienda el código para registrar órdenes de protección después de las entradas.
StartProtection() se llama al arrancar para que el motor liquide posiciones inesperadas si es necesario.
Diferencias con el original EA
La versión MetaTrader manipuló variables globales en todo el terminal; este puerto mantiene los parámetros dentro de la estrategia y los expone a través de contenedores StrategyParam.
Las modificaciones de órdenes fueron reemplazadas por salidas directas del mercado porque StockSharp maneja la lógica de parada/objetivo dentro del propio algoritmo.
Los cálculos de riesgo operan sobre el capital de la cartera proporcionado por StockSharp en lugar de consultas de saldo de cuenta desde MT4.
Archivos
CS/Ais2TradingRobot20005Strategy.cs – Implementación de estrategia utilizando API de alto nivel de StockSharp.
README.md – Descripción en inglés (este archivo).
README_zh.md – Traducción al chino.
README_ru.md – traducción al ruso.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// AIS2 Trading Robot: range breakout strategy.
/// Enters on close above/below previous candle range midpoint,
/// uses ATR for trailing stop management.
/// </summary>
public class Ais2TradingRobot20005Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<decimal> _takeFactor;
private readonly StrategyParam<decimal> _stopFactor;
private decimal _prevHigh;
private decimal _prevLow;
private decimal _prevMid;
private decimal _entryPrice;
private decimal _stopPrice;
public Ais2TradingRobot20005Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
_takeFactor = Param(nameof(TakeFactor), 1.7m)
.SetDisplay("Take Factor", "ATR multiplier for take profit.", "Risk");
_stopFactor = Param(nameof(StopFactor), 1.0m)
.SetDisplay("Stop Factor", "ATR multiplier for stop loss.", "Risk");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
public decimal TakeFactor
{
get => _takeFactor.Value;
set => _takeFactor.Value = value;
}
public decimal StopFactor
{
get => _stopFactor.Value;
set => _stopFactor.Value = value;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = 0;
_prevLow = 0;
_prevMid = 0;
_entryPrice = 0;
_stopPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh = 0;
_prevLow = 0;
_prevMid = 0;
_entryPrice = 0;
_stopPrice = 0;
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevHigh == 0 || atrVal <= 0)
{
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
_prevMid = (candle.HighPrice + candle.LowPrice) / 2m;
return;
}
var close = candle.ClosePrice;
var takeDistance = atrVal * TakeFactor;
var stopDistance = atrVal * StopFactor;
// Manage open position
if (Position > 0)
{
// Take profit
if (close - _entryPrice >= takeDistance)
{
SellMarket();
_entryPrice = 0;
_stopPrice = 0;
}
// Stop loss
else if (_stopPrice > 0 && close <= _stopPrice)
{
SellMarket();
_entryPrice = 0;
_stopPrice = 0;
}
// Trail stop
else
{
var newStop = close - stopDistance;
if (newStop > _stopPrice)
_stopPrice = newStop;
}
}
else if (Position < 0)
{
if (_entryPrice - close >= takeDistance)
{
BuyMarket();
_entryPrice = 0;
_stopPrice = 0;
}
else if (_stopPrice > 0 && close >= _stopPrice)
{
BuyMarket();
_entryPrice = 0;
_stopPrice = 0;
}
else
{
var newStop = close + stopDistance;
if (newStop < _stopPrice || _stopPrice == 0)
_stopPrice = newStop;
}
}
// New entry: breakout above previous high with close above midpoint
if (Position == 0)
{
if (close > _prevHigh && close > _prevMid)
{
_entryPrice = close;
_stopPrice = close - stopDistance;
BuyMarket();
}
else if (close < _prevLow && close < _prevMid)
{
_entryPrice = close;
_stopPrice = close + stopDistance;
SellMarket();
}
}
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
_prevMid = (candle.HighPrice + candle.LowPrice) / 2m;
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import AverageTrueRange
class ais2_trading_robot20005_strategy(Strategy):
def __init__(self):
super(ais2_trading_robot20005_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period", "Indicators")
self._take_factor = self.Param("TakeFactor", 1.7) \
.SetDisplay("Take Factor", "ATR multiplier for take profit", "Risk")
self._stop_factor = self.Param("StopFactor", 1.0) \
.SetDisplay("Stop Factor", "ATR multiplier for stop loss", "Risk")
self._prev_high = 0.0
self._prev_low = 0.0
self._prev_mid = 0.0
self._entry_price = 0.0
self._stop_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def AtrLength(self):
return self._atr_length.Value
@property
def TakeFactor(self):
return self._take_factor.Value
@property
def StopFactor(self):
return self._stop_factor.Value
def OnStarted2(self, time):
super(ais2_trading_robot20005_strategy, self).OnStarted2(time)
self._prev_high = 0.0
self._prev_low = 0.0
self._prev_mid = 0.0
self._entry_price = 0.0
self._stop_price = 0.0
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, atr_val):
if candle.State != CandleStates.Finished:
return
av = float(atr_val)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
if self._prev_high == 0 or av <= 0:
self._prev_high = high
self._prev_low = low
self._prev_mid = (high + low) / 2.0
return
take_distance = av * float(self.TakeFactor)
stop_distance = av * float(self.StopFactor)
# Manage open position
if self.Position > 0:
if close - self._entry_price >= take_distance:
self.SellMarket()
self._entry_price = 0.0
self._stop_price = 0.0
elif self._stop_price > 0 and close <= self._stop_price:
self.SellMarket()
self._entry_price = 0.0
self._stop_price = 0.0
else:
new_stop = close - stop_distance
if new_stop > self._stop_price:
self._stop_price = new_stop
elif self.Position < 0:
if self._entry_price - close >= take_distance:
self.BuyMarket()
self._entry_price = 0.0
self._stop_price = 0.0
elif self._stop_price > 0 and close >= self._stop_price:
self.BuyMarket()
self._entry_price = 0.0
self._stop_price = 0.0
else:
new_stop = close + stop_distance
if new_stop < self._stop_price or self._stop_price == 0:
self._stop_price = new_stop
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_high = high
self._prev_low = low
self._prev_mid = (high + low) / 2.0
return
# New entry
if self.Position == 0:
if close > self._prev_high and close > self._prev_mid:
self._entry_price = close
self._stop_price = close - stop_distance
self.BuyMarket()
elif close < self._prev_low and close < self._prev_mid:
self._entry_price = close
self._stop_price = close + stop_distance
self.SellMarket()
self._prev_high = high
self._prev_low = low
self._prev_mid = (high + low) / 2.0
def OnReseted(self):
super(ais2_trading_robot20005_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._prev_mid = 0.0
self._entry_price = 0.0
self._stop_price = 0.0
def CreateClone(self):
return ais2_trading_robot20005_strategy()