在 GitHub 上查看
Easy Robot 策略
策略概述
Easy Robot 是一套顺势型交易策略,每当上一根小时线收盘后立即判断其方向:若收阳则在新柱开始时做多,若收阴则做空。策略一次只允许持有一个方向的仓位,忠实复刻原始的 MetaTrader 4 专家顾问。
交易规则
- 订阅由 CandleType 参数指定的小时级别蜡烛(默认 H1)。
- 在每根蜡烛结束时比较其收盘价与开盘价:
- 收盘价高于开盘价:在当前无仓位时市价买入。
- 收盘价低于开盘价:在当前空仓时市价卖出。
- 下单数量使用策略的
Volume 属性,与 MQL 版本中通过 CheckVolumeValue 获得 0.01 手起步的逻辑一致。
- 止损和止盈基于周期为 AtrPeriod(默认 14)的 ATR 指标:
- 止损距离 =
ATR * StopFactor。
- 止盈距离 =
ATR * TakeFactor。
- 距离会根据最小报价步长/点值进行修正,确保保护单不会离价格过近。
- 市价单成交后立即调用
SetStopLoss 与 SetTakeProfit 设置保护单,对应 MQL 里 OrderSend 的 sl / tp 参数。
- 当 UseTrailingStop 为 true 时启用拖尾止损:当浮盈达到 TrailingStartPips(MetaTrader 点值)后,每当盈利创新高便按 TrailingStepPips 的间距上移/下移止损,同时保证与经纪商允许的最小距离相符。
- 止损计算优先使用盘口最优买/卖价,若不存在则回退到最新成交价,再次退到蜡烛收盘价,等同于原始代码的
Bid/Ask 行为。
参数说明
| 名称 |
默认值 |
说明 |
TakeFactor |
4.2 |
止盈 ATR 倍数(对应 MQL 输入 TakeFactor)。 |
StopFactor |
4.9 |
止损 ATR 倍数(对应 StopFactor)。 |
UseTrailingStop |
true |
是否启用拖尾止损(对应 UseTstop)。 |
TrailingStartPips |
40 |
启动拖尾所需盈利点数(对应 Tstart)。 |
TrailingStepPips |
19 |
拖尾每次移动的点数(对应 Tstep)。 |
AtrPeriod |
14 |
ATR 指标周期。 |
CandleType |
H1 |
用于信号与 ATR 计算的蜡烛周期。 |
其他说明
- 当仓位回到零时会清空记录的入场价与止损价,以便下一次信号重新计算。
- 最小止损距离通过品种的点值(或价格步长)估算,对应原始包含文件中的
SC 函数。
- 启动时调用一次
StartProtection(),以便平台在需要时触发内置保护机制。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Easy Robot strategy: simple EMA + RSI trend following.
/// Buys when close above EMA and RSI above 50.
/// Sells when close below EMA and RSI below 50.
/// </summary>
public class EasyRobotStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private bool _wasBullish;
private bool _hasPrevSignal;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public EasyRobotStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA period", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_wasBullish = false;
_hasPrevSignal = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrevSignal = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema, decimal rsi)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
var isBullish = close > ema && rsi > 50;
if (_hasPrevSignal && isBullish != _wasBullish)
{
if (isBullish && Position <= 0)
BuyMarket();
else if (!isBullish && close < ema && rsi < 50 && Position >= 0)
SellMarket();
}
_wasBullish = isBullish;
_hasPrevSignal = true;
}
}
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, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class easy_robot_strategy(Strategy):
def __init__(self):
super(easy_robot_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 50) \
.SetDisplay("EMA Period", "EMA period", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._ema = None
self._rsi = None
self._was_bullish = False
self._has_prev_signal = False
@property
def ema_period(self):
return self._ema_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
def OnReseted(self):
super(easy_robot_strategy, self).OnReseted()
self._ema = None
self._rsi = None
self._was_bullish = False
self._has_prev_signal = False
def OnStarted2(self, time):
super(easy_robot_strategy, self).OnStarted2(time)
self._ema = ExponentialMovingAverage()
self._ema.Length = self.ema_period
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
self._has_prev_signal = False
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._ema, self._rsi, self._process_candle)
subscription.Start()
def _process_candle(self, candle, ema_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._ema.IsFormed or not self._rsi.IsFormed:
return
close = float(candle.ClosePrice)
ema_val = float(ema_value)
rsi_val = float(rsi_value)
is_bullish = close > ema_val and rsi_val > 50.0
if self._has_prev_signal and is_bullish != self._was_bullish:
if is_bullish and self.Position <= 0:
self.BuyMarket()
elif not is_bullish and close < ema_val and rsi_val < 50.0 and self.Position >= 0:
self.SellMarket()
self._was_bullish = is_bullish
self._has_prev_signal = True
def CreateClone(self):
return easy_robot_strategy()