Главная
/
Примеры стратегий
Открыть на GitHub
Стратегия ColorMaRsi Trigger MMRec Duplex
Обзор
Стратегия переносит советник MetaTrader Exp_ColorMaRsi-Trigger_MMRec_Duplex.mq5 на высокий уровень API StockSharp. Запускаютс
я два независимых блока MaRsi-Trigger: первый отвечает за длинные сигналы, второй – за короткие. Каждый блок сравнивает быструю
и медленную скользящие средние, а также быстрый и медленный RSI. Итоговый счёт цвета ограничивается диапазоном [-1, 1], что
полностью повторяет работу оригинального индикатора: +1 – бычье состояние, -1 – медвежье, 0 – смешанная картина.
Модуль управления капиталом «MMRec» отслеживает результаты последних сделок в каждом направлении. Если в заданном окне накопилос
ь требуемое число убыточных сделок, следующая позиция открывается уменьшенным объёмом, пока серия не закончится. Тем самым реал
изовано адаптивное изменение размера позиции из библиотеки TradeAlgorithms.mqh.
Торговая логика
Индикаторная цепочка (для каждого блока):
Считаем быструю и медленную скользящие средние (MA_fast/MA_slow) по выбранной цене и таймфрейму.
Считаем быстрый и медленный RSI (RSI_fast/RSI_slow) с отдельными источниками цены.
Формируем цветовой счёт: стартуем с 0, добавляем +1, если MA_fast > MA_slow, иначе -1; аналогично учитываем пару RSI
и ограничиваем результат диапазоном [-1, 1].
Сохраняем историю значений и берём её сдвигом SignalBar, как это делает оригинальный советник.
Длинный блок :
Вход : разрешён только при отсутствии открытой длинной позиции (шорты закрываются заранее). Требуется, чтобы предыдущее зн
ачение (SignalBar + 1) равнялось +1, а текущее (SignalBar) стало ≤ 0, то есть бычий цвет перешёл в нейтральный.
Выход : при появлении отрицательного цвета (-1) на предыдущем баре, если закрытия разрешены параметрами.
Короткий блок :
Вход : возможен лишь при отсутствии открытого шорта (лонги закрываются сначала). Предыдущее значение должно быть -1, теку
щее – ≥ 0, что говорит о смене медвежьего цвета на нейтральный.
Выход : когда предыдущий цвет становится положительным и разрешено закрытие коротких позиций.
Стопы и цели : стоп-лосс и тейк-профит задаются в шагах цены инструмента и проверяются на каждой завершённой свече. Пробой лю
бого уровня мгновенно закрывает позицию.
Управление капиталом : стратегия сохраняет результат каждой завершённой сделки по направлениям. Если среди последних History Depth сделок число убытков достигает LossTrigger, следующий вход выполняется сокращённым объёмом, иначе используется базовый объём.
Параметры
Группа
Имя
Описание
Значение по умолчанию
Длинный блок
LongCandleType
Таймфрейм, на котором работает длинный MaRsi-Trigger.
H4
LongAllowOpen / LongAllowClose
Разрешение на открытие / закрытие длинных позиций.
true
LongStopLossPoints / LongTakeProfitPoints
Дистанции стоп-лосса и тейк-профита в шагах цены (0 отключает уровень).
1000 / 2000
LongSignalBar
Сдвиг по закрытым барам при чтении индикатора.
1
LongRsiPeriod / LongRsiLongPeriod
Периоды быстрого и медленного RSI.
3 / 13
LongMaPeriod / LongMaLongPeriod
Периоды быстрой и медленной скользящих средних.
5 / 10
LongRsiPrice / LongRsiLongPrice
Источник цены для быстрого / медленного RSI.
Weighted / Median
LongMaPrice / LongMaLongPrice
Источник цены для быстрой / медленной MA.
Close / Close
LongMaType / LongMaLongType
Алгоритмы усреднения (Simple, Exponential, Smoothed, Weighted).
Exponential / Exponential
Управление капиталом
LongNormalVolume / LongReducedVolume
Базовый и пониженный объём длинных сделок.
0.1 / 0.01
LongHistoryDepth
Количество последних длинных сделок в окне анализа.
5
LongLossTrigger
Минимальное число убытков в окне для перехода на пониженный объём.
3
Группа
Имя
Описание
Значение по умолчанию
Короткий блок
ShortCandleType
Таймфрейм для короткого блока MaRsi-Trigger.
H4
ShortAllowOpen / ShortAllowClose
Разрешение на открытие / закрытие коротких позиций.
true
ShortStopLossPoints / ShortTakeProfitPoints
Дистанции стоп-лосса и тейк-профита в шагах цены (0 отключает уровень).
1000 / 2000
ShortSignalBar
Сдвиг по закрытым барам при чтении индикатора.
1
ShortRsiPeriod / ShortRsiLongPeriod
Периоды быстрого и медленного RSI.
3 / 13
ShortMaPeriod / ShortMaLongPeriod
Периоды быстрой и медленной скользящих средних.
5 / 10
ShortRsiPrice / ShortRsiLongPrice
Источник цены для быстрого / медленного RSI.
Weighted / Median
ShortMaPrice / ShortMaLongPrice
Источник цены для быстрой / медленной MA.
Close / Close
ShortMaType / ShortMaLongType
Алгоритмы усреднения.
Exponential / Exponential
Управление капиталом
ShortNormalVolume / ShortReducedVolume
Базовый и пониженный объём коротких сделок.
0.1 / 0.01
ShortHistoryDepth
Количество последних коротких сделок в окне анализа.
5
ShortLossTrigger
Минимальное число убытков для перехода на пониженный объём.
3
Примечания
Типы цен полностью соответствуют обозначениям MetaTrader. Например, Weighted вычисляется как (High + Low + 2 * Close) / 4,
а Typical – как (High + Low + Close) / 3.
Если оба блока используют один и тот же таймфрейм (значение по умолчанию), создаётся одна подписка на свечи, питающая оба расчё
та.
Установка LossTrigger в 0 моментально включает пониженный объём, что повторяет поведение оригинального модуля MMRec.
Заявки регистрируются по рынку, поэтому параметр Deviation из MetaTrader не требуется.
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;
public class ColorMaRsiTriggerMmRecDuplexStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public ColorMaRsiTriggerMmRecDuplexStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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_ma_rsi_trigger_mm_rec_duplex_strategy(Strategy):
def __init__(self):
super(color_ma_rsi_trigger_mm_rec_duplex_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(color_ma_rsi_trigger_mm_rec_duplex_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(color_ma_rsi_trigger_mm_rec_duplex_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return color_ma_rsi_trigger_mm_rec_duplex_strategy()