La Estrategia At Random Full es una fiel conversión del asesor experto MetaTrader 5 "At Random Full". Mantiene el
idea original de abrir operaciones basadas en un generador aleatorio mientras se exponen los mismos interruptores de administración de dinero: dirección
filtros, espaciado de cuadrícula, ventanas de tiempo opcionales y un interruptor de encendido/apagado para promediar. El puerto StockSharp utiliza el nivel alto API,
por lo que todo el ciclo de decisión está impulsado por suscripciones de velas y ayudantes estándar StartProtection para órdenes de protección.
Lógica de trading
En cada vela terminada, la estrategia verifica que se permita el comercio (filtro de sesión, estado de la cartera y opcional).
bandera "sólo una posición").
Un generador pseudoaleatorio decide entre una entrada larga o corta. El parámetro ReverseSignals puede cambiar el resultado a
emular el modo inverso MQL.
Los filtros de dirección (TradeMode) bloquean señales no deseadas. El código también aplica la regla original EA de una sola operación por
barra en cada dirección recordando el tiempo de apertura de la vela de la última señal.
Las opciones de gestión de red reflejan el comportamiento de MetaTrader:
MaxPositions limita el número de entradas promedio por lado.
MinStepPoints requiere una distancia mínima (convertida en precio utilizando el paso del precio de seguridad) entre entradas consecutivas.
CloseOpposite obliga a cerrar la exposición opuesta existente antes de enviar una nueva operación.
Las órdenes de mercado se emiten a través de BuyMarket / SellMarket con un volumen normalizado definido por OrderVolume.
Gestión de posiciones y riesgos
StartProtection adjunta órdenes de stop-loss y take-profit que coinciden con las entradas MetaTrader. Si TrailingStopPoints es
mayor que cero, el modo de seguimiento integrado StockSharp está habilitado. Los parámetros TrailingActivatePoints y
TrailingStepPoints se convierten en distancias de precios y se registran para mayor transparencia, pero el seguimiento real lo maneja el
plataforma.
Todos los cálculos de volumen respetan los metadatos de intercambio (mínimo, máximo y paso) exactamente como las rutinas auxiliares MQL.
El control de tiempo emula el bloque InpTimeControl del script. Cuando está habilitado, los intercambios se permiten solo dentro del configurado
[SessionStart, SessionEnd] ventana; Se admiten sesiones nocturnas.
Parámetros
Parámetro
Descripción
Predeterminado
CandleType
Serie de velas utilizada para programar el ciclo de decisión.
15 minute timeframe
OrderVolume
Volumen de orden de mercado base en lotes.
0.1
MaxPositions
Número máximo de entradas promediadas por dirección (0 = ilimitado).
5
MinStepPoints
Distancia mínima entre entradas expresada en MetaTrader puntos.
150
StopLossPoints
Distancia de stop-loss en puntos.
150
TakeProfitPoints
Distancia de toma de ganancias en puntos.
460
TrailingActivatePoints
Umbral de beneficio (en puntos) registrado con fines informativos cuando el seguimiento está habilitado.
70
TrailingStopPoints
La distancia del trailing stop pasó a StartProtection.
250
TrailingStepPoints
Paso entre ajustes de seguimiento, registrado a lo largo de la distancia de activación.
50
OnlyOnePosition
Bloquea nuevas operaciones hasta que se cierre la posición neta actual.
false
CloseOpposite
Cierra la exposición opuesta antes de abrir una operación.
false
ReverseSignals
Invierte la decisión aleatoria para que las compras se conviertan en ventas y viceversa.
false
UseTimeControl
Habilita el filtro de tiempo de la sesión de negociación.
false
SessionStart
Hora de inicio de la sesión (inclusive) cuando UseTimeControl es true.
10:01
SessionEnd
Hora de finalización de la sesión (inclusive) cuando UseTimeControl es true.
Semilla determinista opcional para el generador pseudoaleatorio (0 = recuento de tics ambientales).
0
Notas de implementación
Todos los comentarios están escritos en inglés y el código utiliza sangría de tabulación, coincidiendo con las pautas del repositorio.
El procesamiento de velas se basa en SubscribeCandles().Bind(...), lo que garantiza que la lógica se ejecute una vez por barra terminada como en EA.
La estrategia realiza un seguimiento de los últimos precios de compra y venta para imponer la restricción de espacio mínimo incluso durante el promedio.
Las declaraciones de registro reflejan los diagnósticos detallados impresos por el script original: cada entrada anuncia la dirección elegida,
precio de entrada, volumen y configuración final al inicio.
Consejos de uso
Debido a que la señal comercial es aleatoria, la estrategia es más adecuada para probar la infraestructura o demostrar controles de riesgo.
Ajuste OrderVolume, StopLossPoints y TakeProfitPoints para alinearlos con el tamaño del tick y la volatilidad del instrumento que
planea comerciar.
Habilite UseTimeControl si EA debe funcionar solo durante una sesión específica (por ejemplo, la sesión de Londres o Nueva York).
Utilice RandomSeed durante las ejecuciones de optimización para lograr secuencias reproducibles de decisiones aleatorias.
using System;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "At random Full" MetaTrader expert.
/// Randomly opens long or short positions with grid spacing and position limits.
/// </summary>
public class AtRandomFullStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maxPositions;
private readonly StrategyParam<int> _randomSeed;
private Random _random;
private decimal _lastEntryPrice;
private int _entryCount;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaxPositions
{
get => _maxPositions.Value;
set => _maxPositions.Value = value;
}
public int RandomSeed
{
get => _randomSeed.Value;
set => _randomSeed.Value = value;
}
public AtRandomFullStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Primary timeframe", "General");
_maxPositions = Param(nameof(MaxPositions), 3)
.SetDisplay("Max Positions", "Maximum number of averaged entries", "Risk");
_randomSeed = Param(nameof(RandomSeed), 123)
.SetDisplay("Random Seed", "Fixed seed for deterministic simulations", "Execution");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_random = RandomSeed == 0 ? new Random() : new Random(RandomSeed);
_lastEntryPrice = 0;
_entryCount = 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;
// Only trade occasionally to keep turnover within runner limits.
if (_random.Next(0, 5) != 0)
return;
var volume = Volume;
if (volume <= 0)
volume = 1;
var close = candle.ClosePrice;
// Check grid spacing - minimum 0.5% between entries
if (_lastEntryPrice > 0 && Math.Abs(close - _lastEntryPrice) / _lastEntryPrice < 0.005m)
return;
// Check entry limit
if (MaxPositions > 0 && _entryCount >= MaxPositions)
{
// Close position and reset
if (Position > 0)
SellMarket(Position);
else if (Position < 0)
BuyMarket(Math.Abs(Position));
_entryCount = 0;
_lastEntryPrice = 0;
return;
}
var goLong = _random.Next(0, 2) == 0;
if (goLong)
{
if (Position < 0)
{
BuyMarket(Math.Abs(Position) + volume);
_entryCount = 1;
_lastEntryPrice = close;
}
else if (Position == 0)
{
BuyMarket(volume);
_lastEntryPrice = close;
_entryCount++;
}
}
else
{
if (Position > 0)
{
SellMarket(Math.Abs(Position) + volume);
_entryCount = 1;
_lastEntryPrice = close;
}
else if (Position == 0)
{
SellMarket(volume);
_lastEntryPrice = close;
_entryCount++;
}
}
}
/// <inheritdoc />
protected override void OnReseted()
{
_random = null;
_lastEntryPrice = 0;
_entryCount = 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_full_strategy(Strategy):
def __init__(self):
super(at_random_full_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._max_positions = self.Param("MaxPositions", 3)
self._random_seed = self.Param("RandomSeed", 123)
self._rng = None
self._last_entry_price = 0.0
self._entry_count = 0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MaxPositions(self):
return self._max_positions.Value
@MaxPositions.setter
def MaxPositions(self, value):
self._max_positions.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_full_strategy, self).OnReseted()
self._rng = None
self._last_entry_price = 0.0
self._entry_count = 0
def OnStarted2(self, time):
super(at_random_full_strategy, self).OnStarted2(time)
seed = self.RandomSeed
self._rng = random.Random(seed if seed != 0 else None)
self._last_entry_price = 0.0
self._entry_count = 0
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
# Only trade occasionally
if self._rng.randint(0, 4) != 0:
return
close = float(candle.ClosePrice)
# Check grid spacing
if self._last_entry_price > 0 and abs(close - self._last_entry_price) / self._last_entry_price < 0.005:
return
# Check entry limit
if self.MaxPositions > 0 and self._entry_count >= self.MaxPositions:
if self.Position > 0:
self.SellMarket()
elif self.Position < 0:
self.BuyMarket()
self._entry_count = 0
self._last_entry_price = 0.0
return
go_long = self._rng.randint(0, 1) == 0
if go_long:
if self.Position <= 0:
self.BuyMarket()
self._last_entry_price = close
self._entry_count += 1
else:
if self.Position >= 0:
self.SellMarket()
self._last_entry_price = close
self._entry_count += 1
def CreateClone(self):
return at_random_full_strategy()