Стратегия Color XCCX Candle
Стратегия, преобразованная из MQL кода MQL/14260.
Стратегия сравнивает две простые скользящие средние (SMA), построенные по ценам открытия и закрытия свечи. Когда SMA по закрытию пересекает сверху SMA по открытию, открывается длинная позиция. Когда SMA по закрытию пересекает снизу SMA по открытию, открывается короткая позиция. Перед открытием новой позиции противоположные позиции закрываются.
Параметры:
SMA Length– количество свечей для расчёта обеих SMA.Candle Type– таймфрейм используемых свечей.Stop Loss %– размер стоп-лосса в процентах от цены входа.Take Profit %– размер тейк-профита в процентах от цены входа.
Стратегия использует высокоуровневый API StockSharp для подписки на свечи и привязки индикаторов. При наличии графика отображаются обе SMA и совершённые сделки.
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()