Стратегия Triple EMA Crossover
Стратегия основана на трёх простых скользящих средних. Длинная позиция открывается, когда короткая SMA пересекает среднюю снизу вверх при восходящем расположении всех трёх линий. Короткая позиция открывается при противоположном пересечении и нисходящем тренде. Выход из позиции происходит при пересечении цены с короткой SMA или по защитным стопам.
Детали
- Критерии входа: пересечение SMA1 и SMA2 с фильтром тренда.
- Длинные/короткие: оба направления.
- Критерии выхода: пересечение цены с SMA1 или защитные стопы.
- Стопы: да.
- Значения по умолчанию:
Sma1Period= 9Sma2Period= 21Sma3Period= 55StopLossTicks= 200TakeProfitTicks= 200CandleType= TimeSpan.FromMinutes(5)
- Фильтры:
- Категория: Тренд
- Направление: Оба
- Индикаторы: SMA
- Стопы: Фиксированные
- Сложность: Базовая
- Таймфрейм: Внутридневной (5m)
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Triple SMA crossover with stop loss and take profit.
/// </summary>
public class TripleEmaCrossoverStrategy : Strategy
{
private readonly StrategyParam<int> _sma1Period;
private readonly StrategyParam<int> _sma2Period;
private readonly StrategyParam<int> _sma3Period;
private readonly StrategyParam<int> _stopLossTicks;
private readonly StrategyParam<int> _takeProfitTicks;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevSma1;
private decimal _prevSma2;
private decimal _prevSma3;
private int _cooldown;
public TripleEmaCrossoverStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_sma1Period = Param(nameof(Sma1Period), 5)
.SetDisplay("SMA1 Period", "Period for short SMA", "Indicators");
_sma2Period = Param(nameof(Sma2Period), 13)
.SetDisplay("SMA2 Period", "Period for middle SMA", "Indicators");
_sma3Period = Param(nameof(Sma3Period), 21)
.SetDisplay("SMA3 Period", "Period for long SMA", "Indicators");
_stopLossTicks = Param(nameof(StopLossTicks), 200)
.SetDisplay("Stop Loss (ticks)", "Stop loss in ticks", "Risk");
_takeProfitTicks = Param(nameof(TakeProfitTicks), 200)
.SetDisplay("Take Profit (ticks)", "Take profit in ticks", "Risk");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int Sma1Period
{
get => _sma1Period.Value;
set => _sma1Period.Value = value;
}
public int Sma2Period
{
get => _sma2Period.Value;
set => _sma2Period.Value = value;
}
public int Sma3Period
{
get => _sma3Period.Value;
set => _sma3Period.Value = value;
}
public int StopLossTicks
{
get => _stopLossTicks.Value;
set => _stopLossTicks.Value = value;
}
public int TakeProfitTicks
{
get => _takeProfitTicks.Value;
set => _takeProfitTicks.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevSma1 = 0;
_prevSma2 = 0;
_prevSma3 = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma1 = new SimpleMovingAverage { Length = Sma1Period };
var sma2 = new SimpleMovingAverage { Length = Sma2Period };
var sma3 = new SimpleMovingAverage { Length = Sma3Period };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma1, sma2, sma3, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma1);
DrawIndicator(area, sma2);
DrawIndicator(area, sma3);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal sma1, decimal sma2, decimal sma3)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevSma1 == 0 || _prevSma2 == 0 || _prevSma3 == 0)
{
_prevSma1 = sma1;
_prevSma2 = sma2;
_prevSma3 = sma3;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevSma1 = sma1;
_prevSma2 = sma2;
_prevSma3 = sma3;
return;
}
// SMA1 cross SMA2 — entry signal
var crossUp = _prevSma1 <= _prevSma2 && sma1 > sma2;
var crossDown = _prevSma1 >= _prevSma2 && sma1 < sma2;
// Exit on opposite cross
if (Position > 0 && crossDown)
{
SellMarket();
_cooldown = 20;
}
else if (Position < 0 && crossUp)
{
BuyMarket();
_cooldown = 20;
}
// Entry on SMA1/SMA2 cross
if (Position == 0)
{
if (crossUp)
{
BuyMarket();
_cooldown = 20;
}
else if (crossDown)
{
SellMarket();
_cooldown = 20;
}
}
_prevSma1 = sma1;
_prevSma2 = sma2;
_prevSma3 = sma3;
}
}
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 triple_ema_crossover_strategy(Strategy):
"""Triple SMA crossover: trade on SMA1/SMA2 cross with cooldown."""
def __init__(self):
super(triple_ema_crossover_strategy, self).__init__()
self._sma1_period = self.Param("Sma1Period", 5).SetDisplay("SMA1 Period", "Short SMA", "Indicators")
self._sma2_period = self.Param("Sma2Period", 13).SetDisplay("SMA2 Period", "Middle SMA", "Indicators")
self._sma3_period = self.Param("Sma3Period", 21).SetDisplay("SMA3 Period", "Long SMA", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(triple_ema_crossover_strategy, self).OnReseted()
self._prev_sma1 = 0
self._prev_sma2 = 0
self._prev_sma3 = 0
self._cooldown = 0
def OnStarted2(self, time):
super(triple_ema_crossover_strategy, self).OnStarted2(time)
self._prev_sma1 = 0
self._prev_sma2 = 0
self._prev_sma3 = 0
self._cooldown = 0
sma1 = SimpleMovingAverage()
sma1.Length = self._sma1_period.Value
sma2 = SimpleMovingAverage()
sma2.Length = self._sma2_period.Value
sma3 = SimpleMovingAverage()
sma3.Length = self._sma3_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(sma1, sma2, sma3, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, sma1)
self.DrawIndicator(area, sma2)
self.DrawIndicator(area, sma3)
self.DrawOwnTrades(area)
def OnProcess(self, candle, s1, s2, s3):
if candle.State != CandleStates.Finished:
return
s1 = float(s1)
s2 = float(s2)
s3 = float(s3)
if self._prev_sma1 == 0 or self._prev_sma2 == 0 or self._prev_sma3 == 0:
self._prev_sma1 = s1
self._prev_sma2 = s2
self._prev_sma3 = s3
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_sma1 = s1
self._prev_sma2 = s2
self._prev_sma3 = s3
return
cross_up = self._prev_sma1 <= self._prev_sma2 and s1 > s2
cross_down = self._prev_sma1 >= self._prev_sma2 and s1 < s2
# Exit on opposite cross
if self.Position > 0 and cross_down:
self.SellMarket()
self._cooldown = 20
elif self.Position < 0 and cross_up:
self.BuyMarket()
self._cooldown = 20
# Entry
if self.Position == 0:
if cross_up:
self.BuyMarket()
self._cooldown = 20
elif cross_down:
self.SellMarket()
self._cooldown = 20
self._prev_sma1 = s1
self._prev_sma2 = s2
self._prev_sma3 = s3
def CreateClone(self):
return triple_ema_crossover_strategy()