Cierre de ganancias o pérdidas en la moneda de la cuenta
Esta estrategia reproduce el asesor experto MetaTrader Close_on_PROFIT_or_LOSS_inAccont_Currency. Supervisa continuamente el capital de la cartera al que está vinculada la estrategia y, una vez que se alcanza un objetivo de ganancias configurado o un piso de reducción, liquida todas las posiciones abiertas y cancela todas las órdenes pendientes administradas por la estrategia. La clase se basa en el nivel alto de StockSharp API: una suscripción de vela proporciona el latido, CancelActiveOrders() elimina las órdenes de trabajo y ClosePosition() aplana la exposición a través de órdenes de mercado.
como funciona
La estrategia sigue sondeando el valor actual (Portfolio.CurrentValue) cada vez que se cierra una vela de latido.
Si el capital es mayor o igual a Cierre positivo, la estrategia envía una solicitud de cierre completo.
Si el patrimonio es menor o igual a Cierre Negativo, se ejecuta la misma rutina de liquidación para limitar las pérdidas.
Durante la liquidación, la estrategia cancela todas las órdenes pendientes, envía órdenes de mercado para cerrar todas las posiciones activas y finalmente se detiene (reflejando la llamada ExpertRemove() del EA original).
Importante: establezca los umbrales en la moneda de la cuenta. Para emular el comportamiento original, elija un valor de Cierre positivo encima del capital actual y un valor de Cierre negativo debajo de él; de lo contrario, la salida se activará inmediatamente después del inicio.
Parámetros
Nombre
Descripción
Predeterminado
PositiveClosureInAccountCurrency
Nivel de patrimonio que desencadena una liquidación total cuando se excede.
0
NegativeClosureInAccountCurrency
Piso patrimonial que obliga a la liquidación cuando se alcanza.
0
CandleType
Marco de tiempo utilizado para las velas de latido que impulsan los controles de acciones. Redúzcalo para reacciones más rápidas.
1 minute
Notas
StartProtection() se activa al inicio para copiar el comportamiento de seguridad original.
La estrategia sólo interactúa con las posiciones y órdenes que gestiona; adjúntelo a la cartera que contiene las operaciones que desea proteger.
No hay entradas separadas para diferenciales/deslizamientos porque StockSharp órdenes de mercado ya representan costos de ejecución específicos del conector.
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;
using StockSharp.Algo.Candles;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Closes all positions when portfolio equity reaches configured profit or loss thresholds.
/// Pending orders are cancelled before liquidating the exposure.
/// </summary>
public class CloseOnProfitOrLossInAccountCurrencyStrategy : Strategy
{
private readonly StrategyParam<decimal> _positiveClosure;
private readonly StrategyParam<decimal> _negativeClosure;
private readonly StrategyParam<DataType> _candleType;
private bool _closeRequested;
private SimpleMovingAverage _smaFast;
private SimpleMovingAverage _smaSlow;
/// <summary>
/// Equity level in account currency that triggers closing all positions when exceeded.
/// </summary>
public decimal PositiveClosureInAccountCurrency
{
get => _positiveClosure.Value;
set => _positiveClosure.Value = value;
}
/// <summary>
/// Equity level in account currency that triggers closing all positions when reached on drawdown.
/// </summary>
public decimal NegativeClosureInAccountCurrency
{
get => _negativeClosure.Value;
set => _negativeClosure.Value = value;
}
/// <summary>
/// Candle type used as a heartbeat to evaluate portfolio equity.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="CloseOnProfitOrLossInAccountCurrencyStrategy"/> class.
/// </summary>
public CloseOnProfitOrLossInAccountCurrencyStrategy()
{
_positiveClosure = Param(nameof(PositiveClosureInAccountCurrency), 0m)
.SetDisplay("Positive Closure", "Equity level that triggers full liquidation", "Risk");
_negativeClosure = Param(nameof(NegativeClosureInAccountCurrency), 0m)
.SetDisplay("Negative Closure", "Equity floor that forces liquidation", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Heartbeat Candle", "Candle type that triggers equity checks", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
if (Security == null)
return Array.Empty<(Security, DataType)>();
return new (Security, DataType)[] { (Security, CandleType) };
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
if (Portfolio == null)
throw new InvalidOperationException("Portfolio cannot be null.");
if (Security == null)
throw new InvalidOperationException("Security must be set to subscribe for candles.");
_smaFast = new SimpleMovingAverage { Length = 10 };
_smaSlow = new SimpleMovingAverage { Length = 30 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_smaFast, _smaSlow, ProcessCandleWithIndicators)
.Start();
}
private void ProcessCandleWithIndicators(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (fast > slow && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (fast < slow && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
private void RequestCloseAll(string reason)
{
if (_closeRequested)
return;
_closeRequested = true;
LogInfo(reason);
// Cancel any pending orders to avoid unexpected executions during liquidation.
CancelActiveOrders();
foreach (var position in Positions.ToArray())
{
var value = GetPositionValue(position.Security, Portfolio) ?? 0m;
if (value == 0m)
continue;
// Submit a market order opposite to the current exposure.
ClosePosition(position.Security);
}
// Stop the strategy after sending exit orders, mirroring ExpertRemove behavior.
Stop();
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class close_on_profit_or_loss_in_account_currency_strategy(Strategy):
"""
SMA crossover strategy with equity-based closure.
Uses fast/slow SMA crossover for entries.
"""
def __init__(self):
super(close_on_profit_or_loss_in_account_currency_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Heartbeat Candle", "Candle type that triggers equity checks", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(close_on_profit_or_loss_in_account_currency_strategy, self).OnStarted2(time)
sma_fast = SimpleMovingAverage()
sma_fast.Length = 10
sma_slow = SimpleMovingAverage()
sma_slow.Length = 30
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma_fast, sma_slow, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma_fast)
self.DrawIndicator(area, sma_slow)
self.DrawOwnTrades(area)
def on_process(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return close_on_profit_or_loss_in_account_currency_strategy()