Стратегия FiveMinuteRsiCci
FiveMinuteRsiCciStrategy — порт советника MetaTrader 4 5Mins Rsi Cci EA.mq4 на платформу StockSharp. Оригинальный алгоритм торгует пятиминутные свечи, комбинируя пробой уровней RSI с фильтром из сглаженной/экспоненциальной средних по цене открытия и полярностью двух индикаторов CCI. Перенос сохраняет торговые правила и использует высокоуровневый API StockSharp для подписки на данные, расчёта индикаторов и управления рисками.
Логика торговли
- Подписка на выбранный таймфрейм (по умолчанию 5 минут) и одновременный пересчёт пяти индикаторов: RSI, сглаженной MA по цене открытия, EMA по цене открытия, а также быстрого и медленного CCI от типичной цены.
- Анализируется только закрытая свеча, когда нет открытой позиции и текущий спред меньше
MaxSpreadPoints(значение переводится в денежные единицы). - Сигнал на покупку формируется при выполнении условий:
- сглаженная MA находится выше EMA;
- RSI между предыдущей и текущей свечой пересекает уровень
BullishRsiLevelснизу вверх; - оба значения CCI положительные.
- Сигнал на продажу требует обратных условий (MA ниже EMA, RSI пробивает
BearishRsiLevelсверху вниз, оба CCI отрицательны). - Объём сделки воспроизводит динамическую формулу советника:
LotCoefficient × sqrt(Equity / EquityDivisor)с округлением кVolumeStepи учётом ограниченийVolumeMin/VolumeMaxинструмента. - Метод
StartProtectionавтоматически добавляет стоп-лосс, тейк-профит и трейлинг-стоп, преобразуя метатрейдеровские пункты в абсолютные ценовые смещения.
Параметры
| Параметр | Значение по умолчанию | Описание |
|---|---|---|
CandleType |
TimeSpan.FromMinutes(5).TimeFrame() |
Таймфрейм для расчёта индикаторов и сигналов. |
RsiPeriod |
14 |
Количество свечей в расчёте RSI. |
FastSmmaPeriod |
2 |
Период быстрой сглаженной средней по цене открытия. |
SlowEmaPeriod |
6 |
Период медленной EMA по цене открытия. |
FastCciPeriod |
34 |
Период быстрого CCI от типичной цены (H+L+C)/3. |
SlowCciPeriod |
175 |
Период медленного CCI от типичной цены. |
BullishRsiLevel |
55 |
Уровень RSI, который должен быть пробит снизу вверх для допуска лонгов. |
BearishRsiLevel |
45 |
Уровень RSI, который должен быть пробит сверху вниз для допуска шортов. |
StopLossPoints |
60 |
Дистанция стоп-лосса в пунктах MetaTrader (0 — без стопа). |
TakeProfitPoints |
0 |
Дистанция тейк-профита в пунктах MetaTrader (0 оставляет тейк отключённым, как в оригинале). |
TrailingStopPoints |
20 |
Дистанция трейлинг-стопа в пунктах MetaTrader (0 отключает трейлинг). |
LotCoefficient |
0.01 |
Базовый коэффициент динамического мани-менеджмента. |
EquityDivisor |
10 |
Делитель внутри квадратного корня (sqrt(Equity / EquityDivisor)). |
MaxSpreadPoints |
18 |
Максимально допустимый спред в пунктах MetaTrader. |
Особенности
- Фильтр по спреду использует поток Level1. Пока нет котировок best bid/ask, стратегия ожидает и не открывает позицию.
- Пересчёт пунктов в цену учитывает
PriceStepи точность инструмента; для пяти- и трёхзнаковых символов шаг умножается на 10, что соответствует значениюPointв MetaTrader. - Защитные приказы обслуживает встроенный движок StockSharp c рыночными выходами, что повторяет поведение
OrderModifyв исходном советнике.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Finished-bar RSI threshold crossings confirmed by open-price SMMA/EMA and two typical-price CCIs.
/// </summary>
public class FiveMinuteRsiCciStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _fastSmmaPeriod;
private readonly StrategyParam<int> _slowEmaPeriod;
private readonly StrategyParam<int> _fastCciPeriod;
private readonly StrategyParam<int> _slowCciPeriod;
private readonly StrategyParam<decimal> _bullishRsiLevel;
private readonly StrategyParam<decimal> _bearishRsiLevel;
private readonly StrategyParam<decimal> _stopLossPoints;
private readonly StrategyParam<decimal> _takeProfitPoints;
private readonly StrategyParam<decimal> _trailingStopPoints;
private readonly StrategyParam<decimal> _lotCoefficient;
private readonly StrategyParam<decimal> _equityDivisor;
private readonly StrategyParam<decimal> _maxSpreadPoints;
private RelativeStrengthIndex _rsi;
private SmoothedMovingAverage _smma;
private ExponentialMovingAverage _ema;
private CommodityChannelIndex _fastCci;
private CommodityChannelIndex _slowCci;
private decimal? _previousRsi;
private decimal? _bestBid;
private decimal? _bestAsk;
private decimal? _entryPrice;
private decimal? _trailingStop;
private bool _exitRequested;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int FastSmmaPeriod { get => _fastSmmaPeriod.Value; set => _fastSmmaPeriod.Value = value; }
public int SlowEmaPeriod { get => _slowEmaPeriod.Value; set => _slowEmaPeriod.Value = value; }
public int FastCciPeriod { get => _fastCciPeriod.Value; set => _fastCciPeriod.Value = value; }
public int SlowCciPeriod { get => _slowCciPeriod.Value; set => _slowCciPeriod.Value = value; }
public decimal BullishRsiLevel { get => _bullishRsiLevel.Value; set => _bullishRsiLevel.Value = value; }
public decimal BearishRsiLevel { get => _bearishRsiLevel.Value; set => _bearishRsiLevel.Value = value; }
public decimal StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public decimal TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public decimal TrailingStopPoints { get => _trailingStopPoints.Value; set => _trailingStopPoints.Value = value; }
public decimal LotCoefficient { get => _lotCoefficient.Value; set => _lotCoefficient.Value = value; }
public decimal EquityDivisor { get => _equityDivisor.Value; set => _equityDivisor.Value = value; }
public decimal MaxSpreadPoints { get => _maxSpreadPoints.Value; set => _maxSpreadPoints.Value = value; }
public FiveMinuteRsiCciStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
_rsiPeriod = Param(nameof(RsiPeriod), 14).SetGreaterThanZero();
_fastSmmaPeriod = Param(nameof(FastSmmaPeriod), 2).SetGreaterThanZero();
_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 6).SetGreaterThanZero();
_fastCciPeriod = Param(nameof(FastCciPeriod), 34).SetGreaterThanZero();
_slowCciPeriod = Param(nameof(SlowCciPeriod), 175).SetGreaterThanZero();
_bullishRsiLevel = Param(nameof(BullishRsiLevel), 55m);
_bearishRsiLevel = Param(nameof(BearishRsiLevel), 45m);
_stopLossPoints = Param(nameof(StopLossPoints), 60m).SetNotNegative();
_takeProfitPoints = Param(nameof(TakeProfitPoints), 0m).SetNotNegative();
_trailingStopPoints = Param(nameof(TrailingStopPoints), 20m).SetNotNegative();
_lotCoefficient = Param(nameof(LotCoefficient), 0.01m).SetGreaterThanZero();
_equityDivisor = Param(nameof(EquityDivisor), 10m).SetGreaterThanZero();
_maxSpreadPoints = Param(nameof(MaxSpreadPoints), 18m).SetNotNegative();
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType), (Security, DataType.Level1)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetRuntime();
}
private void ResetRuntime()
{
_previousRsi = null;
_bestBid = null;
_bestAsk = null;
_entryPrice = null;
_trailingStop = null;
_exitRequested = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetRuntime();
_rsi = new() { Length = RsiPeriod };
_smma = new() { Length = FastSmmaPeriod };
_ema = new() { Length = SlowEmaPeriod };
_fastCci = new() { Length = FastCciPeriod };
_slowCci = new() { Length = SlowCciPeriod };
var point = GetPoint();
var takeProfit = TakeProfitPoints > 0m ? new Unit(TakeProfitPoints * point, UnitTypes.Absolute) : new Unit();
var stopLoss = StopLossPoints > 0m ? new Unit(StopLossPoints * point, UnitTypes.Absolute) : new Unit();
StartProtection(takeProfit, stopLoss, useMarketOrders: true, isLocalStop: true);
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ProcessLevel1).Start();
}
SubscribeCandles(CandleType).Bind(ProcessCandle).Start();
}
private decimal GetPoint()
{
var step = Security?.PriceStep ?? 0m;
if (step <= 0m)
throw new InvalidOperationException("Positive Security.PriceStep is required.");
return Security.Decimals is 3 or 5 ? step * 10m : step;
}
private void ProcessLevel1(Level1ChangeMessage message)
{
if (message.TryGetDecimal(Level1Fields.BestBidPrice) is decimal bid && bid > 0m)
_bestBid = bid;
if (message.TryGetDecimal(Level1Fields.BestAskPrice) is decimal ask && ask > 0m)
_bestAsk = ask;
if (Position == 0m || _entryPrice is null || TrailingStopPoints <= 0m || _exitRequested)
return;
var gap = TrailingStopPoints * GetPoint();
var price = Position > 0m ? _bestBid : _bestAsk;
if (price is null)
return;
if (Position > 0m)
{
if (price.Value >= _entryPrice.Value + gap)
{
var candidate = price.Value - gap;
if (_trailingStop is null || candidate > _trailingStop.Value)
_trailingStop = candidate;
}
if (_trailingStop is decimal stop && price.Value <= stop)
RequestExit();
}
else
{
if (price.Value <= _entryPrice.Value - gap)
{
var candidate = price.Value + gap;
if (_trailingStop is null || candidate < _trailingStop.Value)
_trailingStop = candidate;
}
if (_trailingStop is decimal stop && price.Value >= stop)
RequestExit();
}
}
private void RequestExit()
{
if (_exitRequested || Position == 0m)
return;
_exitRequested = true;
ClosePosition();
}
/// <inheritdoc />
protected override void OnOwnTradeReceived(MyTrade trade)
{
base.OnOwnTradeReceived(trade);
if (Position == 0m)
{
_entryPrice = null;
_trailingStop = null;
_exitRequested = false;
}
else if (_entryPrice is null)
{
_entryPrice = trade.Trade.Price;
}
}
private bool IsSpreadAllowed()
=> _bestBid is decimal bid && _bestAsk is decimal ask
&& ask >= bid && ask - bid < MaxSpreadPoints * GetPoint();
private decimal GetVolume()
{
var equity = Portfolio?.CurrentValue ?? Portfolio?.BeginValue ?? 0m;
if (equity <= 0m || EquityDivisor <= 0m)
return 0m;
var raw = LotCoefficient * (decimal)Math.Sqrt((double)(equity / EquityDivisor));
var minimum = Security?.MinVolume ?? 0m;
var maximum = Security?.MaxVolume ?? decimal.MaxValue;
var step = Security?.VolumeStep ?? 0m;
if (maximum < minimum)
return 0m;
if (step > 0m)
{
var first = Math.Ceiling(minimum / step) * step;
var last = Math.Floor(maximum / step) * step;
if (first > last)
return 0m;
return Math.Clamp(Math.Floor(raw / step) * step, first, last);
}
return Math.Clamp(raw, minimum, maximum);
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var rsi = _rsi.Process(candle.ClosePrice, candle.OpenTime, true);
var smma = _smma.Process(candle.OpenPrice, candle.OpenTime, true);
var ema = _ema.Process(candle.OpenPrice, candle.OpenTime, true);
var fastCci = _fastCci.Process(candle);
var slowCci = _slowCci.Process(candle);
if (!rsi.IsFormed || !smma.IsFormed || !ema.IsFormed || !fastCci.IsFormed || !slowCci.IsFormed)
return;
var currentRsi = rsi.ToDecimal();
if (_previousRsi is decimal previous && Position == 0m && !_exitRequested && IsSpreadAllowed())
{
var volume = GetVolume();
if (volume > 0m)
{
if (previous <= BullishRsiLevel && currentRsi > BullishRsiLevel &&
smma.ToDecimal() > ema.ToDecimal() &&
fastCci.ToDecimal() > 0m && slowCci.ToDecimal() > 0m)
BuyMarket(volume);
else if (previous >= BearishRsiLevel && currentRsi < BearishRsiLevel &&
smma.ToDecimal() < ema.ToDecimal() &&
fastCci.ToDecimal() < 0m && slowCci.ToDecimal() < 0m)
SellMarket(volume);
}
}
_previousRsi = currentRsi;
}
}
import math
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.BusinessEntities")
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, Level1Fields, Unit, UnitTypes
from StockSharp.Algo.Indicators import (
RelativeStrengthIndex, CommodityChannelIndex, SmoothedMovingAverage,
ExponentialMovingAverage, CandleIndicatorValue
)
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import process_float
class five_minute_rsi_cci_strategy(Strategy):
def __init__(self):
super(five_minute_rsi_cci_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._fast_smma_period = self.Param("FastSmmaPeriod", 2)
self._slow_ema_period = self.Param("SlowEmaPeriod", 6)
self._fast_cci_period = self.Param("FastCciPeriod", 34)
self._slow_cci_period = self.Param("SlowCciPeriod", 175)
self._bullish_rsi_level = self.Param("BullishRsiLevel", 55.0)
self._bearish_rsi_level = self.Param("BearishRsiLevel", 45.0)
self._stop_loss_points = self.Param("StopLossPoints", 60.0)
self._take_profit_points = self.Param("TakeProfitPoints", 0.0)
self._trailing_stop_points = self.Param("TrailingStopPoints", 20.0)
self._lot_coefficient = self.Param("LotCoefficient", 0.01)
self._equity_divisor = self.Param("EquityDivisor", 10.0)
self._max_spread_points = self.Param("MaxSpreadPoints", 18.0)
self._reset_runtime()
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def FastSmmaPeriod(self):
return self._fast_smma_period.Value
@FastSmmaPeriod.setter
def FastSmmaPeriod(self, value):
self._fast_smma_period.Value = value
@property
def SlowEmaPeriod(self):
return self._slow_ema_period.Value
@SlowEmaPeriod.setter
def SlowEmaPeriod(self, value):
self._slow_ema_period.Value = value
@property
def FastCciPeriod(self):
return self._fast_cci_period.Value
@FastCciPeriod.setter
def FastCciPeriod(self, value):
self._fast_cci_period.Value = value
@property
def SlowCciPeriod(self):
return self._slow_cci_period.Value
@SlowCciPeriod.setter
def SlowCciPeriod(self, value):
self._slow_cci_period.Value = value
@property
def BullishRsiLevel(self):
return self._bullish_rsi_level.Value
@BullishRsiLevel.setter
def BullishRsiLevel(self, value):
self._bullish_rsi_level.Value = value
@property
def BearishRsiLevel(self):
return self._bearish_rsi_level.Value
@BearishRsiLevel.setter
def BearishRsiLevel(self, value):
self._bearish_rsi_level.Value = value
@property
def StopLossPoints(self):
return self._stop_loss_points.Value
@StopLossPoints.setter
def StopLossPoints(self, value):
self._stop_loss_points.Value = value
@property
def TakeProfitPoints(self):
return self._take_profit_points.Value
@TakeProfitPoints.setter
def TakeProfitPoints(self, value):
self._take_profit_points.Value = value
@property
def TrailingStopPoints(self):
return self._trailing_stop_points.Value
@TrailingStopPoints.setter
def TrailingStopPoints(self, value):
self._trailing_stop_points.Value = value
@property
def LotCoefficient(self):
return self._lot_coefficient.Value
@LotCoefficient.setter
def LotCoefficient(self, value):
self._lot_coefficient.Value = value
@property
def EquityDivisor(self):
return self._equity_divisor.Value
@EquityDivisor.setter
def EquityDivisor(self, value):
self._equity_divisor.Value = value
@property
def MaxSpreadPoints(self):
return self._max_spread_points.Value
@MaxSpreadPoints.setter
def MaxSpreadPoints(self, value):
self._max_spread_points.Value = value
def _reset_runtime(self):
self._previous_rsi = None
self._best_bid = None
self._best_ask = None
self._entry_price = None
self._trailing_stop = None
self._exit_requested = False
def OnReseted(self):
super(five_minute_rsi_cci_strategy, self).OnReseted()
self._reset_runtime()
def _point(self):
if self.Security is None or self.Security.PriceStep is None:
raise ValueError("Positive Security.PriceStep is required.")
step = float(self.Security.PriceStep)
if step <= 0:
raise ValueError("Positive Security.PriceStep is required.")
return step * 10.0 if self.Security.Decimals in (3, 5) else step
def OnStarted2(self, time):
super(five_minute_rsi_cci_strategy, self).OnStarted2(time)
self._reset_runtime()
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiPeriod
self._smma = SmoothedMovingAverage()
self._smma.Length = self.FastSmmaPeriod
self._ema = ExponentialMovingAverage()
self._ema.Length = self.SlowEmaPeriod
self._fast_cci = CommodityChannelIndex()
self._fast_cci.Length = self.FastCciPeriod
self._slow_cci = CommodityChannelIndex()
self._slow_cci.Length = self.SlowCciPeriod
point = self._point()
stop = Unit(Decimal(self.StopLossPoints * point), UnitTypes.Absolute) if self.StopLossPoints > 0 else Unit()
take = Unit(Decimal(self.TakeProfitPoints * point), UnitTypes.Absolute) if self.TakeProfitPoints > 0 else Unit()
self.StartProtection(take, stop, useMarketOrders=True, isLocalStop=True)
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._process_level1).Start()
self.SubscribeCandles(self.CandleType).Bind(self._process_candle).Start()
def _process_level1(self, message):
bid = message.Changes[Level1Fields.BestBidPrice] if message.Changes.ContainsKey(Level1Fields.BestBidPrice) else None
ask = message.Changes[Level1Fields.BestAskPrice] if message.Changes.ContainsKey(Level1Fields.BestAskPrice) else None
if bid is not None and bid > 0:
self._best_bid = float(bid)
if ask is not None and ask > 0:
self._best_ask = float(ask)
if self.Position == 0 or self._entry_price is None or self.TrailingStopPoints <= 0 or self._exit_requested:
return
gap = float(self.TrailingStopPoints) * self._point()
price = self._best_bid if self.Position > 0 else self._best_ask
if price is None:
return
if self.Position > 0:
if price >= self._entry_price + gap:
candidate = price - gap
if self._trailing_stop is None or candidate > self._trailing_stop:
self._trailing_stop = candidate
if self._trailing_stop is not None and price <= self._trailing_stop:
self._request_exit()
else:
if price <= self._entry_price - gap:
candidate = price + gap
if self._trailing_stop is None or candidate < self._trailing_stop:
self._trailing_stop = candidate
if self._trailing_stop is not None and price >= self._trailing_stop:
self._request_exit()
def _request_exit(self):
if self._exit_requested or self.Position == 0:
return
self._exit_requested = True
self.ClosePosition()
def OnOwnTradeReceived(self, trade):
super(five_minute_rsi_cci_strategy, self).OnOwnTradeReceived(trade)
if self.Position == 0:
self._entry_price = None
self._trailing_stop = None
self._exit_requested = False
elif self._entry_price is None:
self._entry_price = float(trade.Trade.TradePrice)
def _spread_allowed(self):
return (self._best_bid is not None and self._best_ask is not None
and self._best_ask >= self._best_bid
and self._best_ask - self._best_bid < float(self.MaxSpreadPoints) * self._point())
def _volume(self):
portfolio = self.Portfolio
if portfolio is None:
return None
equity = portfolio.CurrentValue if portfolio.CurrentValue is not None else portfolio.BeginValue
divisor = Decimal(float(self.EquityDivisor))
if equity is None or equity <= 0 or divisor <= 0:
return None
raw = Decimal.Multiply(Decimal(float(self.LotCoefficient)),
Decimal(math.sqrt(float(Decimal.Divide(equity, divisor)))))
minimum = self.Security.MinVolume if self.Security.MinVolume is not None else Decimal(0)
maximum = self.Security.MaxVolume if self.Security.MaxVolume is not None else Decimal.MaxValue
if minimum > maximum:
return None
step = self.Security.VolumeStep
if step is not None and step > 0:
first = Decimal.Ceiling(Decimal.Divide(minimum, step))
last = Decimal.Floor(Decimal.Divide(maximum, step))
if first > last:
return None
units = max(first, min(last, Decimal.Floor(Decimal.Divide(raw, step))))
raw = Decimal.Multiply(units, step)
else:
raw = max(minimum, min(maximum, raw))
return raw if raw > 0 else None
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
rsi = process_float(self._rsi, candle.ClosePrice, candle.OpenTime, True)
smma = process_float(self._smma, candle.OpenPrice, candle.OpenTime, True)
ema = process_float(self._ema, candle.OpenPrice, candle.OpenTime, True)
fast_in = CandleIndicatorValue(self._fast_cci, candle)
fast_in.IsFinal = True
slow_in = CandleIndicatorValue(self._slow_cci, candle)
slow_in.IsFinal = True
fast_cci = self._fast_cci.Process(fast_in)
slow_cci = self._slow_cci.Process(slow_in)
if not all((rsi.IsFormed, smma.IsFormed, ema.IsFormed, fast_cci.IsFormed, slow_cci.IsFormed)):
return
current = float(rsi)
previous = self._previous_rsi
if previous is not None and self.Position == 0 and not self._exit_requested and self._spread_allowed():
volume = self._volume()
if volume is not None:
if (previous <= float(self.BullishRsiLevel) and current > float(self.BullishRsiLevel)
and float(smma) > float(ema)
and float(fast_cci) > 0 and float(slow_cci) > 0):
self.BuyMarket(volume)
elif (previous >= float(self.BearishRsiLevel) and current < float(self.BearishRsiLevel)
and float(smma) < float(ema)
and float(fast_cci) < 0 and float(slow_cci) < 0):
self.SellMarket(volume)
self._previous_rsi = current
def CreateClone(self):
return five_minute_rsi_cci_strategy()