Pin Bar Magic-Strategie
Erkennt bullische und bärische Pin Bars innerhalb eines Trends, der durch ein Trio von gleitenden Durchschnitten definiert wird. Aufträge werden an den Kerzenextremen platziert und nach einigen Kerzen storniert, wenn sie nicht ausgeführt werden. Die Positionsgröße wird aus einem prozentualen Eigenkapitalrisiko und dem ATR-basierten Stop-Abstand berechnet.
Die Methode zielt darauf ab, scharfe Umkehrungen an bedeutenden Unterstützungs- oder Widerstandsniveaus zu erfassen. Positionen werden beendet, wenn die schnelle und mittlere EMA in die entgegengesetzte Richtung kreuzen, was eine Trendschwäche signalisiert.
Details
- Einstiegskriterien:
- Long: Schnelle EMA > Mittlere EMA > Langsame SMA, bullischer Pin Bar, der eine der Durchschnitte durchsticht.
- Short: Schnelle EMA < Mittlere EMA < Langsame SMA, bärischer Pin Bar, der eine der Durchschnitte durchsticht.
- Ausstiegskriterien:
- Schnelle EMA kreuzt die mittlere EMA in die entgegengesetzte Richtung.
- Indikatoren:
- Langsame SMA (Periode 50)
- Mittlere EMA (18) und schnelle EMA (6)
- ATR (Länge 14)
- Stops: Positionsrisiko = EquityRisk% des Kontos mit Stop bei ATR * Multiplikator.
- Standardwerte:
EquityRisk= 3AtrMultiplier= 0.5SlowSmaLength= 50MediumEmaLength= 18FastEmaLength= 6AtrLength= 14CancelEntryBars= 3
- Filter:
- Kursaktions-Umkehr
- Funktioniert standardmäßig auf 1-Stunden-Kerzen
- Indikatoren: EMA, SMA, ATR
- Stops: Ja
- Komplexität: Hoch
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>
/// Pin Bar Magic Strategy.
/// Detects pin bar candlestick patterns at EMA/SMA levels in trending markets.
/// Buys on bullish pin bars piercing moving averages in uptrend.
/// Sells on bearish pin bars piercing moving averages in downtrend.
/// </summary>
public class PinBarMagicStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleTypeParam;
private readonly StrategyParam<int> _slowSmaLength;
private readonly StrategyParam<int> _mediumEmaLength;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _cooldownBars;
private SimpleMovingAverage _slowSma;
private ExponentialMovingAverage _mediumEma;
private ExponentialMovingAverage _fastEma;
private int _cooldownRemaining;
public PinBarMagicStrategy()
{
_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General");
_slowSmaLength = Param(nameof(SlowSmaLength), 50)
.SetGreaterThanZero()
.SetDisplay("Slow SMA Period", "Slow SMA period", "Indicators");
_mediumEmaLength = Param(nameof(MediumEmaLength), 18)
.SetGreaterThanZero()
.SetDisplay("Medium EMA Period", "Medium EMA period", "Indicators");
_fastEmaLength = Param(nameof(FastEmaLength), 6)
.SetGreaterThanZero()
.SetDisplay("Fast EMA Period", "Fast EMA period", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk");
}
public DataType CandleType
{
get => _candleTypeParam.Value;
set => _candleTypeParam.Value = value;
}
public int SlowSmaLength
{
get => _slowSmaLength.Value;
set => _slowSmaLength.Value = value;
}
public int MediumEmaLength
{
get => _mediumEmaLength.Value;
set => _mediumEmaLength.Value = value;
}
public int FastEmaLength
{
get => _fastEmaLength.Value;
set => _fastEmaLength.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_slowSma = null;
_mediumEma = null;
_fastEma = null;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_slowSma = new SimpleMovingAverage { Length = SlowSmaLength };
_mediumEma = new ExponentialMovingAverage { Length = MediumEmaLength };
_fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_slowSma, _mediumEma, _fastEma, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _slowSma);
DrawIndicator(area, _mediumEma);
DrawIndicator(area, _fastEma);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal slowSma, decimal mediumEma, decimal fastEma)
{
if (candle.State != CandleStates.Finished)
return;
if (!_slowSma.IsFormed || !_mediumEma.IsFormed || !_fastEma.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
// Check pin bar patterns
var candleRange = candle.HighPrice - candle.LowPrice;
if (candleRange == 0)
return;
var bullishPinBar = false;
var bearishPinBar = false;
if (candle.ClosePrice > candle.OpenPrice)
{
var lowerWick = candle.OpenPrice - candle.LowPrice;
bullishPinBar = lowerWick > 0.60m * candleRange;
var upperWick = candle.HighPrice - candle.ClosePrice;
bearishPinBar = upperWick > 0.60m * candleRange;
}
else
{
var lowerWick = candle.ClosePrice - candle.LowPrice;
bullishPinBar = lowerWick > 0.60m * candleRange;
var upperWick = candle.HighPrice - candle.OpenPrice;
bearishPinBar = upperWick > 0.60m * candleRange;
}
// Trend conditions - EMA fan
var fanUpTrend = fastEma > mediumEma && mediumEma > slowSma;
var fanDnTrend = fastEma < mediumEma && mediumEma < slowSma;
// Piercing conditions - candle wick pierces through an MA level
var bullPierce = (candle.LowPrice < fastEma && candle.ClosePrice > fastEma) ||
(candle.LowPrice < mediumEma && candle.ClosePrice > mediumEma) ||
(candle.LowPrice < slowSma && candle.ClosePrice > slowSma);
var bearPierce = (candle.HighPrice > fastEma && candle.ClosePrice < fastEma) ||
(candle.HighPrice > mediumEma && candle.ClosePrice < mediumEma) ||
(candle.HighPrice > slowSma && candle.ClosePrice < slowSma);
// Buy: uptrend + bullish pin bar + pierce
if (fanUpTrend && bullishPinBar && bullPierce && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Sell: downtrend + bearish pin bar + pierce
else if (fanDnTrend && bearishPinBar && bearPierce && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Exit long: trend reversal (fast crosses below medium)
else if (Position > 0 && fastEma < mediumEma)
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short: trend reversal (fast crosses above medium)
else if (Position < 0 && fastEma > mediumEma)
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = 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, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class pin_bar_magic_strategy(Strategy):
"""Pin Bar Magic Strategy."""
def __init__(self):
super(pin_bar_magic_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General")
self._slow_sma_length = self.Param("SlowSmaLength", 50) \
.SetDisplay("Slow SMA Period", "Slow SMA period", "Indicators")
self._medium_ema_length = self.Param("MediumEmaLength", 18) \
.SetDisplay("Medium EMA Period", "Medium EMA period", "Indicators")
self._fast_ema_length = self.Param("FastEmaLength", 6) \
.SetDisplay("Fast EMA Period", "Fast EMA period", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk")
self._slow_sma = None
self._medium_ema = None
self._fast_ema = None
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(pin_bar_magic_strategy, self).OnReseted()
self._slow_sma = None
self._medium_ema = None
self._fast_ema = None
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(pin_bar_magic_strategy, self).OnStarted2(time)
self._slow_sma = SimpleMovingAverage()
self._slow_sma.Length = int(self._slow_sma_length.Value)
self._medium_ema = ExponentialMovingAverage()
self._medium_ema.Length = int(self._medium_ema_length.Value)
self._fast_ema = ExponentialMovingAverage()
self._fast_ema.Length = int(self._fast_ema_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._slow_sma, self._medium_ema, self._fast_ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._slow_sma)
self.DrawIndicator(area, self._medium_ema)
self.DrawIndicator(area, self._fast_ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, slow_sma, medium_ema, fast_ema):
if candle.State != CandleStates.Finished:
return
if not self._slow_sma.IsFormed or not self._medium_ema.IsFormed or not self._fast_ema.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
candle_range = float(candle.HighPrice - candle.LowPrice)
if candle_range == 0:
return
bullish_pin_bar = False
bearish_pin_bar = False
if float(candle.ClosePrice) > float(candle.OpenPrice):
lower_wick = float(candle.OpenPrice - candle.LowPrice)
bullish_pin_bar = lower_wick > 0.60 * candle_range
upper_wick = float(candle.HighPrice - candle.ClosePrice)
bearish_pin_bar = upper_wick > 0.60 * candle_range
else:
lower_wick = float(candle.ClosePrice - candle.LowPrice)
bullish_pin_bar = lower_wick > 0.60 * candle_range
upper_wick = float(candle.HighPrice - candle.OpenPrice)
bearish_pin_bar = upper_wick > 0.60 * candle_range
slow_sma_val = float(slow_sma)
medium_ema_val = float(medium_ema)
fast_ema_val = float(fast_ema)
fan_up_trend = fast_ema_val > medium_ema_val and medium_ema_val > slow_sma_val
fan_dn_trend = fast_ema_val < medium_ema_val and medium_ema_val < slow_sma_val
close = float(candle.ClosePrice)
low = float(candle.LowPrice)
high = float(candle.HighPrice)
bull_pierce = (low < fast_ema_val and close > fast_ema_val) or \
(low < medium_ema_val and close > medium_ema_val) or \
(low < slow_sma_val and close > slow_sma_val)
bear_pierce = (high > fast_ema_val and close < fast_ema_val) or \
(high > medium_ema_val and close < medium_ema_val) or \
(high > slow_sma_val and close < slow_sma_val)
cooldown = int(self._cooldown_bars.Value)
if fan_up_trend and bullish_pin_bar and bull_pierce and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif fan_dn_trend and bearish_pin_bar and bear_pierce and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
elif self.Position > 0 and fast_ema_val < medium_ema_val:
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and fast_ema_val > medium_ema_val:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
def CreateClone(self):
return pin_bar_magic_strategy()