Mutanabby AI Algo Pro 戦略
Mutanabby AI Algo Pro 戦略は、強気の包み足パターンが RSI のしきい値以下の読みおよび指定された本数のバーにわたる価格下落と一致したときにロングでエントリーします。弱気の包み足パターンが出現するか、ストップロスに達したときに決済します。
詳細
- エントリー条件: 強気の包み足、安定したローソク足、RSI がしきい値以下、N 本前の価格を下回る。
- ロング/ショート: ロングのみ。
- エグジット条件: 弱気の包み足またはストップロス。
- ストップ: オプション。
- デフォルト値:
CandleStabilityIndex= 0.5RsiIndex= 50CandleDeltaLength= 5DisableRepeatingSignals= falseEnableStopLoss= trueStopLossMethod= EntryPriceBasedEntryStopLossPercent= 2.0LookbackPeriod= 10StopLossBufferPercent= 0.5CandleType= TimeSpan.FromMinutes(1)
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: ロングのみ
- インジケーター: 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>
/// Mutanabby AI Algo Pro strategy.
/// Long only. Enters on a bullish engulfing candle whose body is at least CandleStabilityIndex of its range, while RSI is below
/// RsiIndex and the close is below the close CandleDeltaLength bars ago. Exits on a bearish engulfing candle or when the stop is hit.
/// The stop is either EntryStopLossPercent below the entry price or StopLossBufferPercent below the lowest low of LookbackPeriod bars.
/// </summary>
public class MutanabbyAiAlgoProStrategy : Strategy
{
/// <summary>
/// Defines stop loss calculation modes.
/// </summary>
public enum StopLossModes
{
/// <summary>
/// Stop loss is calculated from entry price.
/// </summary>
EntryPriceBased,
/// <summary>
/// Stop loss is based on the lowest low over a period.
/// </summary>
LowestLowBased
}
private readonly StrategyParam<decimal> _candleStabilityIndex;
private readonly StrategyParam<int> _rsiIndex;
private readonly StrategyParam<int> _candleDeltaLength;
private readonly StrategyParam<bool> _disableRepeatingSignals;
private readonly StrategyParam<bool> _enableStopLoss;
private readonly StrategyParam<StopLossModes> _stopLossMethod;
private readonly StrategyParam<decimal> _entryStopLossPercent;
private readonly StrategyParam<int> _lookbackPeriod;
private readonly StrategyParam<decimal> _stopLossBufferPercent;
private readonly StrategyParam<DataType> _candleType;
private const int _rsiLength = 14;
private decimal? _prevOpen;
private decimal? _prevClose;
private readonly Queue<decimal> _closes = new();
private bool? _lastSignalBuy;
private decimal _stopLossPrice;
/// <summary>
/// Minimum ratio between candle body and true range.
/// </summary>
public decimal CandleStabilityIndex
{
get => _candleStabilityIndex.Value;
set => _candleStabilityIndex.Value = value;
}
/// <summary>
/// RSI threshold.
/// </summary>
public int RsiIndex
{
get => _rsiIndex.Value;
set => _rsiIndex.Value = value;
}
/// <summary>
/// Bars for price comparison.
/// </summary>
public int CandleDeltaLength
{
get => _candleDeltaLength.Value;
set => _candleDeltaLength.Value = value;
}
/// <summary>
/// Prevent consecutive identical signals.
/// </summary>
public bool DisableRepeatingSignals
{
get => _disableRepeatingSignals.Value;
set => _disableRepeatingSignals.Value = value;
}
/// <summary>
/// Enable stop loss.
/// </summary>
public bool EnableStopLoss
{
get => _enableStopLoss.Value;
set => _enableStopLoss.Value = value;
}
/// <summary>
/// Stop loss calculation method.
/// </summary>
public StopLossModes StopLossMethod
{
get => _stopLossMethod.Value;
set => _stopLossMethod.Value = value;
}
/// <summary>
/// Entry based stop loss percent.
/// </summary>
public decimal EntryStopLossPercent
{
get => _entryStopLossPercent.Value;
set => _entryStopLossPercent.Value = value;
}
/// <summary>
/// Lookback period for lowest low stop.
/// </summary>
public int LookbackPeriod
{
get => _lookbackPeriod.Value;
set => _lookbackPeriod.Value = value;
}
/// <summary>
/// Buffer percent below lowest low.
/// </summary>
public decimal StopLossBufferPercent
{
get => _stopLossBufferPercent.Value;
set => _stopLossBufferPercent.Value = value;
}
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="MutanabbyAiAlgoProStrategy"/> class.
/// </summary>
public MutanabbyAiAlgoProStrategy()
{
_candleStabilityIndex = Param(nameof(CandleStabilityIndex), 0.5m)
.SetDisplay("Candle Stability Index", "Minimum body/true range ratio", "Technical")
.SetRange(0m, 1m);
_rsiIndex = Param(nameof(RsiIndex), 50)
.SetDisplay("RSI Index", "RSI threshold for entries", "Technical")
.SetRange(0, 100);
_candleDeltaLength = Param(nameof(CandleDeltaLength), 5)
.SetDisplay("Candle Delta Length", "Bars for price comparison", "Technical")
.SetRange(1, 50);
_disableRepeatingSignals = Param(nameof(DisableRepeatingSignals), false)
.SetDisplay("Disable Repeating Signals", "Avoid consecutive identical signals", "Technical");
_enableStopLoss = Param(nameof(EnableStopLoss), true)
.SetDisplay("Enable Stop Loss", "Activate stop loss", "Risk Management");
_stopLossMethod = Param(nameof(StopLossMethod), StopLossModes.EntryPriceBased)
.SetDisplay("Stop Loss Method", "Entry price or lowest low based", "Risk Management");
_entryStopLossPercent = Param(nameof(EntryStopLossPercent), 2.0m)
.SetDisplay("Entry Stop Loss %", "Stop loss percent from entry", "Risk Management")
.SetGreaterThanZero();
_lookbackPeriod = Param(nameof(LookbackPeriod), 10)
.SetDisplay("Lookback Period", "Bars for lowest low stop", "Risk Management")
.SetGreaterThanZero();
_stopLossBufferPercent = Param(nameof(StopLossBufferPercent), 0.5m)
.SetDisplay("Stop Loss Buffer %", "Additional buffer below lowest low", "Risk Management");
_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();
ResetState();
}
private void ResetState()
{
_prevOpen = null;
_prevClose = null;
_closes.Clear();
_lastSignalBuy = null;
_stopLossPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var rsi = new RelativeStrengthIndex { Length = _rsiLength };
var lowest = new Lowest { Length = LookbackPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, lowest, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, rsi);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal lowestLow)
{
if (candle.State != CandleStates.Finished)
return;
var prevOpen = _prevOpen;
var prevClose = _prevClose;
var closeN = _closes.Count == CandleDeltaLength ? _closes.Peek() : (decimal?)null;
_prevOpen = candle.OpenPrice;
_prevClose = candle.ClosePrice;
_closes.Enqueue(candle.ClosePrice);
while (_closes.Count > CandleDeltaLength)
_closes.Dequeue();
if (prevOpen is not decimal po || prevClose is not decimal pc || closeN is not decimal cn)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var open = candle.OpenPrice;
if (Position > 0)
{
var stopHit = EnableStopLoss && _stopLossPrice > 0 && candle.LowPrice <= _stopLossPrice;
var bearishEngulfing = pc > po && close < open && close < po;
if (stopHit || bearishEngulfing)
{
SellMarket(Position);
_lastSignalBuy = false;
_stopLossPrice = 0m;
}
return;
}
var range = candle.HighPrice - candle.LowPrice;
var stable = range > 0 && Math.Abs(close - open) / range >= CandleStabilityIndex;
var bullishEngulfing = pc < po && close > open && close > po;
if (!bullishEngulfing || !stable || rsiValue >= RsiIndex || close >= cn)
return;
if (DisableRepeatingSignals && _lastSignalBuy == true)
return;
BuyMarket(Volume + Math.Abs(Position));
_lastSignalBuy = true;
_stopLossPrice = !EnableStopLoss
? 0m
: StopLossMethod == StopLossModes.EntryPriceBased
? close * (1 - EntryStopLossPercent / 100m)
: lowestLow * (1 - StopLossBufferPercent / 100m);
}
}
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 RelativeStrengthIndex, Lowest
from StockSharp.Algo.Strategies import Strategy
RSI_LENGTH = 14
class mutanabby_ai_algo_pro_strategy(Strategy):
"""
Mutanabby AI Algo Pro strategy.
Long only. Enters on a bullish engulfing candle whose body is at least CandleStabilityIndex of its range, while RSI is below
RsiIndex and the close is below the close CandleDeltaLength bars ago. Exits on a bearish engulfing candle or when the stop is hit.
The stop is either EntryStopLossPercent below the entry price or StopLossBufferPercent below the lowest low of LookbackPeriod bars.
StopLossMethod: EntryPriceBased or LowestLowBased.
"""
def __init__(self):
super(mutanabby_ai_algo_pro_strategy, self).__init__()
self._candle_stability_index = self.Param("CandleStabilityIndex", 0.5).SetRange(0.0, 1.0).SetDisplay("Candle Stability Index", "Minimum body/true range ratio", "Technical")
self._rsi_index = self.Param("RsiIndex", 50).SetRange(0, 100).SetDisplay("RSI Index", "RSI threshold for entries", "Technical")
self._candle_delta_length = self.Param("CandleDeltaLength", 5).SetRange(1, 50).SetDisplay("Candle Delta Length", "Bars for price comparison", "Technical")
self._disable_repeating_signals = self.Param("DisableRepeatingSignals", False).SetDisplay("Disable Repeating Signals", "Avoid consecutive identical signals", "Technical")
self._enable_stop_loss = self.Param("EnableStopLoss", True).SetDisplay("Enable Stop Loss", "Activate stop loss", "Risk Management")
self._stop_loss_method = self.Param("StopLossMethod", "EntryPriceBased").SetDisplay("Stop Loss Method", "Entry price or lowest low based", "Risk Management")
self._entry_stop_loss_percent = self.Param("EntryStopLossPercent", 2.0).SetGreaterThanZero().SetDisplay("Entry Stop Loss %", "Stop loss percent from entry", "Risk Management")
self._lookback_period = self.Param("LookbackPeriod", 10).SetGreaterThanZero().SetDisplay("Lookback Period", "Bars for lowest low stop", "Risk Management")
self._stop_loss_buffer_percent = self.Param("StopLossBufferPercent", 0.5).SetDisplay("Stop Loss Buffer %", "Additional buffer below lowest low", "Risk Management")
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 GetWorkingSecurities(self):
return [(self.Security, self.candle_type)]
def _reset_state(self):
self._prev_open = None
self._prev_close = None
self._closes = []
self._last_signal_buy = None
self._stop_loss_price = 0.0
def OnReseted(self):
super(mutanabby_ai_algo_pro_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(mutanabby_ai_algo_pro_strategy, self).OnStarted2(time)
self._reset_state()
rsi = RelativeStrengthIndex()
rsi.Length = RSI_LENGTH
lowest = Lowest()
lowest.Length = self._lookback_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, lowest, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
def _process_candle(self, candle, rsi_value, lowest_low):
if candle.State != CandleStates.Finished:
return
delta_length = self._candle_delta_length.Value
prev_open = self._prev_open
prev_close = self._prev_close
close_n = self._closes[0] if len(self._closes) == delta_length else None
close = float(candle.ClosePrice)
opn = float(candle.OpenPrice)
self._prev_open = opn
self._prev_close = close
self._closes.append(close)
while len(self._closes) > delta_length:
self._closes.pop(0)
if prev_open is None or prev_close is None or close_n is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position > 0:
stop_hit = self._enable_stop_loss.Value and self._stop_loss_price > 0 and float(candle.LowPrice) <= self._stop_loss_price
bearish_engulfing = prev_close > prev_open and close < opn and close < prev_open
if stop_hit or bearish_engulfing:
self.SellMarket(self.Position)
self._last_signal_buy = False
self._stop_loss_price = 0.0
return
rng = float(candle.HighPrice) - float(candle.LowPrice)
stable = rng > 0 and abs(close - opn) / rng >= float(self._candle_stability_index.Value)
bullish_engulfing = prev_close < prev_open and close > opn and close > prev_open
if not bullish_engulfing or not stable or float(rsi_value) >= self._rsi_index.Value or close >= close_n:
return
if self._disable_repeating_signals.Value and self._last_signal_buy is True:
return
self.BuyMarket(self.Volume + abs(self.Position))
self._last_signal_buy = True
if not self._enable_stop_loss.Value:
self._stop_loss_price = 0.0
elif str(self._stop_loss_method.Value) == "EntryPriceBased":
self._stop_loss_price = close * (1.0 - float(self._entry_stop_loss_percent.Value) / 100.0)
else:
self._stop_loss_price = float(lowest_low) * (1.0 - float(self._stop_loss_buffer_percent.Value) / 100.0)
def CreateClone(self):
return mutanabby_ai_algo_pro_strategy()