La Estrategia de apertura de posición condicional reproduce el comportamiento del script MetaTrader original "Abrir una posición de compra si no hay una posición abierta". La lógica es intencionalmente simple: cuando los cambios manuales habilitan el lado largo o corto, la estrategia envía una orden de mercado sólo si no hay exposición abierta en esa dirección. Esto evita entradas duplicadas y mantiene la posición alineada con el lado seleccionado.
El puerto StockSharp mantiene la implementación neutral para los intermediarios al confiar en la suscripción de vela de alto nivel del marco y el asistente de protección integrado. Las distancias de stop-loss y take-profit se proporcionan en unidades de pips (escalones de precio) para que puedan adaptarse a cualquier instrumento.
Lógica de la estrategia
Suscríbase a la serie de velas configuradas para actuar como un latido del corazón.
En cada vela terminada verifique la posición neta actual.
Si el interruptor largo está habilitado y la posición es plana o corta, envíe una orden de compra de mercado.
Si el interruptor corto está habilitado y la posición es plana o larga, envíe una orden de venta en el mercado.
Las órdenes de protección se gestionan automáticamente a través de StartProtection, que convierte las distancias de pips en compensaciones de precios reales.
Debido a que StockSharp usa posiciones netas, habilitar ambas partes al mismo tiempo abrirá primero la operación larga y luego, si sigue sin cambios después de completarse, la operación corta. Esto refleja la intención del código MQL que evitaba múltiples pedidos por dirección.
Parámetros
Nombre
Predeterminado
Descripción
Volume
1
Tamaño de la orden para cada entrada al mercado.
StopLossPips
100
Distancia de stop-loss expresada en pasos de precio. Establezca en cero para desactivar.
TakeProfitPips
200
Distancia de obtención de beneficios expresada en incrementos de precio. Establezca en cero para desactivar.
EnableBuy
false
Cuando true la estrategia puede abrir posiciones largas si no existe una exposición larga.
EnableSell
false
Cuando true la estrategia puede abrir posiciones cortas si no existe exposición corta.
CandleType
1 minute timeframe
Serie de velas que impulsa la evaluación periódica.
Notas
Las distancias se convierten en incrementos de precios reales utilizando el PriceStep del instrumento. Si el intercambio no lo informa, el valor del pip bruto se utiliza como compensación absoluta.
StartProtection adjunta automáticamente órdenes de stop-loss y take-profit después de cada ejecución, por lo que no es necesaria la gestión manual de órdenes.
La estrategia se centra en la activación de estilo manual y pretende ser una plantilla para la ejecución discrecional a través de parámetros.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Conditional Position Opener" MetaTrader expert.
/// Uses Momentum indicator to conditionally open long or short positions.
/// Opens long when momentum is positive, short when negative.
/// </summary>
public class ConditionalPositionOpenerStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _momentumPeriod;
private Momentum _momentum;
private decimal? _prevMomentum;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MomentumPeriod
{
get => _momentumPeriod.Value;
set => _momentumPeriod.Value = value;
}
public ConditionalPositionOpenerStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for signal generation", "General");
_momentumPeriod = Param(nameof(MomentumPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Momentum Period", "Momentum indicator period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMomentum = null;
_momentum = new Momentum { Length = MomentumPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_momentum, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal momentumValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_momentum.IsFormed)
{
_prevMomentum = momentumValue;
return;
}
if (_prevMomentum is null)
{
_prevMomentum = momentumValue;
return;
}
var volume = Volume;
if (volume <= 0)
volume = 1;
// Cross above 101 (positive momentum)
var crossUp = _prevMomentum.Value <= 101m && momentumValue > 101m;
// Cross below 99 (negative momentum)
var crossDown = _prevMomentum.Value >= 99m && momentumValue < 99m;
if (crossUp)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (crossDown)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevMomentum = momentumValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_momentum = null;
_prevMomentum = null;
base.OnReseted();
}
}