LazyBot V1 é uma estratégia de breakout diária convertida do consultor especialista MetaTrader 5 original. Todos os dias de negociação, ele coloca um par de ordens de stop pendentes em torno da faixa de preço do dia anterior e usa um trailing stop para proteger as posições abertas. A conversão aproveita o StockSharp API de alto nível com assinaturas de velas e gerenciamento automático de pedidos.
Lógica de negociação
Aguarde a conclusão de uma vela do período configurado (diariamente por padrão).
Em um novo dia, opcionalmente, certifique-se de que o horário atual do servidor esteja dentro da janela de negociação permitida e pule os finais de semana.
Cancele quaisquer ordens pendentes de breakout existentes criadas pela estratégia.
Coloque um stop de compra acima da máxima do dia anterior e um stop de venda abaixo da mínima do dia anterior. O parâmetro Breakout Offset (pips) adiciona distância extra a ambos os níveis de ruptura.
Quando qualquer uma das ordens for acionada, mantenha o stop-loss de proteção a uma distância fixa e acompanhe-o sempre que o preço avançar a favor da negociação mais do que a distância configurada do pip.
Recalcule o volume para os próximos pedidos usando um tamanho de lote fixo ou o módulo de dimensionamento baseado em risco.
Parâmetros
Nome
Descrição
Tipo de vela
Prazo utilizado para coletar as velas de referência (diariamente por padrão).
Nome do bot
Valor escrito nos comentários do pedido para facilitar o rastreamento.
Stop Loss (pips)
Distância usada para o stop inicial e final.
Deslocamento de ruptura (pips)
Distância extra aplicada à máxima/mínima anterior ao colocar as ordens pendentes.
Spread máximo (pips)
Spread máximo permitido antes de criar novas ordens de breakout. Defina como 0 para desativar a verificação.
Use o horário de negociação
Ativa o filtro de hora de início semelhante ao EA original.
Hora de início
Primeira hora (inclusive) em que novos pedidos poderão ser feitos.
Hora final
Hora em que novos pedidos deixam de ser agendados. Quando igual à hora de início, o filtro atua como um limite inferior simples.
% de risco de uso
Permite cálculo de volume baseado em risco.
% de risco
Porcentagem do patrimônio do portfólio usado para dimensionar posições quando Use Risk % está ativado.
Volume Fixo
Volume de ordem fixo usado quando o dimensionamento de risco está desabilitado. Quando zero, a estratégia volta para a propriedade global Volume (o padrão é 0,01).
Gestão de risco
O trailing stop reflete a lógica de trailing MetaTrader, mantendo o stop loss Stop Loss (pips) longe do melhor bid/ask e apenas apertando quando um preço melhor é alcançado.
O filtro de spread protege a estratégia de enviar novas ordens de breakout quando o mercado estiver muito amplo.
O dimensionamento baseado em risco divide o risco monetário permitido (equity * Risk %) pela distância de stop expressa em unidades de preço e nunca fica abaixo do tamanho de lote fixo.
Notas adicionais
Os comentários dos pedidos seguem o formato BotName;SymbolId;YYYYMMDD, o que facilita a distinção dos pedidos pendentes criados em dias diferentes.
A estratégia assina os dados do Nível 1 para avaliar o spread atual do filtro e rastrear stops com os últimos valores de compra/venda.
Os trailing stops são reaplicados em cada atualização de vela e imediatamente após os preenchimentos para corresponder ao comportamento original EA.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "LazyBot V1" MetaTrader expert.
/// Daily breakout strategy using previous N-bar high/low range.
/// Buys when price breaks above previous high, sells when below previous low.
/// </summary>
public class LazyBotV1Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _lookback;
private readonly Queue<decimal> _highs = new();
private readonly Queue<decimal> _lows = new();
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int Lookback
{
get => _lookback.Value;
set => _lookback.Value = value;
}
public LazyBotV1Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for breakout detection", "General");
_lookback = Param(nameof(Lookback), 30)
.SetGreaterThanZero()
.SetDisplay("Lookback", "Number of bars for high/low range", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highs.Clear();
_lows.Clear();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// Build range from previous bars (not including current)
if (_highs.Count >= Lookback)
{
var highs = _highs.ToArray();
var lows = _lows.ToArray();
decimal highest = decimal.MinValue;
decimal lowest = decimal.MaxValue;
foreach (var h in highs)
if (h > highest) highest = h;
foreach (var l in lows)
if (l < lowest) lowest = l;
var close = candle.ClosePrice;
var volume = Volume;
if (volume <= 0)
volume = 1;
var padding = (highest - lowest) * 0.05m;
if (close > highest + padding)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (close < lowest - padding)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
}
_highs.Enqueue(candle.HighPrice);
_lows.Enqueue(candle.LowPrice);
if (_highs.Count > Lookback)
{
_highs.Dequeue();
_lows.Dequeue();
}
}
/// <inheritdoc />
protected override void OnReseted()
{
_highs.Clear();
_lows.Clear();
base.OnReseted();
}
}
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
class lazy_bot_v1_strategy(Strategy):
def __init__(self):
super(lazy_bot_v1_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._lookback = self.Param("Lookback", 30)
self._highs = []
self._lows = []
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def Lookback(self):
return self._lookback.Value
@Lookback.setter
def Lookback(self, value):
self._lookback.Value = value
def OnReseted(self):
super(lazy_bot_v1_strategy, self).OnReseted()
self._highs = []
self._lows = []
def OnStarted2(self, time):
super(lazy_bot_v1_strategy, self).OnStarted2(time)
self._highs = []
self._lows = []
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
lookback = self.Lookback
if len(self._highs) >= lookback:
highest = max(self._highs)
lowest = min(self._lows)
close = float(candle.ClosePrice)
padding = (highest - lowest) * 0.05
if close > highest + padding:
if self.Position <= 0:
self.BuyMarket()
elif close < lowest - padding:
if self.Position >= 0:
self.SellMarket()
self._highs.append(float(candle.HighPrice))
self._lows.append(float(candle.LowPrice))
while len(self._highs) > lookback:
self._highs.pop(0)
self._lows.pop(0)
def CreateClone(self):
return lazy_bot_v1_strategy()