Стратегия RoBoost
Данная стратегия представляет собой адаптацию советника MQL4 RoBoostj на C#. Алгоритм торгует одним инструментом, используя сигналы индикатора RSI в сочетании с простой оценкой ценового импульса. Расчёты выполняются на свечах выбранного типа (по умолчанию часовые свечи).
Логика
- Если цена закрытия предыдущей свечи выше, чем текущей, и значение RSI опускается ниже порога RSI Down, открывается короткая позиция.
- Если цена закрытия предыдущей свечи ниже либо равна текущей, а RSI поднимается выше порога RSI Up, открывается длинная позиция.
- Открытые позиции сопровождаются следующими механизмами управления риском:
- фиксированные уровни Take Profit и Stop Loss в ценовых пунктах;
- опциональный трейлинг-стоп, который активируется после прохождения ценой расстояния Trail Start и сопровождает цену с шагом Trail Step.
Параметры
| Имя | Описание |
|---|---|
CandleType |
Серия свечей для расчётов. |
RsiPeriod |
Период индикатора RSI. |
RsiUp |
Порог RSI для открытия длинных позиций. |
RsiDown |
Порог RSI для открытия коротких позиций. |
TakeProfit |
Расстояние до take profit от цены входа (пункты). |
StopLoss |
Расстояние до stop loss от цены входа (пункты). |
UseTrailing |
Включение логики трейлинг-стопа. |
TrailStart |
Расстояние в пунктах, после которого активируется трейлинг. |
TrailStep |
Расстояние в пунктах между ценой и уровнем трейлинг-стопа. |
Все расстояния задаются в абсолютных ценовых единицах и требуют подбора в зависимости от шага цены конкретного инструмента.
Использование
- Добавьте стратегию в проект или откройте её в StockSharp Designer.
- Настройте параметры в соответствии с предпочтениями.
- Запустите стратегию – она автоматически подпишется на выбранную серию свечей и будет управлять сделками на основе значений RSI и закрытий свечей.
Стратегия предназначена исключительно для образовательных целей и должна быть внимательно протестирована на исторических данных перед использованием на реальных рынках.
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>
/// RSI based strategy converted from the original RoBoostj MQL4 robot.
/// Opens long or short positions depending on price momentum and RSI values.
/// Includes optional trailing stop management.
/// </summary>
public class RoBoostStrategy : Strategy
{
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _rsiUp;
private readonly StrategyParam<int> _rsiDown;
private readonly StrategyParam<bool> _useTrailing;
private readonly StrategyParam<decimal> _trailStart;
private readonly StrategyParam<decimal> _trailStep;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private bool _isLong;
private decimal _trailingStopPrice;
private decimal _previousClose;
private bool _isFirst = true;
/// <summary>
/// Take profit distance from entry price.
/// </summary>
public decimal TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Stop loss distance from entry price.
/// </summary>
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// RSI indicator period length.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI threshold for long entries.
/// </summary>
public int RsiUp
{
get => _rsiUp.Value;
set => _rsiUp.Value = value;
}
/// <summary>
/// RSI threshold for short entries.
/// </summary>
public int RsiDown
{
get => _rsiDown.Value;
set => _rsiDown.Value = value;
}
/// <summary>
/// Enables trailing stop logic.
/// </summary>
public bool UseTrailing
{
get => _useTrailing.Value;
set => _useTrailing.Value = value;
}
/// <summary>
/// Distance at which trailing stop becomes active.
/// </summary>
public decimal TrailStart
{
get => _trailStart.Value;
set => _trailStart.Value = value;
}
/// <summary>
/// Distance maintained from current price when trailing stop is active.
/// </summary>
public decimal TrailStep
{
get => _trailStep.Value;
set => _trailStep.Value = value;
}
/// <summary>
/// Type of candles used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="RoBoostStrategy"/>.
/// </summary>
public RoBoostStrategy()
{
_takeProfit = Param(nameof(TakeProfit), 500m)
.SetGreaterThanZero()
.SetDisplay("Take Profit", "Take profit distance in points", "Risk Management");
_stopLoss = Param(nameof(StopLoss), 1000m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss", "Stop loss distance in points", "Risk Management");
_rsiPeriod = Param(nameof(RsiPeriod), 7)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation length", "Indicator")
.SetOptimize(5, 20, 1);
_rsiUp = Param(nameof(RsiUp), 50)
.SetDisplay("RSI Up", "RSI threshold for longs", "Indicator")
.SetOptimize(45, 70, 5);
_rsiDown = Param(nameof(RsiDown), 50)
.SetDisplay("RSI Down", "RSI threshold for shorts", "Indicator")
.SetOptimize(30, 55, 5);
_useTrailing = Param(nameof(UseTrailing), false)
.SetDisplay("Use Trailing", "Enable trailing stop", "Risk Management");
_trailStart = Param(nameof(TrailStart), 5m)
.SetGreaterThanZero()
.SetDisplay("Trail Start", "Profit distance to activate trailing", "Risk Management");
_trailStep = Param(nameof(TrailStep), 2m)
.SetGreaterThanZero()
.SetDisplay("Trail Step", "Distance between price and trailing stop", "Risk Management");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles used", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0m;
_isLong = false;
_trailingStopPrice = 0m;
_previousClose = 0m;
_isFirst = true;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var currentClose = candle.ClosePrice;
if (_isFirst)
{
_previousClose = currentClose;
_isFirst = false;
return;
}
if (Position == 0)
{
if (_previousClose > currentClose && rsiValue < RsiDown)
{
SellMarket();
_entryPrice = currentClose;
_isLong = false;
_trailingStopPrice = 0m;
}
else if (_previousClose <= currentClose && rsiValue >= RsiUp)
{
BuyMarket();
_entryPrice = currentClose;
_isLong = true;
_trailingStopPrice = 0m;
}
}
else
{
ManagePosition(currentClose);
}
_previousClose = currentClose;
}
private void ManagePosition(decimal currentPrice)
{
if (_entryPrice == 0m)
return;
if (_isLong)
{
var profit = currentPrice - _entryPrice;
if (profit >= TakeProfit || -profit >= StopLoss)
{
SellMarket();
return;
}
if (UseTrailing)
{
if (profit >= TrailStart)
{
var newStop = currentPrice - TrailStep;
if (_trailingStopPrice < newStop)
_trailingStopPrice = newStop;
}
if (_trailingStopPrice != 0m && currentPrice <= _trailingStopPrice)
SellMarket();
}
}
else
{
var profit = _entryPrice - currentPrice;
if (profit >= TakeProfit || -profit >= StopLoss)
{
BuyMarket();
return;
}
if (UseTrailing)
{
if (profit >= TrailStart)
{
var newStop = currentPrice + TrailStep;
if (_trailingStopPrice == 0m || _trailingStopPrice > newStop)
_trailingStopPrice = newStop;
}
if (_trailingStopPrice != 0m && currentPrice >= _trailingStopPrice)
BuyMarket();
}
}
}
}
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class ro_boost_strategy(Strategy):
def __init__(self):
super(ro_boost_strategy, self).__init__()
self._tp = self.Param("TakeProfit", 500.0).SetGreaterThanZero().SetDisplay("Take Profit", "TP distance in points", "Risk")
self._sl = self.Param("StopLoss", 1000.0).SetGreaterThanZero().SetDisplay("Stop Loss", "SL distance in points", "Risk")
self._rsi_period = self.Param("RsiPeriod", 7).SetGreaterThanZero().SetDisplay("RSI Period", "RSI length", "Indicator")
self._rsi_up = self.Param("RsiUp", 50).SetDisplay("RSI Up", "RSI threshold for longs", "Indicator")
self._rsi_down = self.Param("RsiDown", 50).SetDisplay("RSI Down", "RSI threshold for shorts", "Indicator")
self._use_trailing = self.Param("UseTrailing", False).SetDisplay("Use Trailing", "Enable trailing stop", "Risk")
self._trail_start = self.Param("TrailStart", 5.0).SetGreaterThanZero().SetDisplay("Trail Start", "Profit to activate trailing", "Risk")
self._trail_step = self.Param("TrailStep", 2.0).SetGreaterThanZero().SetDisplay("Trail Step", "Trailing distance from price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Candle timeframe", "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(ro_boost_strategy, self).OnReseted()
self._entry_price = 0
self._is_long = False
self._trailing_stop = 0
self._prev_close = 0
self._is_first = True
def OnStarted2(self, time):
super(ro_boost_strategy, self).OnStarted2(time)
self._entry_price = 0
self._is_long = False
self._trailing_stop = 0
self._prev_close = 0
self._is_first = True
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(rsi, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def OnProcess(self, candle, rsi_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
if self._is_first:
self._prev_close = close
self._is_first = False
return
if self.Position == 0:
if self._prev_close > close and rsi_val < self._rsi_down.Value:
self.SellMarket()
self._entry_price = close
self._is_long = False
self._trailing_stop = 0
elif self._prev_close <= close and rsi_val >= self._rsi_up.Value:
self.BuyMarket()
self._entry_price = close
self._is_long = True
self._trailing_stop = 0
else:
self._manage_position(close)
self._prev_close = close
def _manage_position(self, price):
if self._entry_price == 0:
return
if self._is_long:
profit = price - self._entry_price
if profit >= self._tp.Value or -profit >= self._sl.Value:
self.SellMarket()
return
if self._use_trailing.Value:
if profit >= self._trail_start.Value:
new_stop = price - self._trail_step.Value
if self._trailing_stop < new_stop:
self._trailing_stop = new_stop
if self._trailing_stop != 0 and price <= self._trailing_stop:
self.SellMarket()
else:
profit = self._entry_price - price
if profit >= self._tp.Value or -profit >= self._sl.Value:
self.BuyMarket()
return
if self._use_trailing.Value:
if profit >= self._trail_start.Value:
new_stop = price + self._trail_step.Value
if self._trailing_stop == 0 or self._trailing_stop > new_stop:
self._trailing_stop = new_stop
if self._trailing_stop != 0 and price >= self._trailing_stop:
self.BuyMarket()
def CreateClone(self):
return ro_boost_strategy()