Estrategia Mutanabby AI Algo Pro
La estrategia Mutanabby AI Algo Pro entra largo cuando un patrón de vela envolvente alcista se alinea con una lectura de RSI por debajo de un umbral y una caída del precio durante un número determinado de barras. Los cierres ocurren en un patrón envolvente bajista o cuando se alcanza el stop loss.
Detalles
- Criterios de entrada: Envolvente alcista, vela estable, RSI por debajo del umbral, precio por debajo del valor de N barras atrás.
- Largo/Corto: Solo largos.
- Criterios de salida: Envolvente bajista o stop loss.
- Stops: Opcional.
- Valores predeterminados:
CandleStabilityIndex= 0.5RsiIndex= 50CandleDeltaLength= 5DisableRepeatingSignals= falseEnableStopLoss= trueStopLossMethod= EntryPriceBasedEntryStopLossPercent= 2.0LookbackPeriod= 10StopLossBufferPercent= 0.5CandleType= TimeSpan.FromMinutes(1)
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Solo largos
- Indicadores: RSI
- Stops: Sí
- Complejidad: Básico
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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()