Smart AC Trader переносит одноимённого эксперта MetaTrader в экосистему StockSharp. В исходном советнике рассчитывалась относительная сила валют в каждой паре и открывались сделки, когда базовая валюта становилась сильнее котируемой. В StockSharp мы сохраняем идею торговли по силе, но применяем её к одному инструменту, используя комбинацию экспоненциальных скользящих средних (EMA) и индикатора скорости изменения (ROC):
Быстрая EMA отражает краткосрочное направление.
Медленная EMA показывает основную тенденцию.
ROC подтверждает наличие импульса в сторону тренда, прежде чем стратегия разрешит вход.
После открытия позиции стратегия управляет сделкой с помощью стоп-лосса, тейк-профита, трейлинг-стопа и логики перевода в безубыток, что перекликается с широкой системой управления капиталом оригинального эксперта.
Логика торговли
Подписка на выбранный тип свечей и расчёт быстрой EMA, медленной EMA и ROC по закрытию свечи.
Открытие длинной позиции, когда быстрая EMA находится выше медленной и значение ROC не ниже порога для покупок. При наличии короткой позиции она закрывается перед разворотом.
Открытие короткой позиции, когда быстрая EMA находится ниже медленной и значение ROC не выше отрицательного порога для продаж. При наличии длинной позиции она закрывается перед разворотом.
Управление открытой позицией на каждой завершённой свече:
Закрытие по тейк-профиту или стоп-лоссу, выраженным в шагах цены.
При необходимости перевод в безубыток: после достижения заданной прибыли стратегия запоминает смещённый уровень и закрывает позицию при возврате цены.
При необходимости использование трейлинг-стопа с заданной дистанцией от максимума (для лонга) или минимума (для шорта), достигнутых после входа.
Параметры
Параметр
Описание
Fast EMA
Период быстрой EMA.
Slow EMA
Период медленной EMA.
ROC Period
Длина окна для индикатора ROC.
Buy Momentum
Минимальное положительное значение ROC для открытия лонга.
Sell Momentum
Минимальное отрицательное значение ROC (по модулю) для открытия шорта.
Stop Loss
Дистанция стоп-лосса в шагах цены.
Take Profit
Дистанция тейк-профита в шагах цены.
Use Trailing
Включение трейлинг-стопа.
Trailing
Дистанция трейлинг-стопа в шагах цены.
Use Break Even
Включение перевода в безубыток.
Break Even Trigger
Прибыль в шагах цены, необходимая для активации безубытка.
Break Even Offset
Смещение, сохраняемое после активации безубытка.
Candle Type
Тип свечей, используемых в расчётах.
Примечания
При запуске вызывается Strategy.StartProtection(), что соответствует требованиям проекта по защите позиций.
Размер позиции определяется через свойство Strategy.Volume. При смене направления учитывается текущая позиция, поэтому противоположные сигналы закрывают старую сделку и открывают новую.
Все расстояния заданы в шагах цены — это аналог пунктов (pip) из MetaTrader. Перед использованием убедитесь, что у инструмента задан корректный PriceStep.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Smart AC Trader: EMA trend + ROC momentum filter.
/// Buys when fast EMA above slow EMA and ROC positive.
/// Sells when fast EMA below slow EMA and ROC negative.
/// </summary>
public class SmartAcTraderStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _rocPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public int RocPeriod
{
get => _rocPeriod.Value;
set => _rocPeriod.Value = value;
}
public SmartAcTraderStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_rocPeriod = Param(nameof(RocPeriod), 13)
.SetGreaterThanZero()
.SetDisplay("ROC Period", "Rate of Change period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var roc = new RateOfChange { Length = RocPeriod };
decimal? prevFast = null;
decimal? prevSlow = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, roc, (candle, fastVal, slowVal, rocVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevFast.HasValue && prevSlow.HasValue)
{
var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;
if (crossUp && rocVal > 0 && Position <= 0)
BuyMarket();
else if (crossDown && rocVal < 0 && Position >= 0)
SellMarket();
}
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
}
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, RateOfChange
from StockSharp.Algo.Strategies import Strategy
class smart_ac_trader_strategy(Strategy):
def __init__(self):
super(smart_ac_trader_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._fast_period = self.Param("FastPeriod", 10) \
.SetGreaterThanZero() \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetGreaterThanZero() \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._roc_period = self.Param("RocPeriod", 13) \
.SetGreaterThanZero() \
.SetDisplay("ROC Period", "Rate of Change period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(smart_ac_trader_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(smart_ac_trader_strategy, self).OnStarted2(time)
self._fast_ind = ExponentialMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = ExponentialMovingAverage()
self._slow_ind.Length = self._slow_period.Value
self._roc_ind = RateOfChange()
self._roc_ind.Length = self._roc_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._roc_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value, roc_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
fast_val = float(fast_value)
slow_val = float(slow_value)
roc_val = float(roc_value)
if self._prev_fast is not None and self._prev_slow is not None:
cross_up = self._prev_fast <= self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast >= self._prev_slow and fast_val < slow_val
if cross_up and roc_val > 0 and self.Position <= 0:
self.BuyMarket()
elif cross_down and roc_val < 0 and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return smart_ac_trader_strategy()