Estratégia Angrybird xScalpingn
Angrybird xScalpingn é uma estratégia de scalping no estilo martingale. Ela abre uma operação inicial com base na direção de preço de curto prazo e um filtro RSI. Quando o preço se move contra a posição aberta por um passo dinâmico derivado do range recente, a estratégia adiciona outra operação com volume multiplicado por um fator. Todas as posições são fechadas quando o CCI mostra um forte movimento contrário ou quando o stop-loss ou take-profit é atingido.
Detalhes
- Critérios de entrada: A operação inicial segue a direção de fechamento recente com um filtro RSI. Operações adicionais são abertas quando o preço se move contra a posição pelo passo calculado.
- Comprado/Vendido: Ambas as direções.
- Critérios de saída: Reversão do CCI ou stop-loss/take-profit protetor.
- Stops: Sim.
- Valores padrão:
Volume= 0.01LotExponent= 2DynamicPips= trueDefaultPips= 12Depth= 24Del= 3TakeProfit= 20StopLoss= 500Drop= 500RsiMinimum= 30RsiMaximum= 70MaxTrades= 10CandleType= TimeSpan.FromMinutes(1)
- Filtros:
- Categoria: Grid
- Direção: Ambos
- Indicadores: RSI, CCI
- Stops: Sim
- Complexidade: Avançado
- Período: Qualquer
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Alto
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
using StockSharp.Algo;
namespace StockSharp.Samples.Strategies;
public class AngrybirdXScalpingnStrategy : Strategy
{
private readonly StrategyParam<decimal> _lotExponent;
private readonly StrategyParam<bool> _dynamicPips;
private readonly StrategyParam<int> _defaultPips;
private readonly StrategyParam<int> _depth;
private readonly StrategyParam<int> _del;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _drop;
private readonly StrategyParam<decimal> _rsiMinimum;
private readonly StrategyParam<decimal> _rsiMaximum;
private readonly StrategyParam<int> _maxTrades;
private readonly StrategyParam<DataType> _candleType;
private readonly Queue<decimal> _highs = new();
private readonly Queue<decimal> _lows = new();
private decimal? _lastBuyPrice;
private decimal? _lastSellPrice;
private int _tradeCount;
private decimal _pipStep;
private decimal _prevClose;
public decimal LotExponent { get => _lotExponent.Value; set => _lotExponent.Value = value; }
public bool DynamicPips { get => _dynamicPips.Value; set => _dynamicPips.Value = value; }
public int DefaultPips { get => _defaultPips.Value; set => _defaultPips.Value = value; }
public int Depth { get => _depth.Value; set => _depth.Value = value; }
public int Del { get => _del.Value; set => _del.Value = value; }
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public decimal Drop { get => _drop.Value; set => _drop.Value = value; }
public decimal RsiMinimum { get => _rsiMinimum.Value; set => _rsiMinimum.Value = value; }
public decimal RsiMaximum { get => _rsiMaximum.Value; set => _rsiMaximum.Value = value; }
public int MaxTrades { get => _maxTrades.Value; set => _maxTrades.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AngrybirdXScalpingnStrategy()
{
_lotExponent = Param(nameof(LotExponent), 2m)
.SetDisplay("Lot Exponent", "Volume multiplier for additional trades", "General")
.SetGreaterThanZero();
_dynamicPips = Param(nameof(DynamicPips), false)
.SetDisplay("Dynamic Pips", "Use dynamic grid step", "Parameters");
_defaultPips = Param(nameof(DefaultPips), 12)
.SetDisplay("Default Pips", "Base grid step in ticks", "Parameters")
.SetGreaterThanZero();
_depth = Param(nameof(Depth), 24)
.SetDisplay("Depth", "Bars lookback for dynamic step", "Parameters")
.SetGreaterThanZero();
_del = Param(nameof(Del), 3)
.SetDisplay("Del", "Divider for range calculation", "Parameters")
.SetGreaterThanZero();
_takeProfit = Param(nameof(TakeProfit), 20m)
.SetDisplay("Take Profit", "Take profit in ticks", "Risk")
.SetNotNegative();
_stopLoss = Param(nameof(StopLoss), 500m)
.SetDisplay("Stop Loss", "Stop loss in ticks", "Risk")
.SetNotNegative();
_drop = Param(nameof(Drop), 500m)
.SetDisplay("CCI Drop", "CCI threshold for exit", "Parameters")
.SetNotNegative();
_rsiMinimum = Param(nameof(RsiMinimum), 30m)
.SetDisplay("RSI Minimum", "Minimum RSI to allow short", "Parameters")
.SetNotNegative();
_rsiMaximum = Param(nameof(RsiMaximum), 70m)
.SetDisplay("RSI Maximum", "Maximum RSI to allow long", "Parameters")
.SetNotNegative();
_maxTrades = Param(nameof(MaxTrades), 2)
.SetDisplay("Max Trades", "Maximum number of open trades", "Risk")
.SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "Parameters");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_highs.Clear();
_lows.Clear();
_lastBuyPrice = _lastSellPrice = null;
_tradeCount = 0;
_pipStep = 0m;
_prevClose = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = 14 };
var cci = new CommodityChannelIndex { Length = 55 };
var sub = SubscribeCandles(CandleType);
sub.Bind(rsi, cci, ProcessCandle)
.Start();
StartProtection(new Unit(TakeProfit, UnitTypes.Absolute), new Unit(StopLoss, UnitTypes.Absolute));
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, sub);
DrawIndicator(area, rsi);
DrawIndicator(area, cci);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsi, decimal cci)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
var high = candle.HighPrice;
var low = candle.LowPrice;
// calculate dynamic grid step
if (DynamicPips)
{
_highs.Enqueue(high);
_lows.Enqueue(low);
if (_highs.Count > Depth)
{
_highs.Dequeue();
_lows.Dequeue();
}
if (_highs.Count == Depth)
{
var highs = _highs.ToArray();
var lows = _lows.ToArray();
var highest = highs.Max();
var lowest = lows.Min();
var step = (highest - lowest) / Del;
var stepSize = Security?.PriceStep ?? 1m;
var minStep = (DefaultPips / (decimal)Del) * stepSize;
var maxStep = (DefaultPips * Del) * stepSize;
step = Math.Min(Math.Max(step, minStep), maxStep);
_pipStep = step;
}
}
else
{
_pipStep = DefaultPips * (Security?.PriceStep ?? 1m);
}
if (Position == 0)
{
_lastBuyPrice = _lastSellPrice = null;
_tradeCount = 0;
}
// close all on CCI reversal
if (Position > 0 && cci < -Drop)
{
if (Position > 0) SellMarket(Math.Abs(Position));
else if (Position < 0) BuyMarket(Math.Abs(Position));
return;
}
if (Position < 0 && cci > Drop)
{
if (Position > 0) SellMarket(Math.Abs(Position));
else if (Position < 0) BuyMarket(Math.Abs(Position));
return;
}
if (Position != 0)
{
if (_tradeCount < MaxTrades)
{
if (Position > 0 && _lastBuyPrice is decimal lb && lb - close >= _pipStep)
{
var vol = Volume * (decimal)Math.Pow((double)LotExponent, _tradeCount);
BuyMarket(vol);
_lastBuyPrice = close;
_tradeCount++;
}
else if (Position < 0 && _lastSellPrice is decimal ls && close - ls >= _pipStep)
{
var vol = Volume * (decimal)Math.Pow((double)LotExponent, _tradeCount);
SellMarket(vol);
_lastSellPrice = close;
_tradeCount++;
}
}
_prevClose = close;
return;
}
// first trade decision
if (_prevClose != 0m)
{
if (_prevClose > close && rsi > RsiMinimum)
{
SellMarket(Volume);
_lastSellPrice = close;
_tradeCount = 1;
}
else if (_prevClose <= close && rsi < RsiMaximum)
{
BuyMarket(Volume);
_lastBuyPrice = close;
_tradeCount = 1;
}
}
_prevClose = close;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from collections import deque
from StockSharp.Messages import DataType, Unit, UnitTypes, CandleStates
from StockSharp.Algo.Indicators import CommodityChannelIndex, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class angrybird_x_scalpingn_strategy(Strategy):
def __init__(self):
super(angrybird_x_scalpingn_strategy, self).__init__()
self._lot_exponent = self.Param("LotExponent", 2.0) \
.SetDisplay("Lot Exponent", "Volume multiplier for additional trades", "General")
self._dynamic_pips = self.Param("DynamicPips", False) \
.SetDisplay("Dynamic Pips", "Use dynamic grid step", "Parameters")
self._default_pips = self.Param("DefaultPips", 12) \
.SetDisplay("Default Pips", "Base grid step in ticks", "Parameters")
self._depth = self.Param("Depth", 24) \
.SetDisplay("Depth", "Bars lookback for dynamic step", "Parameters")
self._del = self.Param("Del", 3) \
.SetDisplay("Del", "Divider for range calculation", "Parameters")
self._take_profit = self.Param("TakeProfit", 20.0) \
.SetDisplay("Take Profit", "Take profit in ticks", "Risk")
self._stop_loss = self.Param("StopLoss", 500.0) \
.SetDisplay("Stop Loss", "Stop loss in ticks", "Risk")
self._drop = self.Param("Drop", 500.0) \
.SetDisplay("CCI Drop", "CCI threshold for exit", "Parameters")
self._rsi_minimum = self.Param("RsiMinimum", 30.0) \
.SetDisplay("RSI Minimum", "Minimum RSI to allow short", "Parameters")
self._rsi_maximum = self.Param("RsiMaximum", 70.0) \
.SetDisplay("RSI Maximum", "Maximum RSI to allow long", "Parameters")
self._max_trades = self.Param("MaxTrades", 2) \
.SetDisplay("Max Trades", "Maximum number of open trades", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles", "Parameters")
self._highs = deque()
self._lows = deque()
self._last_buy_price = None
self._last_sell_price = None
self._trade_count = 0
self._pip_step = 0.0
self._prev_close = 0.0
@property
def LotExponent(self):
return self._lot_exponent.Value
@LotExponent.setter
def LotExponent(self, value):
self._lot_exponent.Value = value
@property
def DynamicPips(self):
return self._dynamic_pips.Value
@DynamicPips.setter
def DynamicPips(self, value):
self._dynamic_pips.Value = value
@property
def DefaultPips(self):
return self._default_pips.Value
@DefaultPips.setter
def DefaultPips(self, value):
self._default_pips.Value = value
@property
def Depth(self):
return self._depth.Value
@Depth.setter
def Depth(self, value):
self._depth.Value = value
@property
def Del(self):
return self._del.Value
@Del.setter
def Del(self, value):
self._del.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def Drop(self):
return self._drop.Value
@Drop.setter
def Drop(self, value):
self._drop.Value = value
@property
def RsiMinimum(self):
return self._rsi_minimum.Value
@RsiMinimum.setter
def RsiMinimum(self, value):
self._rsi_minimum.Value = value
@property
def RsiMaximum(self):
return self._rsi_maximum.Value
@RsiMaximum.setter
def RsiMaximum(self, value):
self._rsi_maximum.Value = value
@property
def MaxTrades(self):
return self._max_trades.Value
@MaxTrades.setter
def MaxTrades(self, value):
self._max_trades.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(angrybird_x_scalpingn_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = 14
cci = CommodityChannelIndex()
cci.Length = 55
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(rsi, cci, self.ProcessCandle).Start()
self.StartProtection(
Unit(self.TakeProfit, UnitTypes.Absolute),
Unit(self.StopLoss, UnitTypes.Absolute))
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, rsi)
self.DrawIndicator(area, cci)
def ProcessCandle(self, candle, rsi, cci):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
rsi_val = float(rsi)
cci_val = float(cci)
if self.DynamicPips:
self._highs.append(high)
self._lows.append(low)
if len(self._highs) > self.Depth:
self._highs.popleft()
self._lows.popleft()
if len(self._highs) == self.Depth:
highest = max(self._highs)
lowest = min(self._lows)
step_val = (highest - lowest) / float(self.Del)
step_raw = self.Security.PriceStep
step_size = float(step_raw) if step_raw is not None else 1.0
min_step = (float(self.DefaultPips) / float(self.Del)) * step_size
max_step = (float(self.DefaultPips) * float(self.Del)) * step_size
step_val = min(max(step_val, min_step), max_step)
self._pip_step = step_val
else:
step_raw = self.Security.PriceStep
step_size = float(step_raw) if step_raw is not None else 1.0
self._pip_step = float(self.DefaultPips) * step_size
if self.Position == 0:
self._last_buy_price = None
self._last_sell_price = None
self._trade_count = 0
if self.Position > 0 and cci_val < -float(self.Drop):
if self.Position > 0:
self.SellMarket(abs(self.Position))
elif self.Position < 0:
self.BuyMarket(abs(self.Position))
return
if self.Position < 0 and cci_val > float(self.Drop):
if self.Position > 0:
self.SellMarket(abs(self.Position))
elif self.Position < 0:
self.BuyMarket(abs(self.Position))
return
if self.Position != 0:
if self._trade_count < self.MaxTrades:
if (self.Position > 0
and self._last_buy_price is not None
and self._last_buy_price - close >= self._pip_step):
vol = self.Volume * (float(self.LotExponent) ** self._trade_count)
self.BuyMarket(vol)
self._last_buy_price = close
self._trade_count += 1
elif (self.Position < 0
and self._last_sell_price is not None
and close - self._last_sell_price >= self._pip_step):
vol = self.Volume * (float(self.LotExponent) ** self._trade_count)
self.SellMarket(vol)
self._last_sell_price = close
self._trade_count += 1
self._prev_close = close
return
if self._prev_close != 0.0:
if self._prev_close > close and rsi_val > float(self.RsiMinimum):
self.SellMarket(self.Volume)
self._last_sell_price = close
self._trade_count = 1
elif self._prev_close <= close and rsi_val < float(self.RsiMaximum):
self.BuyMarket(self.Volume)
self._last_buy_price = close
self._trade_count = 1
self._prev_close = close
def OnReseted(self):
super(angrybird_x_scalpingn_strategy, self).OnReseted()
self._highs = deque()
self._lows = deque()
self._last_buy_price = None
self._last_sell_price = None
self._trade_count = 0
self._pip_step = 0.0
self._prev_close = 0.0
def CreateClone(self):
return angrybird_x_scalpingn_strategy()