Manadi 売買 EMA MACD RSI 戦略
MACD と RSI の確認を伴う EMA クロスオーバー戦略。固定パーセントのストップロスとテイクプロフィットで市場にエントリーします。
詳細
- エントリー条件: MACD が一致し RSI が範囲内にある状態での EMA クロスオーバー。
- ロング/ショート: 両方向。
- エグジット条件: パーセントベースのストップロスまたはテイクプロフィット。
- ストップ: パーセントベース。
- デフォルト値:
FastEmaLength= 9SlowEmaLength= 21RsiLength= 14RsiUpperLong= 70RsiLowerLong= 40RsiUpperShort= 60RsiLowerShort= 30MacdFast= 12MacdSlow= 26MacdSignal= 9TakeProfitPercent= 0.03StopLossPercent= 0.015CandleType= TimeSpan.FromMinutes(1)
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: 両方
- インジケーター: EMA、MACD、RSI
- ストップ: はい
- 複雑さ: 初心者
- 時間軸: イントラデイ (1m)
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// Manadi Buy Sell EMA MACD RSI strategy.
/// The fast EMA crossing above the slow EMA with MACD above its signal line and RSI between RsiLowerLong and RsiUpperLong goes long.
/// The fast EMA crossing below the slow EMA with MACD below its signal line and RSI between RsiLowerShort and RsiUpperShort goes short.
/// An opposite signal reverses the position. TakeProfitPercent and StopLossPercent are fractions of the entry price (0.03 = 3%).
/// </summary>
public class ManadiBuySellStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _rsiUpperLong;
private readonly StrategyParam<decimal> _rsiLowerLong;
private readonly StrategyParam<decimal> _rsiUpperShort;
private readonly StrategyParam<decimal> _rsiLowerShort;
private readonly StrategyParam<int> _macdFast;
private readonly StrategyParam<int> _macdSlow;
private readonly StrategyParam<int> _macdSignal;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
/// <summary>
/// Fast EMA length.
/// </summary>
public int FastEmaLength
{
get => _fastEmaLength.Value;
set => _fastEmaLength.Value = value;
}
/// <summary>
/// Slow EMA length.
/// </summary>
public int SlowEmaLength
{
get => _slowEmaLength.Value;
set => _slowEmaLength.Value = value;
}
/// <summary>
/// RSI length.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// Upper RSI bound for longs.
/// </summary>
public decimal RsiUpperLong
{
get => _rsiUpperLong.Value;
set => _rsiUpperLong.Value = value;
}
/// <summary>
/// Lower RSI bound for longs.
/// </summary>
public decimal RsiLowerLong
{
get => _rsiLowerLong.Value;
set => _rsiLowerLong.Value = value;
}
/// <summary>
/// Upper RSI bound for shorts.
/// </summary>
public decimal RsiUpperShort
{
get => _rsiUpperShort.Value;
set => _rsiUpperShort.Value = value;
}
/// <summary>
/// Lower RSI bound for shorts.
/// </summary>
public decimal RsiLowerShort
{
get => _rsiLowerShort.Value;
set => _rsiLowerShort.Value = value;
}
/// <summary>
/// MACD fast EMA length.
/// </summary>
public int MacdFast
{
get => _macdFast.Value;
set => _macdFast.Value = value;
}
/// <summary>
/// MACD slow EMA length.
/// </summary>
public int MacdSlow
{
get => _macdSlow.Value;
set => _macdSlow.Value = value;
}
/// <summary>
/// MACD signal line length.
/// </summary>
public int MacdSignal
{
get => _macdSignal.Value;
set => _macdSignal.Value = value;
}
/// <summary>
/// Take profit as a fraction of the entry price.
/// </summary>
public decimal TakeProfitPercent
{
get => _takeProfitPercent.Value;
set => _takeProfitPercent.Value = value;
}
/// <summary>
/// Stop loss as a fraction of the entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public ManadiBuySellStrategy()
{
_fastEmaLength = Param(nameof(FastEmaLength), 9)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA length", "Indicators");
_slowEmaLength = Param(nameof(SlowEmaLength), 21)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA length", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI length", "Indicators");
_rsiUpperLong = Param(nameof(RsiUpperLong), 70m)
.SetDisplay("RSI Upper Long", "Upper RSI bound for longs", "RSI");
_rsiLowerLong = Param(nameof(RsiLowerLong), 40m)
.SetDisplay("RSI Lower Long", "Lower RSI bound for longs", "RSI");
_rsiUpperShort = Param(nameof(RsiUpperShort), 60m)
.SetDisplay("RSI Upper Short", "Upper RSI bound for shorts", "RSI");
_rsiLowerShort = Param(nameof(RsiLowerShort), 30m)
.SetDisplay("RSI Lower Short", "Lower RSI bound for shorts", "RSI");
_macdFast = Param(nameof(MacdFast), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "MACD fast EMA length", "MACD");
_macdSlow = Param(nameof(MacdSlow), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "MACD slow EMA length", "MACD");
_macdSignal = Param(nameof(MacdSignal), 9)
.SetGreaterThanZero()
.SetDisplay("MACD Signal", "MACD signal line length", "MACD");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 0.03m)
.SetNotNegative()
.SetDisplay("Take Profit", "Take profit as a fraction of the entry price", "Risk");
_stopLossPercent = Param(nameof(StopLossPercent), 0.015m)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop loss as a fraction of the entry price", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).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();
_prevFast = null;
_prevSlow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFast },
LongMa = { Length = MacdSlow },
},
SignalMa = { Length = MacdSignal }
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(fastEma, slowEma, rsi, macd, ProcessCandle)
.Start();
// The parameters are fractions, so 0.03 is a 3% distance.
StartProtection(
new Unit(TakeProfitPercent * 100m, UnitTypes.Percent),
new Unit(StopLossPercent * 100m, UnitTypes.Percent),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
{
DrawIndicator(oscillators, rsi);
DrawIndicator(oscillators, macd);
}
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue fastValue, IIndicatorValue slowValue, IIndicatorValue rsiValue, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!fastValue.IsFormed || !slowValue.IsFormed || !rsiValue.IsFormed || !macdValue.IsFormed)
return;
if (macdValue is not IMovingAverageConvergenceDivergenceSignalValue { Macd: decimal macdLine, Signal: decimal signalLine })
return;
var fast = fastValue.GetValue<decimal>();
var slow = slowValue.GetValue<decimal>();
var prevFast = _prevFast;
var prevSlow = _prevSlow;
_prevFast = fast;
_prevSlow = slow;
if (prevFast is not decimal pf || prevSlow is not decimal ps)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var rsi = rsiValue.GetValue<decimal>();
var longSignal = pf <= ps && fast > slow && macdLine > signalLine && rsi > RsiLowerLong && rsi < RsiUpperLong;
var shortSignal = pf >= ps && fast < slow && macdLine < signalLine && rsi > RsiLowerShort && rsi < RsiUpperShort;
if (longSignal && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (shortSignal && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage, RelativeStrengthIndex, MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
class manadi_buy_sell_strategy(Strategy):
"""
Manadi Buy Sell EMA MACD RSI strategy.
The fast EMA crossing above the slow EMA with MACD above its signal line and RSI between RsiLowerLong and RsiUpperLong goes long.
The fast EMA crossing below the slow EMA with MACD below its signal line and RSI between RsiLowerShort and RsiUpperShort goes short.
An opposite signal reverses the position. TakeProfitPercent and StopLossPercent are fractions of the entry price (0.03 = 3%).
"""
def __init__(self):
super(manadi_buy_sell_strategy, self).__init__()
self._fast_ema_length = self.Param("FastEmaLength", 9).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA length", "Indicators")
self._slow_ema_length = self.Param("SlowEmaLength", 21).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA length", "Indicators")
self._rsi_length = self.Param("RsiLength", 14).SetGreaterThanZero().SetDisplay("RSI Length", "RSI length", "Indicators")
self._rsi_upper_long = self.Param("RsiUpperLong", 70.0).SetDisplay("RSI Upper Long", "Upper RSI bound for longs", "RSI")
self._rsi_lower_long = self.Param("RsiLowerLong", 40.0).SetDisplay("RSI Lower Long", "Lower RSI bound for longs", "RSI")
self._rsi_upper_short = self.Param("RsiUpperShort", 60.0).SetDisplay("RSI Upper Short", "Upper RSI bound for shorts", "RSI")
self._rsi_lower_short = self.Param("RsiLowerShort", 30.0).SetDisplay("RSI Lower Short", "Lower RSI bound for shorts", "RSI")
self._macd_fast = self.Param("MacdFast", 12).SetGreaterThanZero().SetDisplay("MACD Fast", "MACD fast EMA length", "MACD")
self._macd_slow = self.Param("MacdSlow", 26).SetGreaterThanZero().SetDisplay("MACD Slow", "MACD slow EMA length", "MACD")
self._macd_signal = self.Param("MacdSignal", 9).SetGreaterThanZero().SetDisplay("MACD Signal", "MACD signal line length", "MACD")
self._take_profit_percent = self.Param("TakeProfitPercent", 0.03).SetNotNegative().SetDisplay("Take Profit", "Take profit as a fraction of the entry price", "Risk")
self._stop_loss_percent = self.Param("StopLossPercent", 0.015).SetNotNegative().SetDisplay("Stop Loss", "Stop loss as a fraction of the entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._prev_fast = None
self._prev_slow = None
def OnReseted(self):
super(manadi_buy_sell_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(manadi_buy_sell_strategy, self).OnStarted2(time)
self._reset_state()
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self._fast_ema_length.Value
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self._slow_ema_length.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self._macd_fast.Value
macd.Macd.LongMa.Length = self._macd_slow.Value
macd.SignalMa.Length = self._macd_signal.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(fast_ema, slow_ema, rsi, macd, self._process_candle).Start()
# The parameters are fractions, so 0.03 is a 3% distance.
hundred = Decimal(100)
self.StartProtection(
Unit(Decimal(self._take_profit_percent.Value) * hundred, UnitTypes.Percent),
Unit(Decimal(self._stop_loss_percent.Value) * hundred, UnitTypes.Percent),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
self.DrawIndicator(oscillators, macd)
def _process_candle(self, candle, fast_value, slow_value, rsi_value, macd_value):
if candle.State != CandleStates.Finished:
return
if not fast_value.IsFormed or not slow_value.IsFormed or not rsi_value.IsFormed or not macd_value.IsFormed:
return
macd_line = macd_value.Macd
signal_line = macd_value.Signal
if macd_line is None or signal_line is None:
return
fast = fast_value.GetValue[Decimal](None)
slow = slow_value.GetValue[Decimal](None)
pf = self._prev_fast
ps = self._prev_slow
self._prev_fast = fast
self._prev_slow = slow
if pf is None or ps is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
rsi = rsi_value.GetValue[Decimal](None)
long_signal = (pf <= ps and fast > slow and macd_line > signal_line
and rsi > Decimal(self._rsi_lower_long.Value) and rsi < Decimal(self._rsi_upper_long.Value))
short_signal = (pf >= ps and fast < slow and macd_line < signal_line
and rsi > Decimal(self._rsi_lower_short.Value) and rsi < Decimal(self._rsi_upper_short.Value))
if long_signal and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif short_signal and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return manadi_buy_sell_strategy()