Intra Bullish Strategy - Profit Ping v4.0 Strategy
Long-only system using an EMA crossover confirmed by MACD histogram and RSI strength.
Details
- Entry Criteria:
- Short EMA crosses above Long EMA
- MACD histogram > 0
- RSI > 50
- Close > Open
- Exit Criteria:
- Short EMA crosses below Long EMA
- MACD histogram < 0
- RSI < 50
- Close < Open
- Indicators:
- Exponential Moving Averages
- MACD
- RSI
- Stops: None.
- Default Values:
ShortEmaLength= 7LongEmaLength= 14RsiLength= 14MacdFastPeriod= 12MacdSlowPeriod= 26MacdSignalPeriod= 9
- Filters:
- Trend-following
- Single timeframe
- Indicators: EMA, MACD, RSI
- Stops: none
- Complexity: Low
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>
/// Intra Bullish Strategy - Profit Ping v4.0.
/// Enters long on EMA crossover with MACD and RSI confirmation.
/// </summary>
public class IntraBullishProfitPingV40Strategy : Strategy
{
private readonly StrategyParam<int> _shortEmaLength;
private readonly StrategyParam<int> _longEmaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _macdFast;
private readonly StrategyParam<int> _macdSlow;
private readonly StrategyParam<int> _macdSignal;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevShort;
private decimal? _prevLong;
private decimal _lastRsi;
private decimal _lastHistogram;
public int ShortEmaLength
{
get => _shortEmaLength.Value;
set => _shortEmaLength.Value = value;
}
public int LongEmaLength
{
get => _longEmaLength.Value;
set => _longEmaLength.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public int MacdFastPeriod
{
get => _macdFast.Value;
set => _macdFast.Value = value;
}
public int MacdSlowPeriod
{
get => _macdSlow.Value;
set => _macdSlow.Value = value;
}
public int MacdSignalPeriod
{
get => _macdSignal.Value;
set => _macdSignal.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public IntraBullishProfitPingV40Strategy()
{
_shortEmaLength = Param(nameof(ShortEmaLength), 7)
.SetDisplay("Short EMA", "Short EMA length", "EMA")
.SetGreaterThanZero();
_longEmaLength = Param(nameof(LongEmaLength), 14)
.SetDisplay("Long EMA", "Long EMA length", "EMA")
.SetGreaterThanZero();
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI calculation period", "RSI")
.SetGreaterThanZero();
_macdFast = Param(nameof(MacdFastPeriod), 12)
.SetDisplay("MACD Fast", "MACD fast EMA length", "MACD")
.SetGreaterThanZero();
_macdSlow = Param(nameof(MacdSlowPeriod), 26)
.SetDisplay("MACD Slow", "MACD slow EMA length", "MACD")
.SetGreaterThanZero();
_macdSignal = Param(nameof(MacdSignalPeriod), 9)
.SetDisplay("MACD Signal", "MACD signal EMA length", "MACD")
.SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(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();
_prevShort = null;
_prevLong = null;
_lastRsi = 0;
_lastHistogram = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var emaShort = new ExponentialMovingAverage { Length = ShortEmaLength };
var emaLong = new ExponentialMovingAverage { Length = LongEmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFastPeriod },
LongMa = { Length = MacdSlowPeriod },
},
SignalMa = { Length = MacdSignalPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(emaShort, emaLong, rsi, macd, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, emaShort);
DrawIndicator(area, emaLong);
DrawOwnTrades(area);
}
}
private void ProcessCandle(
ICandleMessage candle,
IIndicatorValue emaShortVal,
IIndicatorValue emaLongVal,
IIndicatorValue rsiVal,
IIndicatorValue macdVal)
{
if (candle.State != CandleStates.Finished)
return;
if (emaShortVal.IsEmpty || emaLongVal.IsEmpty || rsiVal.IsEmpty || macdVal.IsEmpty)
return;
var emaShort = emaShortVal.ToDecimal();
var emaLong = emaLongVal.ToDecimal();
_lastRsi = rsiVal.ToDecimal();
if (macdVal is MovingAverageConvergenceDivergenceSignalValue macdTyped)
{
if (macdTyped.Macd is decimal m && macdTyped.Signal is decimal s)
_lastHistogram = m - s;
}
var crossUp = _prevShort is not null && _prevLong is not null && _prevShort <= _prevLong && emaShort > emaLong;
var crossDown = _prevShort is not null && _prevLong is not null && _prevShort >= _prevLong && emaShort < emaLong;
var buySignal = crossUp && _lastRsi > 40m;
var sellSignal = crossDown && _lastRsi < 60m;
if (buySignal && Position <= 0)
BuyMarket();
if (sellSignal && Position > 0)
SellMarket();
_prevShort = emaShort;
_prevLong = emaLong;
}
}
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, MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
class intra_bullish_profit_ping_v4_0_strategy(Strategy):
def __init__(self):
super(intra_bullish_profit_ping_v4_0_strategy, self).__init__()
self._short_ema_length = self.Param("ShortEmaLength", 7) \
.SetGreaterThanZero() \
.SetDisplay("Short EMA", "Short EMA length", "EMA")
self._long_ema_length = self.Param("LongEmaLength", 14) \
.SetGreaterThanZero() \
.SetDisplay("Long EMA", "Long EMA length", "EMA")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_short = None
self._prev_long = None
self._last_rsi = 0.0
self._last_histogram = 0.0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(intra_bullish_profit_ping_v4_0_strategy, self).OnReseted()
self._prev_short = None
self._prev_long = None
self._last_rsi = 0.0
self._last_histogram = 0.0
def OnStarted2(self, time):
super(intra_bullish_profit_ping_v4_0_strategy, self).OnStarted2(time)
ema_short = ExponentialMovingAverage()
ema_short.Length = self._short_ema_length.Value
ema_long = ExponentialMovingAverage()
ema_long.Length = self._long_ema_length.Value
self._rsi = RelativeStrengthIndex()
self._rsi.Length = 14
self._macd = MovingAverageConvergenceDivergenceSignal()
self._macd.Macd.ShortMa.Length = 12
self._macd.Macd.LongMa.Length = 26
self._macd.SignalMa.Length = 9
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(ema_short, ema_long, self._rsi, self._macd, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema_short)
self.DrawIndicator(area, ema_long)
self.DrawOwnTrades(area)
def OnProcess(self, candle, ema_short_val, ema_long_val, rsi_val, macd_val):
if candle.State != CandleStates.Finished:
return
if ema_short_val.IsEmpty or ema_long_val.IsEmpty or rsi_val.IsEmpty or macd_val.IsEmpty:
return
ema_s = float(ema_short_val)
ema_l = float(ema_long_val)
self._last_rsi = float(rsi_val)
macd_v = macd_val.Macd
signal_v = macd_val.Signal
if macd_v is not None and signal_v is not None:
self._last_histogram = float(macd_v) - float(signal_v)
cross_up = self._prev_short is not None and self._prev_long is not None and self._prev_short <= self._prev_long and ema_s > ema_l
cross_down = self._prev_short is not None and self._prev_long is not None and self._prev_short >= self._prev_long and ema_s < ema_l
buy_signal = cross_up and self._last_rsi > 40.0
sell_signal = cross_down and self._last_rsi < 60.0
if buy_signal and self.Position <= 0:
self.BuyMarket()
if sell_signal and self.Position > 0:
self.SellMarket()
self._prev_short = ema_s
self._prev_long = ema_l
def CreateClone(self):
return intra_bullish_profit_ping_v4_0_strategy()