X2MA JJRSX 策略
该策略结合双移动平均线趋势过滤器和基于RSI的入场触发。 通过比较快慢均线在较高时间框架上确定趋势。 当RSI在较低时间框架上脱离超卖或超买区域并顺着趋势时执行交易。
细节
- 入场条件:
- 多头:趋势向上且RSI上穿
Oversold - 空头:趋势向下且RSI下穿
Overbought
- 多头:趋势向上且RSI上穿
- 多/空:均可
- 出场条件:相反的RSI阈值或趋势反转
- 止损:无
- 默认参数:
TrendCandleType= 4小时K线SignalCandleType= 30分钟K线FastMaPeriod= 12SlowMaPeriod= 5RsiPeriod= 8Overbought= 70Oversold= 30
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>
/// Strategy that combines dual moving average trend filter with RSI entries.
/// </summary>
public class X2MaJjrsxStrategy : Strategy
{
private readonly StrategyParam<DataType> _trendCandleType;
private readonly StrategyParam<DataType> _signalCandleType;
private readonly StrategyParam<int> _fastMaPeriod;
private readonly StrategyParam<int> _slowMaPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<decimal> _oversold;
private readonly StrategyParam<bool> _useLong;
private readonly StrategyParam<bool> _useShort;
private SimpleMovingAverage _fastMa;
private SimpleMovingAverage _slowMa;
private RelativeStrengthIndex _rsi;
private int _trend;
private decimal _prevRsi;
/// <summary>
/// Constructor.
/// </summary>
public X2MaJjrsxStrategy()
{
_trendCandleType = Param(nameof(TrendCandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Trend Candle Type", "Timeframe for trend moving averages", "General");
_signalCandleType = Param(nameof(SignalCandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Signal Candle Type", "Timeframe for entry signals", "General");
_fastMaPeriod = Param(nameof(FastMaPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Fast MA Period", "Length of fast moving average", "Indicators");
_slowMaPeriod = Param(nameof(SlowMaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Slow MA Period", "Length of slow moving average", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Length of RSI filter", "Indicators");
_overbought = Param(nameof(Overbought), 75m)
.SetDisplay("Overbought", "RSI overbought threshold", "Risk");
_oversold = Param(nameof(Oversold), 25m)
.SetDisplay("Oversold", "RSI oversold threshold", "Risk");
_useLong = Param(nameof(UseLong), true)
.SetDisplay("Enable Long", "Allow long trades", "General");
_useShort = Param(nameof(UseShort), true)
.SetDisplay("Enable Short", "Allow short trades", "General");
}
/// <summary>
/// Candle type for trend calculation.
/// </summary>
public DataType TrendCandleType
{
get => _trendCandleType.Value;
set => _trendCandleType.Value = value;
}
/// <summary>
/// Candle type for entry signals.
/// </summary>
public DataType SignalCandleType
{
get => _signalCandleType.Value;
set => _signalCandleType.Value = value;
}
/// <summary>
/// Fast moving average period.
/// </summary>
public int FastMaPeriod
{
get => _fastMaPeriod.Value;
set => _fastMaPeriod.Value = value;
}
/// <summary>
/// Slow moving average period.
/// </summary>
public int SlowMaPeriod
{
get => _slowMaPeriod.Value;
set => _slowMaPeriod.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI overbought level.
/// </summary>
public decimal Overbought
{
get => _overbought.Value;
set => _overbought.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal Oversold
{
get => _oversold.Value;
set => _oversold.Value = value;
}
/// <summary>
/// Enable long trades.
/// </summary>
public bool UseLong
{
get => _useLong.Value;
set => _useLong.Value = value;
}
/// <summary>
/// Enable short trades.
/// </summary>
public bool UseShort
{
get => _useShort.Value;
set => _useShort.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, TrendCandleType), (Security, SignalCandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_trend = 0;
_prevRsi = 50m;
_fastMa = null;
_slowMa = null;
_rsi = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastMa = new SimpleMovingAverage { Length = FastMaPeriod };
_slowMa = new SimpleMovingAverage { Length = SlowMaPeriod };
_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
_prevRsi = 50m;
var trendSub = SubscribeCandles(TrendCandleType);
trendSub.Bind(_fastMa, _slowMa, ProcessTrend).Start();
var signalSub = SubscribeCandles(SignalCandleType);
signalSub.Bind(_rsi, ProcessSignal).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, signalSub);
DrawIndicator(area, _fastMa);
DrawIndicator(area, _slowMa);
DrawIndicator(area, _rsi);
DrawOwnTrades(area);
}
}
private void ProcessTrend(ICandleMessage candle, decimal fastMa, decimal slowMa)
{
if (candle.State != CandleStates.Finished)
return;
_trend = fastMa > slowMa ? 1 : fastMa < slowMa ? -1 : _trend;
}
private void ProcessSignal(ICandleMessage candle, decimal rsi)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevRsi = rsi;
return;
}
if (UseLong && _trend > 0 && Position <= 0 && _prevRsi < Oversold && rsi >= Oversold)
BuyMarket();
if (UseShort && _trend < 0 && Position >= 0 && _prevRsi > Overbought && rsi <= Overbought)
SellMarket();
if (Position > 0 && (rsi >= Overbought || _trend < 0))
SellMarket();
if (Position < 0 && (rsi <= Oversold || _trend > 0))
BuyMarket();
_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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class x2_ma_jjrsx_strategy(Strategy):
def __init__(self):
super(x2_ma_jjrsx_strategy, self).__init__()
self._trend_candle_type = self.Param("TrendCandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Trend Candle Type", "Timeframe for trend moving averages", "General")
self._signal_candle_type = self.Param("SignalCandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Signal Candle Type", "Timeframe for entry signals", "General")
self._fast_ma_period = self.Param("FastMaPeriod", 5) \
.SetDisplay("Fast MA Period", "Length of fast moving average", "Indicators")
self._slow_ma_period = self.Param("SlowMaPeriod", 20) \
.SetDisplay("Slow MA Period", "Length of slow moving average", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "Length of RSI filter", "Indicators")
self._overbought = self.Param("Overbought", 75.0) \
.SetDisplay("Overbought", "RSI overbought threshold", "Risk")
self._oversold = self.Param("Oversold", 25.0) \
.SetDisplay("Oversold", "RSI oversold threshold", "Risk")
self._use_long = self.Param("UseLong", True) \
.SetDisplay("Enable Long", "Allow long trades", "General")
self._use_short = self.Param("UseShort", True) \
.SetDisplay("Enable Short", "Allow short trades", "General")
self._trend = 0
self._prev_rsi = 50.0
@property
def trend_candle_type(self):
return self._trend_candle_type.Value
@property
def signal_candle_type(self):
return self._signal_candle_type.Value
@property
def fast_ma_period(self):
return self._fast_ma_period.Value
@property
def slow_ma_period(self):
return self._slow_ma_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def overbought(self):
return self._overbought.Value
@property
def oversold(self):
return self._oversold.Value
@property
def use_long(self):
return self._use_long.Value
@property
def use_short(self):
return self._use_short.Value
def OnReseted(self):
super(x2_ma_jjrsx_strategy, self).OnReseted()
self._trend = 0
self._prev_rsi = 50.0
def OnStarted2(self, time):
super(x2_ma_jjrsx_strategy, self).OnStarted2(time)
self._trend = 0
self._prev_rsi = 50.0
fast_ma = SimpleMovingAverage()
fast_ma.Length = int(self.fast_ma_period)
slow_ma = SimpleMovingAverage()
slow_ma.Length = int(self.slow_ma_period)
rsi = RelativeStrengthIndex()
rsi.Length = int(self.rsi_period)
trend_sub = self.SubscribeCandles(self.trend_candle_type)
trend_sub.Bind(fast_ma, slow_ma, self._process_trend).Start()
signal_sub = self.SubscribeCandles(self.signal_candle_type)
signal_sub.Bind(rsi, self._process_signal).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, signal_sub)
self.DrawIndicator(area, fast_ma)
self.DrawIndicator(area, slow_ma)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def _process_trend(self, candle, fast_ma, slow_ma):
if candle.State != CandleStates.Finished:
return
fast_ma = float(fast_ma)
slow_ma = float(slow_ma)
if fast_ma > slow_ma:
self._trend = 1
elif fast_ma < slow_ma:
self._trend = -1
def _process_signal(self, candle, rsi):
if candle.State != CandleStates.Finished:
return
rsi = float(rsi)
ob = float(self.overbought)
os_val = float(self.oversold)
if self.use_long and self._trend > 0 and self.Position <= 0 and self._prev_rsi < os_val and rsi >= os_val:
self.BuyMarket()
if self.use_short and self._trend < 0 and self.Position >= 0 and self._prev_rsi > ob and rsi <= ob:
self.SellMarket()
if self.Position > 0 and (rsi >= ob or self._trend < 0):
self.SellMarket()
if self.Position < 0 and (rsi <= os_val or self._trend > 0):
self.BuyMarket()
self._prev_rsi = rsi
def CreateClone(self):
return x2_ma_jjrsx_strategy()