Esta estratégia é uma versão StockSharp do consultor especialista MetaTrader 5 "Aleatoriamente" (MQL ID 39835). O bot original demonstra como um processo de decisão puramente aleatório se comporta quando é forçado a estar sempre no mercado. Cada barra completada desencadeia um lançamento de moeda que determina se a próxima ação é comprar ou vender. A versão StockSharp mantém a mesma ideia, mas a expressa com primitivas API de alto nível (SubscribeCandles, BuyMarket, SellMarket) e integra-se perfeitamente com Designer ou Runner.
A implementação evita intencionalmente take-profit, stop-loss ou trailing stops, espelhando o script de referência MQL. Serve, portanto, mais como um equipamento de teste ou um exemplo pedagógico do que como uma estratégia lucrativa.
Lógica de negociação
Assine a série de velas configurada (CandleType). O intervalo padrão é de 15 minutos para imitar o comportamento do MetaTrader "período de tempo atual".
Assim que uma vela terminar, verifique se uma negociação anterior deve ser fechada. Quando CloseBeforeReversal está ativado, a estratégia nivela a posição e aguarda a confirmação de que não resta nenhuma exposição antes de emitir a próxima ordem.
Gere uma direção aleatória usando um gerador de números pseudoaleatórios. O parâmetro opcional RandomSeed permite sequências determinísticas para backtests reproduzíveis.
Envie uma ordem de mercado usando o TradeVolume fixo. As negociações longas e curtas são simétricas e não há ordens de proteção. O registro pode ser ativado via LogSignals para rastrear cada decisão aleatória.
Como cada vela desencadeia apenas uma decisão aleatória, a estratégia é plana ou carrega uma única posição a qualquer momento. As posições só são invertidas ou fechadas quando a próxima barra aparece.
Gerenciamento de pedidos e riscos
Todas as entradas e saídas são realizadas com BuyMarket / SellMarket usando o volume configurado. Não há limite ou ordens de parada.
Se CloseBeforeReversal estiver desabilitado, a estratégia pode manter posições consecutivas: um novo sinal aleatório pode abrir imediatamente o lado oposto sem fechar explicitamente a negociação anterior primeiro.
Nenhuma gestão de dinheiro ou proteção de conta é implementada. O objetivo da porta é reproduzir o comportamento do consultor especialista de referência para cenários de testes educacionais e de infraestrutura.
Parâmetros
Parâmetro
Descrição
TradeVolume
Tamanho base do pedido usado para cada entrada aleatória. Deve permanecer positivo.
CloseBeforeReversal
Força a estratégia a fechar a posição atual antes de realizar a próxima negociação aleatória.
LogSignals
Grava mensagens AddInfoLog sempre que uma direção aleatória é gerada.
CandleType
Período de tempo que produz a série de velas que impulsiona o lançamento aleatório da moeda.
RandomSeed
Valor inicial para o gerador de números pseudoaleatórios. Use 0 para confiar no relógio do sistema.
Notas de uso
A porta mantém a ausência de níveis de take-profit e stop-loss, assim como a referência MQL. Qualquer controle de risco deve ser adicionado manualmente se a estratégia for utilizada para experimentos com capital real.
As sementes determinísticas são úteis para criar conjuntos de dados reproduzíveis ao otimizar ou avaliar comportamento aleatório.
A ativação do registro é recomendada durante os testes porque uma estratégia puramente aleatória oferece pouco feedback visual no gráfico.
using System;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that randomly opens long or short positions based on a random threshold.
/// Mirrors the "At random" MetaTrader expert.
/// </summary>
public class AtRandomStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _randomSeed;
private Random _random;
private int _barCount;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RandomSeed
{
get => _randomSeed.Value;
set => _randomSeed.Value = value;
}
public AtRandomStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe that triggers random decisions", "Data");
_randomSeed = Param(nameof(RandomSeed), 42)
.SetDisplay("Random Seed", "Seed for the pseudo random generator (0 = system clock)", "Diagnostics");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_random = RandomSeed == 0 ? new Random() : new Random(RandomSeed);
_barCount = 0;
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;
_barCount++;
// Only trade occasionally to keep turnover within runner limits.
if (_random.Next(0, 6) != 0)
return;
var volume = Volume;
if (volume <= 0)
volume = 1;
// Random direction
var goLong = _random.Next(0, 2) == 0;
if (goLong)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
}
/// <inheritdoc />
protected override void OnReseted()
{
_random = null;
_barCount = 0;
base.OnReseted();
}
}
import clr
import random
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 at_random_strategy(Strategy):
def __init__(self):
super(at_random_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._random_seed = self.Param("RandomSeed", 42)
self._rng = None
self._bar_count = 0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RandomSeed(self):
return self._random_seed.Value
@RandomSeed.setter
def RandomSeed(self, value):
self._random_seed.Value = value
def OnReseted(self):
super(at_random_strategy, self).OnReseted()
self._rng = None
self._bar_count = 0
def OnStarted2(self, time):
super(at_random_strategy, self).OnStarted2(time)
seed = self.RandomSeed
self._rng = random.Random(seed if seed != 0 else None)
self._bar_count = 0
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
self._bar_count += 1
# Only trade occasionally
if self._rng.randint(0, 5) != 0:
return
go_long = self._rng.randint(0, 1) == 0
if go_long:
if self.Position <= 0:
self.BuyMarket()
else:
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return at_random_strategy()