RoBoost 策略
该策略是将原始 MQL4 智能交易系统 RoBoostj 转换为 C# 的实现。 它基于 RSI 指标结合简单的价格动量判断,在选定的 K 线周期上运行 (默认使用 1 小时 K 线)。
策略逻辑
- 当上一根 K 线收盘价高于当前 K 线收盘价且 RSI 低于 RSI Down 阈值时, 策略开仓做空。
- 当上一根 K 线收盘价低于或等于当前收盘价且 RSI 高于 RSI Up 阈值时, 策略开仓做多。
- 持仓通过以下风险控制工具管理:
- 固定的 Take Profit 和 Stop Loss,单位为价格点;
- 可选的跟踪止损,当盈利达到 Trail Start 距离后启用, 止损价与当前价格保持 Trail Step 的间隔。
参数
| 名称 | 说明 |
|---|---|
CandleType |
用于计算的 K 线类型。 |
RsiPeriod |
RSI 指标的周期长度。 |
RsiUp |
触发做多的 RSI 阈值。 |
RsiDown |
触发做空的 RSI 阈值。 |
TakeProfit |
从入场价起的止盈距离(点数)。 |
StopLoss |
从入场价起的止损距离(点数)。 |
UseTrailing |
是否启用跟踪止损。 |
TrailStart |
达到该盈利距离后开始跟踪止损。 |
TrailStep |
跟踪止损与当前价格之间保持的距离。 |
所有距离均以绝对价格单位表示,需要根据交易品种的最小变动单位进行调整。
使用方法
- 将策略添加到项目中或在 StockSharp Designer 中打开。
- 根据个人需求配置参数。
- 启动策略,系统会自动订阅所选 K 线并依据 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()