Esta estrategia coloca órdenes stop simétricas por encima y por debajo del precio actual y usa salidas trailing para capturar rupturas.
Parámetros
Anchor – distancia en pasos de precio para colocar las órdenes stop.
XFactor – multiplicador para el volumen de la orden.
Trailing Stop – distancia del trailing stop en pasos de precio.
Trailing Profit – umbral de ganancia para salir de la posición.
Stop Loss – stop loss fijo en pasos de precio (0 lo desactiva).
Volume – volumen base de la orden.
Candle Type – marco temporal de las velas procesadas.
Lógica de Trading
Cuando no hay posición abierta, se cancelan las órdenes existentes y se colocan tanto un Buy Stop como un Sell Stop a Anchor pasos del cierre de la última vela.
Cuando se abre una posición, se cancela la orden stop opuesta. El precio de entrada se recuerda para los cálculos de salida.
Para una posición larga, si la ganancia alcanza Trailing Profit o el precio cae Stop Loss, la posición se cierra. Para una posición corta, la lógica es espejo.
La estrategia está diseñada como ejemplo de trading de ruptura con gestión de riesgo simple.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Charles 1.3.7 breakout strategy using symmetric price levels.
/// </summary>
public class Charles137Strategy : Strategy
{
private readonly StrategyParam<decimal> _anchor;
private readonly StrategyParam<decimal> _trailingProfit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private decimal _buyLevel;
private decimal _sellLevel;
private bool _levelsSet;
public decimal Anchor { get => _anchor.Value; set => _anchor.Value = value; }
public decimal TrailingProfit { get => _trailingProfit.Value; set => _trailingProfit.Value = value; }
public decimal StopLossVal { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Charles137Strategy()
{
_anchor = Param(nameof(Anchor), 200m)
.SetGreaterThanZero()
.SetDisplay("Anchor", "Distance for breakout levels", "General");
_trailingProfit = Param(nameof(TrailingProfit), 500m)
.SetGreaterThanZero()
.SetDisplay("Trailing Profit", "Profit target distance", "General");
_stopLoss = Param(nameof(StopLossVal), 300m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss", "Stop loss distance", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Working timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
_buyLevel = 0;
_sellLevel = 0;
_levelsSet = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType)
.Bind(ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished) return;
var price = candle.ClosePrice;
if (Position == 0)
{
if (!_levelsSet)
{
_buyLevel = price + Anchor;
_sellLevel = price - Anchor;
_levelsSet = true;
return;
}
if (price >= _buyLevel)
{
BuyMarket();
_entryPrice = price;
_levelsSet = false;
}
else if (price <= _sellLevel)
{
SellMarket();
_entryPrice = price;
_levelsSet = false;
}
else
{
_buyLevel = price + Anchor;
_sellLevel = price - Anchor;
}
}
else if (Position > 0)
{
var profit = price - _entryPrice;
if (profit >= TrailingProfit || profit <= -StopLossVal)
{
SellMarket();
_levelsSet = false;
}
}
else if (Position < 0)
{
var profit = _entryPrice - price;
if (profit >= TrailingProfit || profit <= -StopLossVal)
{
BuyMarket();
_levelsSet = false;
}
}
}
}