Estrategia Color XCCX Candle
Convertida desde el código MQL MQL/14260.
Esta estrategia compara dos medias móviles simples (SMA) construidas a partir de los precios de apertura y cierre de las velas. Cuando la SMA calculada a partir de los precios de cierre cruza por encima de la SMA basada en los precios de apertura, se abre una posición larga. Cuando la SMA basada en el cierre cruza por debajo de la SMA basada en la apertura, se abre una posición corta. Cualquier posición opuesta existente se cierra antes de abrir una nueva.
Parámetros:
SMA Length– número de velas utilizadas para calcular ambas SMA.Candle Type– marco temporal para las velas entrantes.Stop Loss %– tamaño del stop loss como porcentaje del precio de entrada.Take Profit %– tamaño del take profit como porcentaje del precio de entrada.
La estrategia utiliza la API de alto nivel de StockSharp para suscribirse a velas y vincular indicadores. También traza ambas SMA y las operaciones ejecutadas en el gráfico cuando la visualización está disponible.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on comparison of smoothed open and close prices.
/// Buys when the SMA of close crosses above the SMA of open.
/// Sells when the SMA of close crosses below the SMA of open.
/// </summary>
public class ColorXccxCandleStrategy : Strategy
{
private readonly StrategyParam<int> _smaLength;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _takeProfitPercent;
private ExponentialMovingAverage _openEma;
private ExponentialMovingAverage _closeEma;
private decimal _prevDiff;
private bool _hasPrev;
public int SmaLength
{
get => _smaLength.Value;
set => _smaLength.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
public decimal TakeProfitPercent
{
get => _takeProfitPercent.Value;
set => _takeProfitPercent.Value = value;
}
public ColorXccxCandleStrategy()
{
_smaLength = Param(nameof(SmaLength), 5)
.SetDisplay("SMA Length", "Length of the moving averages", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for the strategy", "General");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetDisplay("Stop Loss %", "Stop loss as percent of entry price", "Risk Management");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 4m)
.SetDisplay("Take Profit %", "Take profit as percent of entry price", "Risk Management");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_openEma = default;
_closeEma = default;
_prevDiff = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_openEma = new ExponentialMovingAverage { Length = SmaLength };
_closeEma = new ExponentialMovingAverage { Length = SmaLength };
_prevDiff = 0;
_hasPrev = false;
Indicators.Add(_openEma);
Indicators.Add(_closeEma);
StartProtection(
takeProfit: new Unit(TakeProfitPercent, UnitTypes.Percent),
stopLoss: new Unit(StopLossPercent, UnitTypes.Percent));
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;
var openResult = _openEma.Process(candle.OpenPrice, candle.OpenTime, true);
var closeResult = _closeEma.Process(candle.ClosePrice, candle.OpenTime, true);
if (!openResult.IsFormed || !closeResult.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var openVal = openResult.ToDecimal();
var closeVal = closeResult.ToDecimal();
var diff = closeVal - openVal;
if (!_hasPrev)
{
_prevDiff = diff;
_hasPrev = true;
return;
}
if (_prevDiff <= 0 && diff > 0 && Position <= 0)
{
BuyMarket();
}
else if (_prevDiff >= 0 && diff < 0 && Position >= 0)
{
SellMarket();
}
_prevDiff = diff;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class color_xccx_candle_strategy(Strategy):
def __init__(self):
super(color_xccx_candle_strategy, self).__init__()
self._sma_length = self.Param("SmaLength", 5) \
.SetDisplay("SMA Length", "Length of the moving averages", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for the strategy", "General")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss as percent of entry price", "Risk Management")
self._take_profit_percent = self.Param("TakeProfitPercent", 4.0) \
.SetDisplay("Take Profit %", "Take profit as percent of entry price", "Risk Management")
self._open_ema = None
self._close_ema = None
self._prev_diff = 0.0
self._has_prev = False
@property
def sma_length(self):
return self._sma_length.Value
@property
def candle_type(self):
return self._candle_type.Value
@property
def stop_loss_percent(self):
return self._stop_loss_percent.Value
@property
def take_profit_percent(self):
return self._take_profit_percent.Value
def OnReseted(self):
super(color_xccx_candle_strategy, self).OnReseted()
self._open_ema = None
self._close_ema = None
self._prev_diff = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(color_xccx_candle_strategy, self).OnStarted2(time)
self._open_ema = ExponentialMovingAverage()
self._open_ema.Length = self.sma_length
self._close_ema = ExponentialMovingAverage()
self._close_ema.Length = self.sma_length
self._prev_diff = 0.0
self._has_prev = False
self.Indicators.Add(self._open_ema)
self.Indicators.Add(self._close_ema)
self.StartProtection(
takeProfit=Unit(float(self.take_profit_percent), UnitTypes.Percent),
stopLoss=Unit(float(self.stop_loss_percent), UnitTypes.Percent))
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
open_result = process_float(self._open_ema, candle.OpenPrice, candle.OpenTime, True)
close_result = process_float(self._close_ema, candle.ClosePrice, candle.OpenTime, True)
if not open_result.IsFormed or not close_result.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
open_val = float(open_result)
close_val = float(close_result)
diff = close_val - open_val
if not self._has_prev:
self._prev_diff = diff
self._has_prev = True
return
if self._prev_diff <= 0 and diff > 0 and self.Position <= 0:
self.BuyMarket()
elif self._prev_diff >= 0 and diff < 0 and self.Position >= 0:
self.SellMarket()
self._prev_diff = diff
def CreateClone(self):
return color_xccx_candle_strategy()