AIS2 Trading Robot 20005 é um consultor especialista em breakout intradiário originalmente escrito para MetaTrader 4. A porta recria sua lógica multi-timeframe sobre a estratégia de alto nível de StockSharp API. A estratégia espera por rompimentos de impulso acima/abaixo do ponto médio da vela de período de tempo superior anterior, aplica distâncias dinâmicas de take-profit e stop-loss derivadas do intervalo dessa vela e gerencia posições com um período de tempo secundário e mais rápido que impulsiona um trailing stop.
A conversão centra-se na transparência e no controlo manual: as posições são abertas com ordens de mercado, os níveis de proteção são aplicados dentro da própria estratégia e uma pausa de negociação configurável evita reentradas rápidas. O dimensionamento da posição com base em ações reflete a lógica original de “reserva”, permitindo aos usuários alocar uma fração do valor do portfólio para cada negociação, mantendo um buffer de capital intacto.
Lógica principal
Análise do timeframe primário – Em cada vela finalizada do timeframe principal (padrão 15 minutos) a estratégia calcula:
Ponto médio da vela (High + Low) / 2.
Distâncias de take-profit e stop-loss baseadas em intervalo (range * TakeFactor e range * StopFactor).
Aproximação do spread atual, buffers de parada/congelamento e um passo final mínimo.
Condições de rompimento – As entradas longas exigem um fechamento acima do ponto médio e o preço de venda atual rompendo a máxima anterior mais o spread. Os shorts refletem a condição dos mínimos. As ordens serão bloqueadas se as distâncias de parada/alvo calculadas falharem nas restrições de nível do corretor.
Gerenciamento de risco – O tamanho da posição é derivado do patrimônio do portfólio: OrderReserve define a fração negociável, enquanto AccountReserve mantém uma parte intocada. Se o capital disponível ou os limites do corretor não permitirem a negociação, a configuração será ignorada.
Gerenciamento comercial – O período de tempo mais rápido (padrão 1 minuto) atualiza continuamente a distância final. À medida que o preço avança, o stop migra a favor da negociação, uma vez que a faixa secundária o justifique. Atingir a meta ou o stop resulta em uma saída imediata do mercado.
Proteções operacionais – Um temporizador de resfriamento (TradingPauseSeconds) replica a pausa de negociação MQL original. A estratégia também assina a carteira de pedidos para capturar valores de compra/venda em tempo real; quando indisponível, ele volta para o fechamento da vela.
Parâmetros
Parâmetro
Descrição
Padrão
PrimaryCandleType
Prazo maior usado para gerar sinais de entrada.
Velas de 15 minutos
SecondaryCandleType
Prazo menor para cálculos de trailing stop.
Velas de 1 minuto
TakeFactor
Multiplicador aplicado ao intervalo da vela primária para construir a distância de lucro.
1.7
StopFactor
Multiplicador aplicado ao intervalo da vela primária para construir a distância de stop-loss.
1.7
TrailFactor
Multiplicador aplicado ao intervalo secundário de velas para atualizações finais.
0,5
AccountReserve
Fração do patrimônio líquido mantida em reserva (não utilizada para negociação).
0,20
OrderReserve
Fração do patrimônio total alocado por negociação antes dos buffers.
0,04
BaseVolume
Volume de negociação de reserva quando o dimensionamento do risco não pode ser calculado.
1 lote
StopBufferTicks
Tiques extras adicionados às verificações de conformidade no nível de stop do corretor.
0
FreezeBufferTicks
Carrapatos extras evitando atualizações de paradas frequentes perto dos níveis de congelamento.
0
TrailStepMultiplier
Multiplicador aplicado ao spread ao validar etapas finais.
1
TradingPauseSeconds
Cooldown entre negociações consecutivas.
5 segundos
Todos os parâmetros numéricos expõem SetCanOptimize() (quando for significativo) para que possam participar de cenários de otimização StockSharp.
Notas de uso
Anexe a estratégia a um título e garanta que os dados do nível 1/da carteira de pedidos estejam disponíveis para detecção precisa de spread. Sem cotações ativas, a lógica ainda é executada usando fechamentos de velas, mas as validações de parada tornam-se conservadoras.
Defina PrimaryCandleType/SecondaryCandleType para intervalos de tempo existentes em seu feed de dados. A porta usa SubscribeCandles e vincula manipuladores por meio do API de alto nível de StockSharp.
O trailing stop é virtual (gerenciado internamente); nenhuma ordem de parada é enviada ao corretor. Se você precisar de paradas no servidor, estenda o código para registrar ordens de proteção após as entradas.
StartProtection() é chamado na partida para que o motor liquide posições inesperadas, se necessário.
Diferenças do original EA
A versão MetaTrader manipulou variáveis globais em todo o terminal; esta porta mantém os parâmetros dentro da estratégia e os expõe por meio de StrategyParam wrappers.
As modificações de ordem foram substituídas por saídas diretas do mercado porque StockSharp lida com a lógica stop/target dentro do próprio algoritmo.
Os cálculos de risco operam com base no patrimônio do portfólio fornecido por StockSharp em vez de consultas de saldo de conta do MT4.
Arquivos
CS/Ais2TradingRobot20005Strategy.cs – Implementação de estratégia usando StockSharp API de alto nível.
README.md – Descrição em inglês (este arquivo).
README_zh.md – tradução chinesa.
README_ru.md – Tradução russa.
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()