Conversão do consultor especialista do MetaTrader 5 RndTrade.mq5 para a API de estratégia de alto nível do StockSharp.
Fecha qualquer posição existente em um intervalo de tempo fixo e imediatamente abre uma nova posição de mercado em uma direção selecionada aleatoriamente.
Usa assinaturas de velas baseadas em tempo como substituto determinístico para os callbacks de temporizador originais.
Parâmetros
Nome
Tipo
Padrão
Descrição
IntervalMinutes
int
60
Número de minutos entre o fechamento da posição atual e a abertura de uma nova posição aleatória. Deve ser maior que zero.
Volume
decimal
1
Tamanho da posição usado para entradas a mercado. Derivado da classe base Strategy.
Assinaturas de dados
Assina velas de período cujo comprimento corresponde a IntervalMinutes (p. ex., 60 → velas de 60 minutos).
O evento de fechamento de vela (CandleStates.Finished) é usado para acionar a lógica exatamente uma vez por intervalo.
Lógica de trading
Aguardar a conclusão de cada vela de intervalo.
Pular o processamento até que a estratégia esteja formada, online e o trading seja permitido.
Fechar qualquer posição aberta criada durante o intervalo anterior.
Gerar um valor aleatório para decidir entre uma entrada comprada ou vendida.
Enviar uma ordem a mercado (BuyMarket ou SellMarket) com o volume configurado na direção selecionada.
Notas de implementação
Baseia-se em SubscribeCandles().Bind(ProcessCandle) para evitar o polling manual de valores de indicadores ou coleções.
Chama StartProtection() durante a inicialização para que o módulo de risco integrado esteja ativo, mesmo que nenhum stop-loss ou take-profit explícito seja configurado.
Usa Random da biblioteca padrão para imitar o comportamento MathRand() encontrado na estratégia MQL original.
O código contém comentários em inglês que explicam como cada etapa de conversão se mapeia para as características do StockSharp.
Diferenças em relação à estratégia MQL original
Eventos de temporizador (OnTimer) são emulados por meio de assinaturas de velas em vez da API de temporizador do MetaTrader.
O fechamento de posição é tratado com ClosePosition() em vez de iterar sobre listas de posições e chamar PositionClose para cada ticket.
A versão StockSharp depende da propriedade integrada Volume para o dimensionamento de posições em vez da consulta do lote mínimo do símbolo.
As regras de preenchimento de ordens e as configurações de deslizamento são gerenciadas pelo corretor ou simulador conectado, portanto não são configuradas explicitamente na estratégia.
Uso
Anexar a estratégia a um portfólio e instrumento dentro do ambiente StockSharp.
Configurar IntervalMinutes e Volume de acordo com a frequência de trading e o tamanho desejados.
Iniciar a estratégia. Ela aplanará e reabrirá posições automaticamente em cada intervalo sem nenhuma entrada adicional.
Nenhuma implementação em Python está disponível no momento; apenas a versão C# está disponível.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Random direction trading strategy converted from the MetaTrader RndTrade EA.
/// The strategy closes any open position on each interval and immediately opens a new random position.
/// </summary>
public class RndTradeStrategy : Strategy
{
private readonly StrategyParam<int> _intervalMinutes;
/// <summary>
/// Interval in minutes between closing the current position and opening a new random one.
/// </summary>
public int IntervalMinutes
{
get => _intervalMinutes.Value;
set => _intervalMinutes.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="RndTradeStrategy"/> class.
/// </summary>
public RndTradeStrategy()
{
_intervalMinutes = Param(nameof(IntervalMinutes), 360)
.SetGreaterThanZero()
.SetDisplay("Interval Minutes", "Minutes between closing and opening positions", "General");
Volume = 1;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, TimeSpan.FromMinutes(IntervalMinutes).TimeFrame())];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Use time-based candles as a deterministic timer replacement.
var timeFrame = TimeSpan.FromMinutes(IntervalMinutes).TimeFrame();
var subscription = SubscribeCandles(timeFrame);
subscription
.Bind(ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle)
{
// Process only final candles to execute logic exactly once per interval.
if (candle.State != CandleStates.Finished)
return;
// Always close the existing position before selecting a new random direction.
if (Position > 0)
SellMarket(Position);
else if (Position < 0)
BuyMarket(Math.Abs(Position));
// Derive a deterministic pseudo-random direction from the candle data.
if (ShouldBuy(candle))
{
// Enter long after flattening the previous position.
if (Position <= 0)
BuyMarket(Volume);
}
else
{
// Enter short after flattening the previous position.
if (Position >= 0)
SellMarket(Volume);
}
}
private static bool ShouldBuy(ICandleMessage candle)
{
var hash = HashCode.Combine(candle.OpenTime.Ticks, candle.ClosePrice, candle.TotalVolume);
return (hash & 1) == 0;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class rnd_trade_strategy(Strategy):
def __init__(self):
super(rnd_trade_strategy, self).__init__()
self._interval_minutes = self.Param("IntervalMinutes", 360).SetGreaterThanZero().SetDisplay("Interval Minutes", "Minutes between trades", "General")
def OnStarted2(self, time):
super(rnd_trade_strategy, self).OnStarted2(time)
tf = DataType.TimeFrame(TimeSpan.FromMinutes(self._interval_minutes.Value))
sub = self.SubscribeCandles(tf)
sub.Bind(self.OnProcess).Start()
def OnProcess(self, candle):
if candle.State != CandleStates.Finished:
return
if self.Position > 0:
self.SellMarket()
elif self.Position < 0:
self.BuyMarket()
h = int(float(candle.ClosePrice) * 1000) ^ int(candle.TotalVolume)
if (h & 1) == 0:
if self.Position <= 0:
self.BuyMarket()
else:
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return rnd_trade_strategy()