在 GitHub 上查看
Hercules 策略
Hercules 策略是 MetaTrader 专家顾问 Hercules v1.3 (Majors) 的 StockSharp 版本。策略利用快慢均线交叉,并结合多时间框架过滤条件,同时为每个信号管理两个独立的止盈目标。
交易逻辑
- 信号准备:计算基于收盘价的 EMA(1) 与基于开盘价的 SMA(72),识别最近一根或倒数第二根K线发生的交叉。将两条均线的值求平均得到交叉价格,再向上/向下偏移
TriggerPips 形成触发价格。
- 执行窗口:交叉出现后,信号在两个完整K线周期内有效。只有当当前收盘价在该窗口内突破触发价时才会下单。
- 过滤条件:
- H1 RSI(默认周期
RsiPeriod,典型价输入)在做多时必须高于 RsiUpper,做空时必须低于 RsiLower。
- 当前收盘价需要突破
LookbackMinutes 分钟窗口内的最高/最低价。
- 日线 Envelope(SMA 24,偏移
DailyEnvelopeDeviation%)要求收盘价突破带状区间的对应边界。
- H4 Envelope(SMA 96,偏移
H4EnvelopeDeviation%)提供第二层趋势确认。
- 风险控制:止损位设置在向前数第四根K线的高点或低点。下单量可以固定为
OrderVolume,也可以根据 RiskPercent 占组合价值的比例自动计算。
- 仓位管理:每次信号会开出两笔相同手数的市价单。第一笔在
TakeProfitFirstPips 处止盈,第二笔在 TakeProfitSecondPips 处止盈,TrailingStopPips 用于两笔仓位的移动止损。当止损或两个止盈全部触发后,策略会在 BlackoutHours 小时内暂停新的交易。
参数
| 参数 |
说明 |
OrderVolume |
每笔市价单的基础手数。 |
UseMoneyManagement |
是否根据止损距离和 RiskPercent 自动调整手数。 |
RiskPercent |
每笔交易允许承担的组合风险百分比。 |
TriggerPips |
触发价与交叉价之间的距离。 |
TrailingStopPips |
移动止损的点数。 |
TakeProfitFirstPips |
第一目标的止盈距离。 |
TakeProfitSecondPips |
第二目标的止盈距离。 |
FastPeriod |
快速 EMA 的周期。 |
SlowPeriod |
慢速 SMA 的周期。 |
RsiPeriod |
RSI 滤波器的周期。 |
RsiUpper / RsiLower |
多空方向使用的 RSI 阈值。 |
LookbackMinutes |
计算近期高低点的时间窗口(分钟)。 |
BlackoutHours |
交易完成后冻结新信号的小时数。 |
DailyEnvelopePeriod / DailyEnvelopeDeviation |
日线 Envelope 的参数。 |
H4EnvelopePeriod / H4EnvelopeDeviation |
H4 Envelope 的参数。 |
CandleType |
主交易时间框架。 |
RsiTimeFrame |
计算 RSI 使用的时间框架。 |
DailyTimeFrame |
计算日线 Envelope 的时间框架。 |
H4TimeFrame |
计算 H4 Envelope 的时间框架。 |
文件结构
CS/HerculesStrategy.cs – Hercules 策略的 C# 实现。
README.md – 英文说明。
README_ru.md – 俄文说明。
README_zh.md – 中文说明。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class HerculesStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevRsi; private bool _hasPrev;
private int _cooldown;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public HerculesStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14).SetDisplay("RSI Period", "RSI lookback", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsi)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
if (!_hasPrev) { _prevRsi = rsi; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevRsi = rsi;
return;
}
if (_prevRsi <= 30 && rsi > 30 && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (_prevRsi >= 70 && rsi < 70 && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_prevRsi = rsi;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class hercules_strategy(Strategy):
def __init__(self):
super(hercules_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14).SetDisplay("RSI Period", "RSI lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_rsi = 0.0; self._has_prev = False; self._cooldown = 0
@property
def rsi_period(self): return self._rsi_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(hercules_strategy, self).OnReseted()
self._prev_rsi = 0.0; self._has_prev = False; self._cooldown = 0
def OnStarted2(self, time):
super(hercules_strategy, self).OnStarted2(time)
self._has_prev = False; self._cooldown = 0
rsi = RelativeStrengthIndex(); rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, self.process_candle).Start()
def process_candle(self, candle, rsi):
if candle.State != CandleStates.Finished: return
if not self.IsFormedAndOnlineAndAllowTrading(): return
rsi_val = float(rsi)
if not self._has_prev:
self._prev_rsi = rsi_val; self._has_prev = True; return
if self._cooldown > 0:
self._cooldown -= 1; self._prev_rsi = rsi_val; return
if self._prev_rsi <= 30 and rsi_val > 30 and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume); self._cooldown = 2
elif self._prev_rsi >= 70 and rsi_val < 70 and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume); self._cooldown = 2
self._prev_rsi = rsi_val
def CreateClone(self): return hercules_strategy()