O Tweezer Bottom é um padrão de reversão de duas velas que aparece após um declínio. Ambas as velas compartilham uma mínima similar, sinalizando que os vendedores falharam em empurrar além daquele nível.
Os testes indicam um retorno anual médio de aproximadamente 184%. Funciona melhor no mercado de criptomoedas.
Esta estratégia entra comprada após a segunda vela confirmar o fundo compartilhado, antecipando um repique à medida que a pressão vendedora se esgota.
Os stops são colocados logo abaixo da mínima comum para gerenciar o risco, e a posição encerra se o preço não conseguir subir.
Detalhes
Critérios de entrada: correspondência de padrão
Comprado/Vendido: Ambos
Critérios de saída: stop-loss ou sinal oposto
Stops: Sim, baseado em percentual
Valores padrão:
CandleType = 15 minutos
TolerancePercent = 0.1
StopLossPercent = 2
A estratégia só compra. O stop fica StopLossPercent abaixo da mínima mais baixa do padrão e a posição fecha quando uma vela fecha abaixo dele.
Filtros:
Categoria: Padrão
Direção: Ambos
Indicadores: Candlestick
Stops: Sim
Complexidade: Intermediário
Período: Intradiário
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>
/// Tweezer Bottom strategy.
/// While flat it buys after a bearish candle followed by a bullish one whose low is within TolerancePercent of the first low.
/// The stop lies StopLossPercent below the pattern's lowest low, and a close beyond it closes the position.
/// </summary>
public class TweezerBottomStrategy : Strategy
{
private readonly StrategyParam<decimal> _tolerancePercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private readonly List<ICandleMessage> _candles = [];
private decimal _stopPrice;
/// <summary>
/// How close the two extremes must be, in percent of the first.
/// </summary>
public decimal TolerancePercent
{
get => _tolerancePercent.Value;
set => _tolerancePercent.Value = value;
}
/// <summary>
/// Distance of the stop beyond the pattern, in percent.
/// </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 TweezerBottomStrategy()
{
_tolerancePercent = Param(nameof(TolerancePercent), 0.1m)
.SetNotNegative()
.SetDisplay("Tolerance %", "How close the two extremes must be, in percent of the first", "Pattern");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Distance of the stop beyond the pattern, in percent", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).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();
_candles.Clear();
_stopPrice = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candles.Clear();
_stopPrice = default;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
_candles.Add(candle);
if (_candles.Count > 2)
_candles.RemoveAt(0);
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position > 0)
{
if (candle.ClosePrice <= _stopPrice)
SellMarket(Position);
return;
}
if (Position != 0 || _candles.Count < 2)
return;
var c0 = _candles[0];
var c1 = _candles[1];
if (!(c0.ClosePrice < c0.OpenPrice && c1.ClosePrice > c1.OpenPrice && Math.Abs(c0.LowPrice - c1.LowPrice) <= c0.LowPrice * TolerancePercent / 100m))
return;
BuyMarket(Volume);
_stopPrice = Math.Min(c0.LowPrice, c1.LowPrice) * (1 - StopLossPercent / 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, Math, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class tweezer_bottom_strategy(Strategy):
"""
Tweezer Bottom strategy.
While flat it buys after a bearish candle followed by a bullish one whose low is within TolerancePercent of the first low.
The stop lies StopLossPercent below the pattern's lowest low, and a close beyond it closes the position.
"""
def __init__(self):
super(tweezer_bottom_strategy, self).__init__()
self._tolerance_percent = self.Param("TolerancePercent", 0.1).SetNotNegative().SetDisplay("Tolerance %", "How close the two extremes must be, in percent of the first", "Pattern")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Distance of the stop beyond the pattern, in percent", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._candles = []
self._stop_price = Decimal(0)
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(tweezer_bottom_strategy, self).OnReseted()
self._candles = []
self._stop_price = Decimal(0)
def OnStarted2(self, time):
super(tweezer_bottom_strategy, self).OnStarted2(time)
self._candles = []
self._stop_price = Decimal(0)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
self._candles.append(candle)
if len(self._candles) > 2:
self._candles.pop(0)
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position > 0:
if candle.ClosePrice <= self._stop_price:
self.SellMarket(self.Position)
return
if self.Position != 0 or len(self._candles) < 2:
return
c0, c1 = self._candles
if not (c0.ClosePrice < c0.OpenPrice and c1.ClosePrice > c1.OpenPrice and Math.Abs(c0.LowPrice - c1.LowPrice) <= c0.LowPrice * Decimal(self._tolerance_percent.Value) / Decimal(100)):
return
self.BuyMarket(self.Volume)
self._stop_price = min(c0.LowPrice, c1.LowPrice) * (Decimal(1) - Decimal(self._stop_loss_percent.Value) / Decimal(100))
def CreateClone(self):
return tweezer_bottom_strategy()