Стратегия Intra Bullish Strategy - Profit Ping v4.0
Лонговая система, входящая при пересечении EMA вверх с подтверждением по MACD и RSI.
Детали
- Условия входа:
- Короткая EMA пересекает длинную вверх
- Гистограмма MACD > 0
- RSI > 50
- Цена закрытия выше цены открытия
- Условия выхода:
- Короткая EMA пересекает длинную вниз
- Гистограмма MACD < 0
- RSI < 50
- Цена закрытия ниже цены открытия
- Индикаторы:
- Экспоненциальные скользящие средние
- MACD
- RSI
- Стопы: отсутствуют.
- Значения по умолчанию:
ShortEmaLength= 7LongEmaLength= 14RsiLength= 14MacdFastPeriod= 12MacdSlowPeriod= 26MacdSignalPeriod= 9
- Фильтры:
- Трендовая
- Один таймфрейм
- Индикаторы: EMA, MACD, RSI
- Стопы: нет
- Сложность: низкая
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.
/// Long only. A long opens when the short EMA crosses above the long EMA on a candle where the MACD histogram is positive, RSI is above 50
/// and the candle closes above its open. The position closes when the short EMA crosses below the long EMA with a negative histogram,
/// RSI below 50 and a candle closing below its open. There are no stops.
/// </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;
/// <summary>
/// Short EMA length.
/// </summary>
public int ShortEmaLength
{
get => _shortEmaLength.Value;
set => _shortEmaLength.Value = value;
}
/// <summary>
/// Long EMA length.
/// </summary>
public int LongEmaLength
{
get => _longEmaLength.Value;
set => _longEmaLength.Value = value;
}
/// <summary>
/// RSI length.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// MACD fast period.
/// </summary>
public int MacdFastPeriod
{
get => _macdFast.Value;
set => _macdFast.Value = value;
}
/// <summary>
/// MACD slow period.
/// </summary>
public int MacdSlowPeriod
{
get => _macdSlow.Value;
set => _macdSlow.Value = value;
}
/// <summary>
/// MACD signal period.
/// </summary>
public int MacdSignalPeriod
{
get => _macdSignal.Value;
set => _macdSignal.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public IntraBullishProfitPingV40Strategy()
{
_shortEmaLength = Param(nameof(ShortEmaLength), 7)
.SetGreaterThanZero()
.SetDisplay("Short EMA", "Short EMA length", "EMA");
_longEmaLength = Param(nameof(LongEmaLength), 14)
.SetGreaterThanZero()
.SetDisplay("Long EMA", "Long EMA length", "EMA");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "RSI");
_macdFast = Param(nameof(MacdFastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "MACD fast period", "MACD");
_macdSlow = Param(nameof(MacdSlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "MACD slow period", "MACD");
_macdSignal = Param(nameof(MacdSignalPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("MACD Signal", "MACD signal period", "MACD");
_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;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevShort = null;
_prevLong = null;
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);
var oscillators = CreateChartArea();
if (oscillators != null)
{
DrawIndicator(oscillators, rsi);
DrawIndicator(oscillators, macd);
}
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue emaShortValue, IIndicatorValue emaLongValue, IIndicatorValue rsiValue, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!emaShortValue.IsFormed || !emaLongValue.IsFormed)
return;
var emaShort = emaShortValue.GetValue<decimal>();
var emaLong = emaLongValue.GetValue<decimal>();
var prevShort = _prevShort;
var prevLong = _prevLong;
_prevShort = emaShort;
_prevLong = emaLong;
if (prevShort is not decimal ps || prevLong is not decimal pl)
return;
if (!rsiValue.IsFormed || !macdValue.IsFormed || macdValue is not MovingAverageConvergenceDivergenceSignalValue { Macd: decimal macd, Signal: decimal signal })
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var rsi = rsiValue.GetValue<decimal>();
var histogram = macd - signal;
var crossUp = ps <= pl && emaShort > emaLong;
var crossDown = ps >= pl && emaShort < emaLong;
if (Position <= 0 && crossUp && histogram > 0 && rsi > 50m && candle.ClosePrice > candle.OpenPrice)
BuyMarket(Volume + Math.Abs(Position));
else if (Position > 0 && crossDown && histogram < 0 && rsi < 50m && candle.ClosePrice < candle.OpenPrice)
SellMarket(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
from StockSharp.Algo.Indicators import ExponentialMovingAverage, RelativeStrengthIndex, MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
class intra_bullish_profit_ping_v4_0_strategy(Strategy):
"""
Intra Bullish Strategy - Profit Ping v4.0.
Long only. A long opens when the short EMA crosses above the long EMA on a candle where the MACD histogram is positive, RSI is above 50
and the candle closes above its open. The position closes when the short EMA crosses below the long EMA with a negative histogram,
RSI below 50 and a candle closing below its open. There are no stops.
"""
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._rsi_length = self.Param("RsiLength", 14).SetGreaterThanZero().SetDisplay("RSI Length", "RSI period", "RSI")
self._macd_fast = self.Param("MacdFastPeriod", 12).SetGreaterThanZero().SetDisplay("MACD Fast", "MACD fast period", "MACD")
self._macd_slow = self.Param("MacdSlowPeriod", 26).SetGreaterThanZero().SetDisplay("MACD Slow", "MACD slow period", "MACD")
self._macd_signal = self.Param("MacdSignalPeriod", 9).SetGreaterThanZero().SetDisplay("MACD Signal", "MACD signal period", "MACD")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_short = None
self._prev_long = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(intra_bullish_profit_ping_v4_0_strategy, self).OnReseted()
self._prev_short = None
self._prev_long = None
def OnStarted2(self, time):
super(intra_bullish_profit_ping_v4_0_strategy, self).OnStarted2(time)
self._prev_short = None
self._prev_long = None
ema_short = ExponentialMovingAverage()
ema_short.Length = self._short_ema_length.Value
ema_long = ExponentialMovingAverage()
ema_long.Length = self._long_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(ema_short, ema_long, rsi, macd, self._process_candle).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)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
self.DrawIndicator(oscillators, macd)
def _process_candle(self, candle, ema_short_value, ema_long_value, rsi_value, macd_value):
if candle.State != CandleStates.Finished:
return
if not ema_short_value.IsFormed or not ema_long_value.IsFormed:
return
ema_short = ema_short_value.GetValue[Decimal](None)
ema_long = ema_long_value.GetValue[Decimal](None)
prev_short = self._prev_short
prev_long = self._prev_long
self._prev_short = ema_short
self._prev_long = ema_long
if prev_short is None or prev_long is None:
return
if not rsi_value.IsFormed or not macd_value.IsFormed or macd_value.Macd is None or macd_value.Signal is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
rsi = rsi_value.GetValue[Decimal](None)
histogram = macd_value.Macd - macd_value.Signal
cross_up = prev_short <= prev_long and ema_short > ema_long
cross_down = prev_short >= prev_long and ema_short < ema_long
if self.Position <= 0 and cross_up and histogram > 0 and rsi > 50 and candle.ClosePrice > candle.OpenPrice:
self.BuyMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and cross_down and histogram < 0 and rsi < 50 and candle.ClosePrice < candle.OpenPrice:
self.SellMarket(self.Position)
def CreateClone(self):
return intra_bullish_profit_ping_v4_0_strategy()