複数インジケーターを使ったロング・ショート戦略
この戦略はRSI、Rate of Change、および選択可能な移動平均を使用してロングとショートのシグナルを生成します。エグジットにはATRベースのトレーリングストップを適用します。
詳細
- エントリー条件:
- ロング: RSIが売られすぎと買われすぎの間、ROC > 0、価格がMAの上。
- ショート: 弱気トレンドの確認、ROC < 0、価格がMAの下。
- ロング/ショート: ロングとショート。
- エグジット条件:
- ATRベースのトレーリングストップまたはインジケーターのストップ条件。
- ストップ: ATRトレーリングストップ。
- デフォルト値:
RsiLength= 5RsiOverbought= 70RsiOversold= 44RocLength= 4MaLength= 24MaTypeParam= TEMAAtrLength= 14AtrMultiplier= 2BearishMaLength= 200BearishTrendDuration= 5
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: ロング & ショート
- インジケーター: RSI, ROC, MA, ATR
- ストップ: はい
- 複雑さ: 中
- 時間軸: 任意
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Long and short strategy with RSI, ROC and a selectable moving average.
/// Goes long when RSI is between the oversold and overbought levels, ROC is positive and price is above the MA. Goes short when a bearish
/// trend is confirmed (close below the bearish SMA for BearishTrendDuration bars), ROC is negative and price is below the MA.
/// Positions exit on an ATR trailing stop, a long when RSI rises above overbought and a short when RSI falls below oversold.
/// </summary>
public class LongAndShortWithMultiIndicatorsStrategy : Strategy
{
/// <summary>
/// Moving average types.
/// </summary>
public enum MaTypes
{
/// <summary>
/// Simple moving average.
/// </summary>
SMA,
/// <summary>
/// Exponential moving average.
/// </summary>
EMA,
/// <summary>
/// Weighted moving average.
/// </summary>
WMA,
/// <summary>
/// Double exponential moving average.
/// </summary>
DEMA,
/// <summary>
/// Triple exponential moving average.
/// </summary>
TEMA,
/// <summary>
/// Hull moving average.
/// </summary>
HMA,
/// <summary>
/// Smoothed moving average.
/// </summary>
SMMA,
}
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<decimal> _rsiOversold;
private readonly StrategyParam<int> _rocLength;
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<MaTypes> _maTypeParam;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<int> _bearishMaLength;
private readonly StrategyParam<int> _bearishTrendDuration;
private readonly StrategyParam<DataType> _candleType;
private int _bearishBars;
private decimal? _trailPrice;
/// <summary>
/// RSI period.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// RSI overbought level.
/// </summary>
public decimal RsiOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
/// <summary>
/// ROC period.
/// </summary>
public int RocLength
{
get => _rocLength.Value;
set => _rocLength.Value = value;
}
/// <summary>
/// Moving average period.
/// </summary>
public int MaLength
{
get => _maLength.Value;
set => _maLength.Value = value;
}
/// <summary>
/// Moving average type.
/// </summary>
public MaTypes MaTypeParam
{
get => _maTypeParam.Value;
set => _maTypeParam.Value = value;
}
/// <summary>
/// ATR period.
/// </summary>
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <summary>
/// ATR multiplier of the trailing stop.
/// </summary>
public decimal AtrMultiplier
{
get => _atrMultiplier.Value;
set => _atrMultiplier.Value = value;
}
/// <summary>
/// SMA period that defines the bearish trend.
/// </summary>
public int BearishMaLength
{
get => _bearishMaLength.Value;
set => _bearishMaLength.Value = value;
}
/// <summary>
/// Consecutive closes below the bearish SMA that confirm the bearish trend.
/// </summary>
public int BearishTrendDuration
{
get => _bearishTrendDuration.Value;
set => _bearishTrendDuration.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public LongAndShortWithMultiIndicatorsStrategy()
{
_rsiLength = Param(nameof(RsiLength), 5)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "Indicators");
_rsiOverbought = Param(nameof(RsiOverbought), 70m)
.SetDisplay("RSI Overbought", "RSI overbought level", "Indicators");
_rsiOversold = Param(nameof(RsiOversold), 44m)
.SetDisplay("RSI Oversold", "RSI oversold level", "Indicators");
_rocLength = Param(nameof(RocLength), 4)
.SetGreaterThanZero()
.SetDisplay("ROC Length", "ROC period", "Indicators");
_maLength = Param(nameof(MaLength), 24)
.SetGreaterThanZero()
.SetDisplay("MA Length", "Moving average period", "Indicators");
_maTypeParam = Param(nameof(MaTypeParam), MaTypes.TEMA)
.SetDisplay("MA Type", "Moving average type", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Length", "ATR period", "Risk");
_atrMultiplier = Param(nameof(AtrMultiplier), 2m)
.SetNotNegative()
.SetDisplay("ATR Multiplier", "ATR multiplier of the trailing stop", "Risk");
_bearishMaLength = Param(nameof(BearishMaLength), 200)
.SetGreaterThanZero()
.SetDisplay("Bearish MA Length", "SMA period that defines the bearish trend", "Trend");
_bearishTrendDuration = Param(nameof(BearishTrendDuration), 5)
.SetGreaterThanZero()
.SetDisplay("Bearish Duration", "Consecutive closes below the bearish SMA", "Trend");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_bearishBars = 0;
_trailPrice = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bearishBars = 0;
_trailPrice = null;
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var roc = new RateOfChange { Length = RocLength };
var ma = CreateMa(MaTypeParam, MaLength);
var atr = new AverageTrueRange { Length = AtrLength };
var bearishMa = new SimpleMovingAverage { Length = BearishMaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(rsi, roc, ma, atr, bearishMa, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ma);
DrawIndicator(area, bearishMa);
DrawOwnTrades(area);
}
}
private static IIndicator CreateMa(MaTypes type, int length)
{
return type switch
{
MaTypes.SMA => new SimpleMovingAverage { Length = length },
MaTypes.EMA => new ExponentialMovingAverage { Length = length },
MaTypes.WMA => new WeightedMovingAverage { Length = length },
MaTypes.DEMA => new DoubleExponentialMovingAverage { Length = length },
MaTypes.HMA => new HullMovingAverage { Length = length },
MaTypes.SMMA => new SmoothedMovingAverage { Length = length },
_ => new TripleExponentialMovingAverage { Length = length },
};
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue rsiValue, IIndicatorValue rocValue, IIndicatorValue maValue, IIndicatorValue atrValue, IIndicatorValue bearishMaValue)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (bearishMaValue.IsFormed)
_bearishBars = close < bearishMaValue.GetValue<decimal>() ? _bearishBars + 1 : 0;
if (!rsiValue.IsFormed || !rocValue.IsFormed || !maValue.IsFormed || !atrValue.IsFormed)
return;
var rsi = rsiValue.GetValue<decimal>();
var roc = rocValue.GetValue<decimal>();
var ma = maValue.GetValue<decimal>();
var atr = atrValue.GetValue<decimal>();
if (Position > 0)
{
if (AtrMultiplier > 0)
_trailPrice = Math.Max(_trailPrice ?? decimal.MinValue, close - atr * AtrMultiplier);
if ((_trailPrice is decimal stop && candle.LowPrice <= stop) || rsi > RsiOverbought)
{
SellMarket(Position);
_trailPrice = null;
return;
}
}
else if (Position < 0)
{
if (AtrMultiplier > 0)
_trailPrice = Math.Min(_trailPrice ?? decimal.MaxValue, close + atr * AtrMultiplier);
if ((_trailPrice is decimal stop && candle.HighPrice >= stop) || rsi < RsiOversold)
{
BuyMarket(-Position);
_trailPrice = null;
return;
}
}
if (!IsFormedAndOnlineAndAllowTrading())
return;
var longSignal = rsi > RsiOversold && rsi < RsiOverbought && roc > 0 && close > ma;
var shortSignal = _bearishBars >= BearishTrendDuration && roc < 0 && close < ma;
if (longSignal && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_trailPrice = null;
}
else if (shortSignal && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_trailPrice = null;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import (RelativeStrengthIndex, RateOfChange, AverageTrueRange, SimpleMovingAverage, ExponentialMovingAverage,
WeightedMovingAverage, DoubleExponentialMovingAverage, TripleExponentialMovingAverage,
HullMovingAverage, SmoothedMovingAverage)
from StockSharp.Algo.Strategies import Strategy
class long_and_short_with_multi_indicators_strategy(Strategy):
"""
Long and short strategy with RSI, ROC and a selectable moving average.
Goes long when RSI is between the oversold and overbought levels, ROC is positive and price is above the MA. Goes short when a bearish
trend is confirmed (close below the bearish SMA for BearishTrendDuration bars), ROC is negative and price is below the MA.
Positions exit on an ATR trailing stop, a long when RSI rises above overbought and a short when RSI falls below oversold.
MaTypeParam: SMA, EMA, WMA, DEMA, TEMA, HMA or SMMA.
"""
def __init__(self):
super(long_and_short_with_multi_indicators_strategy, self).__init__()
self._rsi_length = self.Param("RsiLength", 5).SetGreaterThanZero().SetDisplay("RSI Length", "RSI period", "Indicators")
self._rsi_overbought = self.Param("RsiOverbought", 70.0).SetDisplay("RSI Overbought", "RSI overbought level", "Indicators")
self._rsi_oversold = self.Param("RsiOversold", 44.0).SetDisplay("RSI Oversold", "RSI oversold level", "Indicators")
self._roc_length = self.Param("RocLength", 4).SetGreaterThanZero().SetDisplay("ROC Length", "ROC period", "Indicators")
self._ma_length = self.Param("MaLength", 24).SetGreaterThanZero().SetDisplay("MA Length", "Moving average period", "Indicators")
self._ma_type = self.Param("MaTypeParam", "TEMA").SetDisplay("MA Type", "Moving average type", "Indicators")
self._atr_length = self.Param("AtrLength", 14).SetGreaterThanZero().SetDisplay("ATR Length", "ATR period", "Risk")
self._atr_multiplier = self.Param("AtrMultiplier", 2.0).SetNotNegative().SetDisplay("ATR Multiplier", "ATR multiplier of the trailing stop", "Risk")
self._bearish_ma_length = self.Param("BearishMaLength", 200).SetGreaterThanZero().SetDisplay("Bearish MA Length", "SMA period that defines the bearish trend", "Trend")
self._bearish_trend_duration = self.Param("BearishTrendDuration", 5).SetGreaterThanZero().SetDisplay("Bearish Duration", "Consecutive closes below the bearish SMA", "Trend")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._bearish_bars = 0
self._trail_price = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(long_and_short_with_multi_indicators_strategy, self).OnReseted()
self._bearish_bars = 0
self._trail_price = None
def _create_ma(self, ma_type, length):
types = {
"SMA": SimpleMovingAverage,
"EMA": ExponentialMovingAverage,
"WMA": WeightedMovingAverage,
"DEMA": DoubleExponentialMovingAverage,
"HMA": HullMovingAverage,
"SMMA": SmoothedMovingAverage,
}
ma = types.get(str(ma_type), TripleExponentialMovingAverage)()
ma.Length = length
return ma
def OnStarted2(self, time):
super(long_and_short_with_multi_indicators_strategy, self).OnStarted2(time)
self._bearish_bars = 0
self._trail_price = None
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
roc = RateOfChange()
roc.Length = self._roc_length.Value
ma = self._create_ma(self._ma_type.Value, self._ma_length.Value)
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
bearish_ma = SimpleMovingAverage()
bearish_ma.Length = self._bearish_ma_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(rsi, roc, ma, atr, bearish_ma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ma)
self.DrawIndicator(area, bearish_ma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, rsi_value, roc_value, ma_value, atr_value, bearish_ma_value):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
if bearish_ma_value.IsFormed:
self._bearish_bars = self._bearish_bars + 1 if close < bearish_ma_value.GetValue[Decimal](None) else 0
if not rsi_value.IsFormed or not roc_value.IsFormed or not ma_value.IsFormed or not atr_value.IsFormed:
return
rsi = rsi_value.GetValue[Decimal](None)
roc = roc_value.GetValue[Decimal](None)
ma = ma_value.GetValue[Decimal](None)
atr = atr_value.GetValue[Decimal](None)
mult = Decimal(self._atr_multiplier.Value)
overbought = Decimal(self._rsi_overbought.Value)
oversold = Decimal(self._rsi_oversold.Value)
if self.Position > 0:
if mult > 0:
level = close - atr * mult
self._trail_price = level if self._trail_price is None else max(self._trail_price, level)
if (self._trail_price is not None and candle.LowPrice <= self._trail_price) or rsi > overbought:
self.SellMarket(self.Position)
self._trail_price = None
return
elif self.Position < 0:
if mult > 0:
level = close + atr * mult
self._trail_price = level if self._trail_price is None else min(self._trail_price, level)
if (self._trail_price is not None and candle.HighPrice >= self._trail_price) or rsi < oversold:
self.BuyMarket(-self.Position)
self._trail_price = None
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
long_signal = rsi > oversold and rsi < overbought and roc > 0 and close > ma
short_signal = self._bearish_bars >= self._bearish_trend_duration.Value and roc < 0 and close < ma
if long_signal and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._trail_price = None
elif short_signal and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._trail_price = None
def CreateClone(self):
return long_and_short_with_multi_indicators_strategy()