Virtual Profit Close replica el comportamiento del MetaTrader 4 asesor experto Virtual_Profit_Close.mq4. La estrategia vigila el
posición actual del valor configurado y sale tan pronto como se alcanza un objetivo de beneficio virtual. A diferencia de una orden regular de toma de ganancias,
el nivel de salida se evalúa internamente, por lo que no quedan órdenes de ganancias en el libro de órdenes. Un trailing stop configurable puede mover la salida
precio más cercano al mercado a medida que el comercio avanza hacia la obtención de ganancias. Cuando se ejecuta en modo de prueba, la estrategia puede abrir automáticamente posiciones de muestra.
para demostrar su lógica.
Notas de conversión
Los eventos de tick se consumen a través de SubscribeTrades().Bind(ProcessTrade).Start() para imitar la rutina original OnTick.
Los MetaTrader "puntos" se convierten en pips inspeccionando Security.PriceStep y ajustando los símbolos de 3/5 dígitos.
Los cálculos de ganancias virtuales y seguimiento utilizan la oferta actual para posiciones largas y la demanda para posiciones cortas, coincidiendo con el MQL
implementación que se basó en los precios Bid y Ask.
La lógica del trailing stop se activa después del umbral de beneficio configurado y mantiene el stop a una distancia fija del mercado.
precio, similar a llamar repetidamente a OrderModify en MQL.
Un modo de demostración reemplaza el asistente de prueba de estrategia original (SendTest) al abrir órdenes de mercado de acuerdo con el método seleccionado.
dirección y volumen. Las paradas protectoras opcionales se colocan usando SetStopLoss.
Parámetros
Parámetro
Descripción
ProfitPips
Nivel de toma de ganancias virtual expresado en MetaTrader pips. La estrategia cierra la posición una vez que el beneficio supera esta distancia.
UseTrailingStop
Habilita el comportamiento de seguimiento cuando se establece en true.
TrailingOffsetPips
Distancia mantenida entre el precio actual y el trailing stop una vez activo.
TrailingActivationPips
Beneficio mínimo en pips requerido antes de que se active el trailing stop.
EnableDemoMode
Abre automáticamente órdenes de demostración cada vez que la posición se vuelve plana. Útil para pruebas retrospectivas.
DemoOrderDirection
Dirección de pedidos de demostración (Buy o Sell).
DemoOrderVolume
Volumen enviado para pedidos de demostración.
DemoStopPips
Stop de protección opcional para órdenes de demostración, expresado en pips.
Comportamiento
Cuando comienza la estrategia, calcula el tamaño del pip y las distancias para obtener ganancias, paradas finales y de demostración.
Cada tick recibido a través de ProcessTrade evalúa la posición actual:
Las posiciones largas se cierran cuando el precio de oferta genera el beneficio virtual configurado.
Las posiciones cortas se cierran cuando el precio de venta cubre la misma distancia en la dirección opuesta.
Si el seguimiento está habilitado y se alcanza el umbral de activación, el trailing stop se mueve junto con el movimiento favorable del precio. una vez
el mercado cruza el nivel final, la estrategia envía una orden de mercado para salir.
El modo de demostración puede abrir automáticamente una nueva posición cada vez que la estrategia se vuelve plana, recreando la característica exclusiva para probadores del
experto original.
Requisitos
La estrategia necesita datos de mercado a nivel de tick para responder con precisión a los cambios de precios.
Sólo se debe asignar un símbolo a la instancia de estrategia. No se admiten varios símbolos simultáneos que coincidan con el original
Implementación MQL que monitoreó el símbolo del gráfico actual.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Virtual Profit Close strategy: EMA crossover with profit target management.
/// Enters on EMA crossover, closes when profit target is hit.
/// </summary>
public class VirtualProfitCloseStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
private decimal _entryPrice;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public VirtualProfitCloseStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_hasPrev = false;
_entryPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
_entryPrice = 0;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (_hasPrev)
{
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
BuyMarket();
_entryPrice = close;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
SellMarket();
_entryPrice = close;
}
}
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
}
}
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.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class virtual_profit_close_strategy(Strategy):
def __init__(self):
super(virtual_profit_close_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 20) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicators")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
self._entry_price = 0.0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
def OnReseted(self):
super(virtual_profit_close_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
self._entry_price = 0.0
def OnStarted2(self, time):
super(virtual_profit_close_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
self._has_prev = False
self._entry_price = 0.0
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(15)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
if not self._fast.IsFormed or not self._slow.IsFormed:
return
close = float(candle.ClosePrice)
fast_val = float(fast_value)
slow_val = float(slow_value)
if self._has_prev:
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
self.BuyMarket()
self._entry_price = close
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
self.SellMarket()
self._entry_price = close
self._prev_fast = fast_val
self._prev_slow = slow_val
self._has_prev = True
def CreateClone(self):
return virtual_profit_close_strategy()