Стратегия торгует по направлению усреднителя третьего поколения. Индикатор представляет собой комбинацию двух экспоненциальных средних и окрашивается в синий цвет при росте и в розовый при падении. При смене цвета вверх формируется сигнал на покупку, при смене вниз — сигнал на продажу.
Сделки открываются только в заданное пользователем время после появления сигнала. Позиции могут закрываться при противоположном сигнале или по истечении заданного времени удержания. Дополнительно поддерживаются уровни стоп‑лосса и тейк‑профита в пунктах.
Параметры
Length — период усреднения третьего поколения.
StartHour — час, в который разрешено открывать позиции.
StartMinute — минута внутри часа для открытия.
HoldMinutes — максимальное время удержания позиции.
Volume — объём заявки при входе.
StopLoss — расстояние стоп‑лосса в пунктах, 0 выключает стоп.
TakeProfit — расстояние тейк‑профита в пунктах, 0 выключает цель.
UseLongEntries — разрешение на открытие длинных позиций.
UseShortEntries — разрешение на открытие коротких позиций.
CloseLongBySignal — закрывать лонги при появлении сигнала на продажу.
CloseShortBySignal — закрывать шорты при появлении сигнала на покупку.
CandleType — таймфрейм свечей для расчётов.
Логика
Подписка на свечи выбранного таймфрейма.
Расчёт усреднителя третьего поколения на каждой свече.
Определение роста или падения значения между соседними свечами.
Сохранение сигнала на покупку или продажу в зависимости от направления.
В указанное время открытие позиции в сторону сохранённого сигнала.
Закрытие позиции при противоположном сигнале, по истечении времени удержания или при достижении стоп‑лосса/тейк‑профита.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Color 3rd Generation XMA strategy.
/// Uses two EMAs of different periods to approximate 3rd generation moving average.
/// Opens long when fast EMA crosses above slow EMA, short when crosses below.
/// </summary>
public class Color3RdGenXmaStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<decimal> _minSpread;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _isFirst = true;
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
public decimal MinSpread { get => _minSpread.Value; set => _minSpread.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Color3RdGenXmaStrategy()
{
_fastLength = Param(nameof(FastLength), 20)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "General");
_slowLength = Param(nameof(SlowLength), 50)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period", "General");
_minSpread = Param(nameof(MinSpread), 20m)
.SetGreaterThanZero()
.SetDisplay("Min Spread", "Minimum EMA spread in price steps", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_isFirst = true;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0m;
_prevSlow = 0m;
_isFirst = true;
var fastEma = new ExponentialMovingAverage { Length = FastLength };
var slowEma = new ExponentialMovingAverage { Length = SlowLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (_isFirst)
{
_prevFast = fast;
_prevSlow = slow;
_isFirst = false;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fast;
_prevSlow = slow;
return;
}
var step = Security.PriceStep ?? 1m;
var spread = Math.Abs(fast - slow);
if (spread < MinSpread * step)
{
_prevFast = fast;
_prevSlow = slow;
return;
}
var prevAbove = _prevFast > _prevSlow;
var curAbove = fast > slow;
if (!prevAbove && curAbove && Position <= 0)
BuyMarket();
else if (prevAbove && !curAbove && Position >= 0)
SellMarket();
_prevFast = fast;
_prevSlow = slow;
}
}
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 color_3rd_gen_xma_strategy(Strategy):
def __init__(self):
super(color_3rd_gen_xma_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 20) \
.SetDisplay("Fast EMA", "Fast EMA period", "General")
self._slow_length = self.Param("SlowLength", 50) \
.SetDisplay("Slow EMA", "Slow EMA period", "General")
self._min_spread = self.Param("MinSpread", 20.0) \
.SetDisplay("Min Spread", "Minimum EMA spread in price steps", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for calculations", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._is_first = True
@property
def fast_length(self):
return self._fast_length.Value
@property
def slow_length(self):
return self._slow_length.Value
@property
def min_spread(self):
return self._min_spread.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_3rd_gen_xma_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._is_first = True
def OnStarted2(self, time):
super(color_3rd_gen_xma_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._is_first = True
fast_ema = ExponentialMovingAverage()
fast_ema.Length = int(self.fast_length)
slow_ema = ExponentialMovingAverage()
slow_ema.Length = int(self.slow_length)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ema, slow_ema, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
fast = float(fast)
slow = float(slow)
if self._is_first:
self._prev_fast = fast
self._prev_slow = slow
self._is_first = False
return
spread = abs(fast - slow)
ms = float(self.min_spread)
price_step = float(self.Security.PriceStep) if self.Security.PriceStep is not None else 1.0
if spread < ms * price_step:
self._prev_fast = fast
self._prev_slow = slow
return
prev_above = self._prev_fast > self._prev_slow
cur_above = fast > slow
if not prev_above and cur_above and self.Position <= 0:
self.BuyMarket()
elif prev_above and not cur_above and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return color_3rd_gen_xma_strategy()