Estratégia MA CCI
Estratégia que combina a Média Móvel e o indicador CCI. Compra quando o preço está acima da MA e o CCI está sobrevendido. Vende quando o preço está abaixo da MA e o CCI está sobrecomprado.
Os testes indicam um retorno anual médio de cerca de 49%. Funciona melhor no mercado de criptomoedas.
Uma média móvel orienta a tendência enquanto o CCI busca desvios dessa média. As entradas ocorrem nos extremos do CCI na direção da MA.
Ideal para traders de swing que entram em retrocessos. Um stop percentual protege contra movimentos bruscos.
Detalhes
- Critérios de entrada:
- Comprado:
Close > MA && CCI < OversoldLevel - Vendido:
Close < MA && CCI > OverboughtLevel
- Comprado:
- Comprado/Vendido: Ambos
- Critérios de saída:
- CCI retorna à linha zero
- Stops: Baseados em percentual usando
StopLossPercent - Valores padrão:
MaPeriod= 50CciPeriod= 20OverboughtLevel= 100mOversoldLevel= -100mStopLossPercent= 2.0mCandleType= TimeSpan.FromMinutes(5).TimeFrame() Uma SMA de 20 candles se move junto com o CCI dos mesmos 20 candles, então o preço quase nunca fica acima dela com o CCI abaixo de -100: o arquivo de março de 2024 tem no máximo um candle assim por instrumento. Por isso a SMA de tendência usa 50 candles por padrão. Um sinal de entrada contra uma posição aberta a inverte.
- Filtros:
- Categoria: Reversão à média
- Direção: Ambos
- Indicadores: Moving Average, CCI
- Stops: Sim
- Complexidade: Intermediário
- Período: Médio prazo
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Médio
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>
/// MA CCI strategy.
/// A close above the MaPeriod SMA with CCI below OversoldLevel goes long and a close below it with CCI above OverboughtLevel goes short,
/// reversing an opposite position. The position closes once CCI returns to the zero line, and a percent stop limits the loss.
/// </summary>
public class MaCciStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<decimal> _oversoldLevel;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// Period of the trend SMA.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Period of CCI.
/// </summary>
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
/// <summary>
/// CCI level for shorts.
/// </summary>
public decimal OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
/// <summary>
/// CCI level for longs.
/// </summary>
public decimal OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
/// <summary>
/// Stop loss percentage from entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public MaCciStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Period of the trend SMA", "Indicators");
_cciPeriod = Param(nameof(CciPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "Period of CCI", "Indicators");
_overboughtLevel = Param(nameof(OverboughtLevel), 100m)
.SetDisplay("Overbought Level", "CCI level for shorts", "Indicators");
_oversoldLevel = Param(nameof(OversoldLevel), -100m)
.SetDisplay("Oversold Level", "CCI level for longs", "Indicators");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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 OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = MaPeriod };
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(sma, cci, ProcessCandle)
.Start();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
// The stop has to see prices between candles, not only at their close.
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ObserveProtectionQuote).Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
{
DrawIndicator(oscillators, cci);
}
}
}
private void ObserveProtectionQuote(Level1ChangeMessage quote)
{
// The high-level handler activates native protection before this callback, also between signal bars.
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue smaValue, IIndicatorValue cciValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!smaValue.IsFormed || !cciValue.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var ma = smaValue.GetValue<decimal>();
var cci = cciValue.GetValue<decimal>();
var close = candle.ClosePrice;
if (close > ma && cci < OversoldLevel && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (close < ma && cci > OverboughtLevel && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && cci >= 0)
SellMarket(Position);
else if (Position < 0 && cci <= 0)
BuyMarket(-Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Indicators import SimpleMovingAverage, CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class ma_cci_strategy(Strategy):
"""
MA CCI strategy.
A close above the MaPeriod SMA with CCI below OversoldLevel goes long and a close below it with CCI above OverboughtLevel goes short,
reversing an opposite position. The position closes once CCI returns to the zero line, and a percent stop limits the loss.
"""
def __init__(self):
super(ma_cci_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 50).SetGreaterThanZero().SetDisplay("MA Period", "Period of the trend SMA", "Indicators")
self._cci_period = self.Param("CciPeriod", 20).SetGreaterThanZero().SetDisplay("CCI Period", "Period of CCI", "Indicators")
self._overbought_level = self.Param("OverboughtLevel", 100.0).SetDisplay("Overbought Level", "CCI level for shorts", "Indicators")
self._oversold_level = self.Param("OversoldLevel", -100.0).SetDisplay("Oversold Level", "CCI level for longs", "Indicators")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(ma_cci_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self._ma_period.Value
cci = CommodityChannelIndex()
cci.Length = self._cci_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(sma, cci, self._process_candle).Start()
self.StartProtection(Unit(), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
# The stop has to see prices between candles, not only at their close.
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._observe_protection_quote).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, cci)
def _observe_protection_quote(self, quote):
# The high-level handler activates native protection before the callback, including between bars.
pass
def _process_candle(self, candle, sma_value, cci_value):
if candle.State != CandleStates.Finished:
return
if not sma_value.IsFormed or not cci_value.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
ma = sma_value.GetValue[Decimal](None)
cci = cci_value.GetValue[Decimal](None)
close = candle.ClosePrice
zero = Decimal(0)
if close > ma and cci < Decimal(self._oversold_level.Value) and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif close < ma and cci > Decimal(self._overbought_level.Value) and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and cci >= zero:
self.SellMarket(self.Position)
elif self.Position < 0 and cci <= zero:
self.BuyMarket(-self.Position)
def CreateClone(self):
return ma_cci_strategy()