Pinbars heben plötzliche Preisablehnungen hervor und können kurzfristige Wendepunkte signalisieren. Diese Strategie misst die Länge des Kerzendochts relativ zu seinem Körper und sucht nach langen Schatten, die aus der jüngsten Preisbewegung herausragen. Ein gleitender Durchschnittsfilter hilft, in Richtung des zugrunde liegenden Trends zu handeln.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 82%. Sie funktioniert am besten auf dem Aktienmarkt.
Bei jeder Kerzenaktualisierung berechnet das System obere und untere Schatten und vergleicht sie mit der Körpergröße. Ein bullischer Pinbar mit langem unterem Docht kann einen Long-Einstieg auslösen, wenn der Preis über dem gleitenden Durchschnitt liegt. Ebenso kann ein bärischer Pinbar mit einem ausgedehnten oberen Docht eine Short-Position in einem Abwärtstrend einleiten. Stops werden auf einen festen Prozentsatz vom Einstieg gesetzt.
Der Trade wird geschlossen, wenn ein entgegengesetzter Pinbar gegen die offene Position erscheint oder der schützende Stop erreicht wird. Die Kombination der Pinbar-Logik mit einem Trendfilter verbessert die Zuverlässigkeit durch Vermeidung kontrend-Setups.
Details
Einstiegskriterien: Pinbar mit langem Docht und kleinem entgegengesetzten Schatten, durch Trend bestätigt.
Long/Short: Beide.
Ausstiegskriterien: Entgegengesetzter Pinbar oder Stop-Loss.
Stops: Ja, prozentbasiert.
Standardwerte:
TailToBodyRatio = 2
OppositeTailRatio = 0.5
MAPeriod = 20
CandleType = 15 minute
StopLossPercent = 1
Filter:
Kategorie: Muster
Richtung: Beide
Indikatoren: Candlestick, MA
Stops: Ja
Komplexität: Mittel
Zeitrahmen: Intraday
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
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>
/// Pinbar Reversal strategy.
/// Enters long on bullish pinbar (long lower wick) below SMA.
/// Enters short on bearish pinbar (long upper wick) above SMA.
/// Exits via SMA crossover.
/// </summary>
public class PinbarReversalStrategy : Strategy
{
private readonly StrategyParam<decimal> _tailToBodyRatio;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private int _cooldown;
/// <summary>
/// Tail to body ratio.
/// </summary>
public decimal TailToBodyRatio
{
get => _tailToBodyRatio.Value;
set => _tailToBodyRatio.Value = value;
}
/// <summary>
/// MA Period.
/// </summary>
public int MAPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public PinbarReversalStrategy()
{
_tailToBodyRatio = Param(nameof(TailToBodyRatio), 2.0m)
.SetRange(1.5m, 5.0m)
.SetDisplay("Tail/Body Ratio", "Min tail to body ratio", "Pattern");
_maPeriod = Param(nameof(MAPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Period for SMA", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_cooldown = 0;
var sma = new SimpleMovingAverage { Length = MAPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldown > 0)
{
_cooldown--;
return;
}
var bodySize = Math.Abs(candle.OpenPrice - candle.ClosePrice);
var lowerWick = Math.Min(candle.OpenPrice, candle.ClosePrice) - candle.LowPrice;
var upperWick = candle.HighPrice - Math.Max(candle.OpenPrice, candle.ClosePrice);
// Bullish pinbar: long lower wick, small upper wick
var isBullishPinbar = bodySize > 0 && lowerWick > bodySize * TailToBodyRatio && upperWick < bodySize * 0.5m;
// Bearish pinbar: long upper wick, small lower wick
var isBearishPinbar = bodySize > 0 && upperWick > bodySize * TailToBodyRatio && lowerWick < bodySize * 0.5m;
if (Position == 0 && isBullishPinbar && candle.ClosePrice < smaValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && isBearishPinbar && candle.ClosePrice > smaValue)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && candle.ClosePrice < smaValue)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && candle.ClosePrice > smaValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
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 StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class pinbar_reversal_strategy(Strategy):
"""
Pinbar Reversal strategy.
Enters long on bullish pinbar (long lower wick) below SMA.
Enters short on bearish pinbar (long upper wick) above SMA.
Exits via SMA crossover.
"""
def __init__(self):
super(pinbar_reversal_strategy, self).__init__()
self._tail_to_body_ratio = self.Param("TailToBodyRatio", 2.0).SetDisplay("Tail/Body Ratio", "Min tail to body ratio", "Pattern")
self._ma_period = self.Param("MAPeriod", 20).SetDisplay("MA Period", "Period for SMA", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(pinbar_reversal_strategy, self).OnReseted()
self._cooldown = 0
def OnStarted2(self, time):
super(pinbar_reversal_strategy, self).OnStarted2(time)
self._cooldown = 0
sma = SimpleMovingAverage()
sma.Length = self._ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, sma_val):
if candle.State != CandleStates.Finished:
return
if self._cooldown > 0:
self._cooldown -= 1
return
body_size = abs(float(candle.OpenPrice) - float(candle.ClosePrice))
lower_wick = min(float(candle.OpenPrice), float(candle.ClosePrice)) - float(candle.LowPrice)
upper_wick = float(candle.HighPrice) - max(float(candle.OpenPrice), float(candle.ClosePrice))
ratio = float(self._tail_to_body_ratio.Value)
# Bullish pinbar: long lower wick, small upper wick
is_bullish_pinbar = body_size > 0 and lower_wick > body_size * ratio and upper_wick < body_size * 0.5
# Bearish pinbar: long upper wick, small lower wick
is_bearish_pinbar = body_size > 0 and upper_wick > body_size * ratio and lower_wick < body_size * 0.5
close = float(candle.ClosePrice)
sv = float(sma_val)
cd = self._cooldown_bars.Value
if self.Position == 0 and is_bullish_pinbar and close < sv:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and is_bearish_pinbar and close > sv:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and close < sv:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and close > sv:
self.BuyMarket()
self._cooldown = cd
def CreateClone(self):
return pinbar_reversal_strategy()