FT Bill Williams Händlerstrategie
Überblick
Die FT Bill Williams Trader Strategy ist eine hochrangige StockSharp-Übersetzung des MetaTrader-Expertenberaters „FT_BillWillams_Trader“. Es kombiniert Bill Williams-Fraktale mit dem Alligator-Indikator, um Trendausbrüche zu handeln. Die Strategie sucht nach neuen Fraktalen, überprüft, ob die Alligator-Struktur die Ausbruchsrichtung bestätigt, und wendet optional Abstands-, Ausrichtungs- und Umkehrsignalfilter an, bevor eine Position eröffnet wird.
Handelslogik
- Fraktale Erkennung – die Strategie puffert die aktuellsten
FractalPeriod Hochs und Tiefs. Wenn der mittlere Balken den höchsten (oder niedrigsten) Punkt im Fenster darstellt, wird ein neues Ausbruchsniveau aufgezeichnet. Über/unter dem Fraktal wird ein IndentPoints-Offset hinzugefügt, um vorzeitige Einträge zu vermeiden.
- Breakout-Bestätigung – abhängig von
EntryConfirmation:
PriceBreakout bestätigt, wann die Kerzenspanne das Ausbruchsniveau überschreitet.
CloseBreakout wartet darauf, dass der Schlusskurs der vorherigen Kerze über dem Niveau liegt.
- Entfernungsprüfung – Eingaben werden abgelehnt, wenn das Ausbruchsniveau weiter als
MaxDistancePoints von den Alligator-Lippen entfernt ist (vorheriger Balkenwert). Setzen Sie den Abstand auf Null, um den Filter zu deaktivieren.
- Zahnfilter – wenn
UseTeethFilter aktiviert ist, muss der vorherige Schlusskurs über (für Long-Positionen) oder unter (für Short-Positionen) den Alligator-Zähnen liegen.
- Trendausrichtung – bei
UseTrendAlignment = true müssen Lippen, Zähne und Kiefer mindestens TeethLipsDistancePoints bzw. JawTeethDistancePoints Punkte voneinander entfernt sein, um zu bestätigen, dass Alligator im Trend liegt.
- Umgekehrte Ausgänge – wenn
ReverseExit = OppositeFractal, schließt jedes neue entgegengesetzte Fraktal sofort die offene Position. Bei OppositePosition schließt die Strategie zunächst den aktuellen Trade ab, bevor sie einen in die entgegengesetzte Richtung eröffnet.
- Jaw Exit –
JawExit definiert, ob die Position geschlossen wird, wenn der Preis den Alligator-Kiefer kreuzt (Intrabar oder bei Kerzenschluss).
- Trailing Stop – wenn
EnableTrailing wahr ist und der Handel profitabel ist, bewegt sich der Stop zu den Lippen oder Zähnen, abhängig von der relativen Neigung der Lippen und dem SlopeSmaPeriod SMA. Anfängliche Schutzstopps und Gewinnziele werden durch StopLossPoints und TakeProfitPoints gesteuert.
Parameter
| Eigentum |
Beschreibung |
Standard |
OrderVolume |
Handelsvolumen, das beim Versenden von Marktaufträgen verwendet wird. |
0.1 |
FractalPeriod |
Anzahl der Balken im Fraktalmuster (ungerade Werte empfohlen). |
5 |
IndentPoints |
Zum Ausbruchsniveau hinzugefügter Offset (in Punkten). |
1 |
EntryConfirmation |
Breakout-Bestätigungsmodus (PriceBreakout, CloseBreakout). |
CloseBreakout |
UseTeethFilter |
Erfordern, dass sich der vorherige Abschluss auf der richtigen Seite der Alligator-Zähne befindet. |
true |
MaxDistancePoints |
Maximaler Abstand zwischen Ausbruchsebene und Alligator Lippen (Punkten). |
1000 |
UseTrendAlignment |
Erzwingen Sie den Mindestabstand zwischen Alligator Zeilen. |
false |
JawTeethDistancePoints |
Mindestabstand zwischen Kiefer und Zähnen, der im Ausrichtungsfilter verwendet wird. |
10 |
TeethLipsDistancePoints |
Mindestabstand zwischen Zähnen und Lippen, der im Ausrichtungsfilter verwendet wird. |
10 |
JawExit |
Modus zum Schließen von Positionen bei Backenkreuzung (Disabled, PriceCross, CloseCross). |
CloseCross |
ReverseExit |
Umgang mit Gegensignalen (Disabled, OppositeFractal, OppositePosition). |
OppositePosition |
EnableTrailing |
Aktivieren Sie die Alligator-basierte Trailing-Stop-Verwaltung. |
true |
SlopeSmaPeriod |
Periode des SMA, der mit der Lippensteigung verglichen wird. |
5 |
StopLossPoints |
Stop-Loss-Distanz in Punkten (0 deaktiviert). |
50 |
TakeProfitPoints |
Take-Profit-Distanz in Punkten (0 deaktiviert). |
50 |
JawPeriod, TeethPeriod, LipsPeriod |
Zeiträume für die Zeilen Alligator. |
13, 8, 5 |
JawShift, TeethShift, LipsShift |
Vorwärtsverschiebung für jede Alligator-Zeile. |
8, 5, 3 |
MaMethod |
Typ des gleitenden Durchschnitts für Alligator (Simple, Exponential, Smoothed, Weighted). |
Simple |
AppliedPrice |
Der an Alligator gelieferte Kerzenpreis. |
CandlePrice.Median |
CandleType |
Aus den Marktdaten abonnierter Kerzentyp. |
15-minute timeframe |
Zusätzliche Hinweise
- Die Strategie zeichnet die Alligator-Linien und führt Trades im Standard-Chartbereich aus.
FractalPeriod sollte ungerade bleiben, sodass der mittlere Balken die fraktale Spitze darstellt; Der Standardwert entspricht dem ursprünglichen Expert Advisor.
- Entfernungsbasierte Parameter (
IndentPoints, MaxDistancePoints, JawTeethDistancePoints, TeethLipsDistancePoints, StopLossPoints, TakeProfitPoints) werden in Brokerpunkten (Security.PriceStep) ausgedrückt.
- Trailing Stops und Jaw Exits basieren auf abgeschlossenen Kerzen und spiegeln die ursprüngliche MQL-Logik wider, die mit den vorherigen Balkenwerten der Alligator funktioniert.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Bill Williams Fractal Breakout strategy filtered by Alligator alignment.
/// Buys on up-fractal breakout when price is above alligator teeth,
/// sells on down-fractal breakout when price is below alligator teeth.
/// Exits on opposite signal (reverse position).
/// </summary>
public class FTBillWillamsTraderStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _jawPeriod;
private readonly StrategyParam<int> _teethPeriod;
private readonly StrategyParam<int> _lipsPeriod;
private readonly StrategyParam<int> _fractalLen;
private SMA _jaw = null!;
private SMA _teeth = null!;
private SMA _lips = null!;
private decimal[] _highBuf = Array.Empty<decimal>();
private decimal[] _lowBuf = Array.Empty<decimal>();
private int _bufCount;
private decimal? _pendingBuyLevel;
private decimal? _pendingSellLevel;
private decimal _prevJaw;
private decimal _prevTeeth;
private decimal _prevLips;
private decimal _entryPrice;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int JawPeriod
{
get => _jawPeriod.Value;
set => _jawPeriod.Value = value;
}
public int TeethPeriod
{
get => _teethPeriod.Value;
set => _teethPeriod.Value = value;
}
public int LipsPeriod
{
get => _lipsPeriod.Value;
set => _lipsPeriod.Value = value;
}
public int FractalLen
{
get => _fractalLen.Value;
set => _fractalLen.Value = value;
}
public FTBillWillamsTraderStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
.SetDisplay("Candle Type", "Candle type for strategy", "General");
_jawPeriod = Param(nameof(JawPeriod), 13)
.SetDisplay("Jaw Period", "Alligator jaw SMA period", "Alligator");
_teethPeriod = Param(nameof(TeethPeriod), 8)
.SetDisplay("Teeth Period", "Alligator teeth SMA period", "Alligator");
_lipsPeriod = Param(nameof(LipsPeriod), 5)
.SetDisplay("Lips Period", "Alligator lips SMA period", "Alligator");
_fractalLen = Param(nameof(FractalLen), 5)
.SetDisplay("Fractal Length", "Number of bars for fractal detection", "Signals");
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_jaw = new SMA { Length = JawPeriod };
_teeth = new SMA { Length = TeethPeriod };
_lips = new SMA { Length = LipsPeriod };
_highBuf = new decimal[FractalLen];
_lowBuf = new decimal[FractalLen];
_bufCount = 0;
_pendingBuyLevel = null;
_pendingSellLevel = null;
_prevJaw = 0;
_prevTeeth = 0;
_prevLips = 0;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_jaw = new SMA { Length = JawPeriod };
_teeth = new SMA { Length = TeethPeriod };
_lips = new SMA { Length = LipsPeriod };
_highBuf = new decimal[FractalLen];
_lowBuf = new decimal[FractalLen];
_bufCount = 0;
_pendingBuyLevel = null;
_pendingSellLevel = null;
_prevJaw = 0;
_prevTeeth = 0;
_prevLips = 0;
_entryPrice = 0;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_jaw, _teeth, _lips, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _jaw);
DrawIndicator(area, _teeth);
DrawIndicator(area, _lips);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal jawVal, decimal teethVal, decimal lipsVal)
{
if (candle.State != CandleStates.Finished)
return;
// Update fractal buffers
UpdateFractals(candle);
var close = candle.ClosePrice;
var high = candle.HighPrice;
var low = candle.LowPrice;
// Manage existing positions - exit on opposite signal
if (Position > 0)
{
// Close long if price breaks below pending sell level or close drops below teeth
if (_pendingSellLevel is decimal sellLvl && low < sellLvl)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
// Close short if price breaks above pending buy level or close rises above teeth
if (_pendingBuyLevel is decimal buyLvl && high > buyLvl)
{
BuyMarket();
_entryPrice = 0;
}
}
// Enter long: price breaks above up-fractal level, close above teeth (bullish)
if (Position <= 0 && _pendingBuyLevel is decimal pendBuy)
{
if (high > pendBuy && close > teethVal)
{
if (Position < 0)
BuyMarket(); // close short first
BuyMarket();
_entryPrice = close;
}
}
// Enter short: price breaks below down-fractal level, close below teeth (bearish)
if (Position >= 0 && _pendingSellLevel is decimal pendSell)
{
if (low < pendSell && close < teethVal)
{
if (Position > 0)
SellMarket(); // close long first
SellMarket();
_entryPrice = close;
}
}
_prevJaw = jawVal;
_prevTeeth = teethVal;
_prevLips = lipsVal;
}
private void UpdateFractals(ICandleMessage candle)
{
var len = _highBuf.Length;
if (len < 3)
return;
// Shift buffers
Array.Copy(_highBuf, 1, _highBuf, 0, len - 1);
_highBuf[len - 1] = candle.HighPrice;
Array.Copy(_lowBuf, 1, _lowBuf, 0, len - 1);
_lowBuf[len - 1] = candle.LowPrice;
_bufCount++;
if (_bufCount < len)
return;
var wing = (len - 1) / 2;
var center = len - 1 - wing;
// Check up fractal
var centerHigh = _highBuf[center];
var isUp = true;
for (var i = 0; i < len; i++)
{
if (i != center && _highBuf[i] >= centerHigh)
{
isUp = false;
break;
}
}
if (isUp)
_pendingBuyLevel = centerHigh;
// Check down fractal
var centerLow = _lowBuf[center];
var isDown = true;
for (var i = 0; i < len; i++)
{
if (i != center && _lowBuf[i] <= centerLow)
{
isDown = false;
break;
}
}
if (isDown)
_pendingSellLevel = centerLow;
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import SimpleMovingAverage
class ft_bill_willams_trader_strategy(Strategy):
def __init__(self):
super(ft_bill_willams_trader_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))) \
.SetDisplay("Candle Type", "Candle type for strategy", "General")
self._jaw_period = self.Param("JawPeriod", 13) \
.SetDisplay("Jaw Period", "Alligator jaw SMA period", "Alligator")
self._teeth_period = self.Param("TeethPeriod", 8) \
.SetDisplay("Teeth Period", "Alligator teeth SMA period", "Alligator")
self._lips_period = self.Param("LipsPeriod", 5) \
.SetDisplay("Lips Period", "Alligator lips SMA period", "Alligator")
self._fractal_len = self.Param("FractalLen", 5) \
.SetDisplay("Fractal Length", "Number of bars for fractal detection", "Signals")
self._high_buf = []
self._low_buf = []
self._buf_count = 0
self._pending_buy_level = None
self._pending_sell_level = None
self._prev_jaw = 0.0
self._prev_teeth = 0.0
self._prev_lips = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def JawPeriod(self):
return self._jaw_period.Value
@property
def TeethPeriod(self):
return self._teeth_period.Value
@property
def LipsPeriod(self):
return self._lips_period.Value
@property
def FractalLen(self):
return self._fractal_len.Value
def OnStarted2(self, time):
super(ft_bill_willams_trader_strategy, self).OnStarted2(time)
self._jaw = SimpleMovingAverage()
self._jaw.Length = self.JawPeriod
self._teeth = SimpleMovingAverage()
self._teeth.Length = self.TeethPeriod
self._lips = SimpleMovingAverage()
self._lips.Length = self.LipsPeriod
fractal_len = self.FractalLen
self._high_buf = [0.0] * fractal_len
self._low_buf = [0.0] * fractal_len
self._buf_count = 0
self._pending_buy_level = None
self._pending_sell_level = None
self._prev_jaw = 0.0
self._prev_teeth = 0.0
self._prev_lips = 0.0
self._entry_price = 0.0
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._jaw, self._teeth, self._lips, self.ProcessCandle).Start()
def ProcessCandle(self, candle, jaw_val, teeth_val, lips_val):
if candle.State != CandleStates.Finished:
return
jaw_val = float(jaw_val)
teeth_val = float(teeth_val)
lips_val = float(lips_val)
self._update_fractals(candle)
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
if self.Position > 0:
if self._pending_sell_level is not None and low < self._pending_sell_level:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if self._pending_buy_level is not None and high > self._pending_buy_level:
self.BuyMarket()
self._entry_price = 0.0
if self.Position <= 0 and self._pending_buy_level is not None:
if high > self._pending_buy_level and close > teeth_val:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
if self.Position >= 0 and self._pending_sell_level is not None:
if low < self._pending_sell_level and close < teeth_val:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._prev_jaw = jaw_val
self._prev_teeth = teeth_val
self._prev_lips = lips_val
def _update_fractals(self, candle):
flen = self.FractalLen
if flen < 3:
return
self._high_buf.pop(0)
self._high_buf.append(float(candle.HighPrice))
self._low_buf.pop(0)
self._low_buf.append(float(candle.LowPrice))
self._buf_count += 1
if self._buf_count < flen:
return
wing = (flen - 1) // 2
center = flen - 1 - wing
center_high = self._high_buf[center]
is_up = True
for i in range(flen):
if i != center and self._high_buf[i] >= center_high:
is_up = False
break
if is_up:
self._pending_buy_level = center_high
center_low = self._low_buf[center]
is_down = True
for i in range(flen):
if i != center and self._low_buf[i] <= center_low:
is_down = False
break
if is_down:
self._pending_sell_level = center_low
def OnReseted(self):
super(ft_bill_willams_trader_strategy, self).OnReseted()
self._high_buf = []
self._low_buf = []
self._buf_count = 0
self._pending_buy_level = None
self._pending_sell_level = None
self._prev_jaw = 0.0
self._prev_teeth = 0.0
self._prev_lips = 0.0
self._entry_price = 0.0
def CreateClone(self):
return ft_bill_willams_trader_strategy()