Alligator Trend Strategy
The strategy reproduces the classic Bill Williams Alligator system from the original MetaTrader script (Alligator.mq5). It uses three smoothed moving averages built on the median price and shifted forward to visualize the market phase. A long position is opened when the fast Lips line is above the Teeth, and the Teeth are above the Jaw. A short position is opened when the alignment is reversed. Only one position can be active at the same time.
Once in a trade the strategy protects the position with a stop-loss and take-profit expressed in pips. When the market moves in favour of the trade by a configurable zero-level distance, the stop is moved to break-even. A trailing stop follows the highest high (for longs) or lowest low (for shorts) with a minimum step to avoid frequent stop updates. Positions are closed when either the stop-loss, the trailing stop, or the take-profit levels are reached.
The default configuration targets 30-minute candles and Forex-style pip values, but the parameters can be optimized for other markets. Because the original MQL version uses broker-specific pip handling, the conversion relies on the instrument PriceStep to translate pip distances into absolute prices.
Trading Rules
Entry
- Long: No open position and
Lips > Teeth > Jawon the last completed candle. - Short: No open position and
Lips < Teeth < Jawon the last completed candle.
Exit and Risk Management
- Initial Stop: Placed
StopLossPipsbelow (long) or above (short) the fill price. - Take Profit: Placed
TakeProfitPipsaway from the fill price. - Zero Level: When the price advances by
ZeroLevelPips, the stop is moved to the entry price. - Trailing Stop: After the zero-level activation, the stop trails the extreme by
TrailingStopPips, updating only when the improvement exceedsTrailingStepPips. - Positions are flattened immediately when any stop or the take-profit level is touched on candle data.
Parameters
| Parameter | Default | Description |
|---|---|---|
CandleType |
30-minute time frame | Candle series used for indicator calculations and signal evaluation. |
JawLength |
13 | Smoothed moving average period for the blue jaw line. |
TeethLength |
8 | Smoothed moving average period for the red teeth line. |
LipsLength |
5 | Smoothed moving average period for the green lips line. |
JawShift |
8 | Forward displacement of the jaw line, expressed in bars. |
TeethShift |
5 | Forward displacement of the teeth line, expressed in bars. |
LipsShift |
3 | Forward displacement of the lips line, expressed in bars. |
EnableLong |
true |
Allows or blocks long entries. |
EnableShort |
true |
Allows or blocks short entries. |
StopLossPips |
45 | Stop-loss distance in pips from the fill price. |
TakeProfitPips |
145 | Take-profit distance in pips from the fill price. |
ZeroLevelPips |
30 | Distance in pips required to move the stop to break-even. |
TrailingStopPips |
50 | Distance between the current extreme and the trailing stop. |
TrailingStepPips |
10 | Minimum pip improvement required before updating the trailing stop. |
Notes
- The Alligator indicator is calculated on the median price
(High + Low) / 2to match the MetaTrader implementation. - Shifted line values are emulated with internal buffers so that comparisons use the same displaced data as the original script.
- The strategy assumes that one trade is filled before a new signal is processed on the same bar, mirroring the bar-by-bar execution of the source EA.
- Optimize pip distances to match the tick size and volatility of the traded instrument.
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;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Classic Bill Williams Alligator strategy with stop management rules.
/// </summary>
/// <remarks>
/// The strategy opens a long position when the Lips, Teeth, and Jaw lines are aligned upward
/// and opens a short position when they are aligned downward. Once in a trade the algorithm
/// applies the zero level rule to move the stop to break-even, updates a trailing stop with a
/// configurable step, and closes the position at the stop or take-profit levels.
/// </remarks>
public class AlligatorTrendStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _jawLength;
private readonly StrategyParam<int> _teethLength;
private readonly StrategyParam<int> _lipsLength;
private readonly StrategyParam<int> _jawShift;
private readonly StrategyParam<int> _teethShift;
private readonly StrategyParam<int> _lipsShift;
private readonly StrategyParam<bool> _enableLong;
private readonly StrategyParam<bool> _enableShort;
private readonly StrategyParam<decimal> _stopLossPips;
private readonly StrategyParam<decimal> _takeProfitPips;
private readonly StrategyParam<decimal> _zeroLevelPips;
private readonly StrategyParam<decimal> _trailingStopPips;
private readonly StrategyParam<decimal> _trailingStepPips;
private readonly List<decimal> _jawBuffer = new();
private readonly List<decimal> _teethBuffer = new();
private readonly List<decimal> _lipsBuffer = new();
private decimal _entryPrice;
private decimal? _longStop;
private decimal? _longTake;
private bool _longBreakevenActivated;
private decimal _longBestPrice;
private decimal? _shortStop;
private decimal? _shortTake;
private bool _shortBreakevenActivated;
private decimal _shortBestPrice;
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Jaw length.
/// </summary>
public int JawLength
{
get => _jawLength.Value;
set => _jawLength.Value = value;
}
/// <summary>
/// Teeth length.
/// </summary>
public int TeethLength
{
get => _teethLength.Value;
set => _teethLength.Value = value;
}
/// <summary>
/// Lips length.
/// </summary>
public int LipsLength
{
get => _lipsLength.Value;
set => _lipsLength.Value = value;
}
/// <summary>
/// Forward shift applied to the jaw line.
/// </summary>
public int JawShift
{
get => _jawShift.Value;
set => _jawShift.Value = value;
}
/// <summary>
/// Forward shift applied to the teeth line.
/// </summary>
public int TeethShift
{
get => _teethShift.Value;
set => _teethShift.Value = value;
}
/// <summary>
/// Forward shift applied to the lips line.
/// </summary>
public int LipsShift
{
get => _lipsShift.Value;
set => _lipsShift.Value = value;
}
/// <summary>
/// Enable long trades.
/// </summary>
public bool EnableLong
{
get => _enableLong.Value;
set => _enableLong.Value = value;
}
/// <summary>
/// Enable short trades.
/// </summary>
public bool EnableShort
{
get => _enableShort.Value;
set => _enableShort.Value = value;
}
/// <summary>
/// Stop-loss distance expressed in pips.
/// </summary>
public decimal StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Take-profit distance expressed in pips.
/// </summary>
public decimal TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Distance to move the stop to break-even.
/// </summary>
public decimal ZeroLevelPips
{
get => _zeroLevelPips.Value;
set => _zeroLevelPips.Value = value;
}
/// <summary>
/// Distance between price extreme and trailing stop.
/// </summary>
public decimal TrailingStopPips
{
get => _trailingStopPips.Value;
set => _trailingStopPips.Value = value;
}
/// <summary>
/// Minimum increment for trailing stop updates.
/// </summary>
public decimal TrailingStepPips
{
get => _trailingStepPips.Value;
set => _trailingStepPips.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="AlligatorTrendStrategy"/> class.
/// </summary>
public AlligatorTrendStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles used for calculations", "General");
_jawLength = Param(nameof(JawLength), 13)
.SetGreaterThanZero()
.SetDisplay("Jaw Length", "Smoothed moving average period for the jaw", "Alligator")
;
_teethLength = Param(nameof(TeethLength), 8)
.SetGreaterThanZero()
.SetDisplay("Teeth Length", "Smoothed moving average period for the teeth", "Alligator")
;
_lipsLength = Param(nameof(LipsLength), 5)
.SetGreaterThanZero()
.SetDisplay("Lips Length", "Smoothed moving average period for the lips", "Alligator")
;
_jawShift = Param(nameof(JawShift), 8)
.SetDisplay("Jaw Shift", "Forward shift applied to the jaw line", "Alligator")
;
_teethShift = Param(nameof(TeethShift), 5)
.SetDisplay("Teeth Shift", "Forward shift applied to the teeth line", "Alligator")
;
_lipsShift = Param(nameof(LipsShift), 3)
.SetDisplay("Lips Shift", "Forward shift applied to the lips line", "Alligator")
;
_enableLong = Param(nameof(EnableLong), true)
.SetDisplay("Enable Long", "Allow long entries", "Trading");
_enableShort = Param(nameof(EnableShort), true)
.SetDisplay("Enable Short", "Allow short entries", "Trading");
_stopLossPips = Param(nameof(StopLossPips), 500m)
.SetDisplay("Stop Loss", "Stop-loss distance in pips", "Risk")
;
_takeProfitPips = Param(nameof(TakeProfitPips), 2000m)
.SetDisplay("Take Profit", "Take-profit distance in pips", "Risk")
;
_zeroLevelPips = Param(nameof(ZeroLevelPips), 300m)
.SetDisplay("Zero Level", "Distance to move stop to break-even", "Risk")
;
_trailingStopPips = Param(nameof(TrailingStopPips), 500m)
.SetDisplay("Trailing Stop", "Trailing stop distance in pips", "Risk")
;
_trailingStepPips = Param(nameof(TrailingStepPips), 100m)
.SetDisplay("Trailing Step", "Minimum trailing stop increment in pips", "Risk")
;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_jawBuffer.Clear();
_teethBuffer.Clear();
_lipsBuffer.Clear();
_entryPrice = 0m;
ResetLong();
ResetShort();
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var jaw = new SmoothedMovingAverage { Length = JawLength };
var teeth = new SmoothedMovingAverage { Length = TeethLength };
var lips = new SmoothedMovingAverage { Length = LipsLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle);
subscription.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, jaw);
DrawIndicator(area, teeth);
DrawIndicator(area, lips);
DrawOwnTrades(area);
}
void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var medianPrice = (candle.HighPrice + candle.LowPrice) / 2m;
var inputValue = new DecimalIndicatorValue(jaw, medianPrice, candle.CloseTime) { IsFinal = true };
var jawValue = jaw.Process(inputValue);
var teethValue = teeth.Process(new DecimalIndicatorValue(teeth, medianPrice, candle.CloseTime) { IsFinal = true });
var lipsValue = lips.Process(new DecimalIndicatorValue(lips, medianPrice, candle.CloseTime) { IsFinal = true });
if (!jawValue.IsFormed || !teethValue.IsFormed || !lipsValue.IsFormed)
return;
var jawShifted = GetShiftedValue(_jawBuffer, jawValue.GetValue<decimal>(), JawShift);
var teethShifted = GetShiftedValue(_teethBuffer, teethValue.GetValue<decimal>(), TeethShift);
var lipsShifted = GetShiftedValue(_lipsBuffer, lipsValue.GetValue<decimal>(), LipsShift);
if (!jawShifted.HasValue || !teethShifted.HasValue || !lipsShifted.HasValue)
return;
if (!jaw.IsFormed)
return;
if (ManagePosition(candle))
return;
var bullishAlignment = lipsShifted.Value > teethShifted.Value && teethShifted.Value > jawShifted.Value;
var bearishAlignment = lipsShifted.Value < teethShifted.Value && teethShifted.Value < jawShifted.Value;
if (Position == 0)
{
if (bullishAlignment && EnableLong)
{
BuyMarket();
}
else if (bearishAlignment && EnableShort)
{
SellMarket();
}
}
}
}
/// <inheritdoc />
protected override void OnOwnTradeReceived(MyTrade trade)
{
base.OnOwnTradeReceived(trade);
var tradeMsg = trade.Trade;
if (tradeMsg is null)
return;
var price = tradeMsg.Price;
var direction = trade.Order.Side;
var distanceToStop = StopLossPips > 0m ? GetPriceByPips(StopLossPips) : (decimal?)null;
var distanceToTake = TakeProfitPips > 0m ? GetPriceByPips(TakeProfitPips) : (decimal?)null;
if (direction == Sides.Buy)
{
if (Position > 0)
{
_entryPrice = price;
_longStop = distanceToStop.HasValue ? price - distanceToStop.Value : null;
_longTake = distanceToTake.HasValue ? price + distanceToTake.Value : null;
_longBreakevenActivated = false;
_longBestPrice = price;
}
else if (Position == 0)
{
ResetShort();
}
}
else if (direction == Sides.Sell)
{
if (Position < 0)
{
_entryPrice = price;
_shortStop = distanceToStop.HasValue ? price + distanceToStop.Value : null;
_shortTake = distanceToTake.HasValue ? price - distanceToTake.Value : null;
_shortBreakevenActivated = false;
_shortBestPrice = price;
}
else if (Position == 0)
{
ResetLong();
}
}
if (Position == 0)
{
ResetLong();
ResetShort();
}
}
private bool ManagePosition(ICandleMessage candle)
{
if (Position > 0)
{
var entryPrice = _entryPrice;
if (entryPrice == 0m)
return false;
_longBestPrice = Math.Max(_longBestPrice, candle.HighPrice);
if (_longTake.HasValue && candle.HighPrice >= _longTake.Value)
{
SellMarket();
ResetLong();
return true;
}
if (_longStop.HasValue && candle.LowPrice <= _longStop.Value)
{
SellMarket();
ResetLong();
return true;
}
if (ZeroLevelPips > 0m && !_longBreakevenActivated && _longStop.HasValue && entryPrice > _longStop.Value)
{
var zeroDistance = GetPriceByPips(ZeroLevelPips);
if (_longBestPrice - entryPrice >= zeroDistance)
{
_longStop = entryPrice;
_longBreakevenActivated = true;
}
}
if (TrailingStopPips > 0m)
{
var trailingDistance = GetPriceByPips(TrailingStopPips);
var step = GetPriceByPips(TrailingStepPips);
var candidate = _longBestPrice - trailingDistance;
if (!_longStop.HasValue || candidate - _longStop.Value >= step)
_longStop = candidate;
}
}
else if (Position < 0)
{
var entryPrice = _entryPrice;
if (entryPrice == 0m)
return false;
_shortBestPrice = _shortBestPrice == 0m ? candle.LowPrice : Math.Min(_shortBestPrice, candle.LowPrice);
if (_shortTake.HasValue && candle.LowPrice <= _shortTake.Value)
{
BuyMarket();
ResetShort();
return true;
}
if (_shortStop.HasValue && candle.HighPrice >= _shortStop.Value)
{
BuyMarket();
ResetShort();
return true;
}
if (ZeroLevelPips > 0m && !_shortBreakevenActivated && _shortStop.HasValue && entryPrice < _shortStop.Value)
{
var zeroDistance = GetPriceByPips(ZeroLevelPips);
if (entryPrice - candle.LowPrice >= zeroDistance)
{
_shortStop = entryPrice;
_shortBreakevenActivated = true;
}
}
if (TrailingStopPips > 0m)
{
var trailingDistance = GetPriceByPips(TrailingStopPips);
var step = GetPriceByPips(TrailingStepPips);
var candidate = _shortBestPrice + trailingDistance;
if (!_shortStop.HasValue || _shortStop.Value - candidate >= step)
_shortStop = candidate;
}
}
else
{
ResetLong();
ResetShort();
}
return false;
}
private static decimal? GetShiftedValue(List<decimal> buffer, decimal value, int shift)
{
if (shift <= 0)
return value;
buffer.Add(value);
if (buffer.Count <= shift)
return null;
var result = buffer[0];
try { buffer.RemoveAt(0); } catch { }
return result;
}
private decimal GetPriceByPips(decimal pips)
{
if (pips <= 0m)
return 0m;
var step = Security?.PriceStep ?? 0m;
if (step <= 0m)
step = 1m;
return pips * step;
}
private void ResetLong()
{
_longStop = null;
_longTake = null;
_longBreakevenActivated = false;
_longBestPrice = 0m;
}
private void ResetShort()
{
_shortStop = null;
_shortTake = null;
_shortBreakevenActivated = false;
_shortBestPrice = 0m;
}
}
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, Sides
from StockSharp.Algo.Indicators import SmoothedMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class alligator_trend_strategy(Strategy):
"""
Classic Bill Williams Alligator strategy with stop management rules.
Opens long when Lips > Teeth > Jaw, short when reversed.
Applies break-even, trailing stop, and take-profit logic.
"""
def __init__(self):
super(alligator_trend_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles used for calculations", "General")
self._jaw_length = self.Param("JawLength", 13) \
.SetGreaterThanZero() \
.SetDisplay("Jaw Length", "Smoothed moving average period for the jaw", "Alligator")
self._teeth_length = self.Param("TeethLength", 8) \
.SetGreaterThanZero() \
.SetDisplay("Teeth Length", "Smoothed moving average period for the teeth", "Alligator")
self._lips_length = self.Param("LipsLength", 5) \
.SetGreaterThanZero() \
.SetDisplay("Lips Length", "Smoothed moving average period for the lips", "Alligator")
self._jaw_shift = self.Param("JawShift", 8) \
.SetDisplay("Jaw Shift", "Forward shift applied to the jaw line", "Alligator")
self._teeth_shift = self.Param("TeethShift", 5) \
.SetDisplay("Teeth Shift", "Forward shift applied to the teeth line", "Alligator")
self._lips_shift = self.Param("LipsShift", 3) \
.SetDisplay("Lips Shift", "Forward shift applied to the lips line", "Alligator")
self._enable_long = self.Param("EnableLong", True) \
.SetDisplay("Enable Long", "Allow long entries", "Trading")
self._enable_short = self.Param("EnableShort", True) \
.SetDisplay("Enable Short", "Allow short entries", "Trading")
self._stop_loss_pips = self.Param("StopLossPips", 500.0) \
.SetDisplay("Stop Loss", "Stop-loss distance in pips", "Risk")
self._take_profit_pips = self.Param("TakeProfitPips", 2000.0) \
.SetDisplay("Take Profit", "Take-profit distance in pips", "Risk")
self._zero_level_pips = self.Param("ZeroLevelPips", 300.0) \
.SetDisplay("Zero Level", "Distance to move stop to break-even", "Risk")
self._trailing_stop_pips = self.Param("TrailingStopPips", 500.0) \
.SetDisplay("Trailing Stop", "Trailing stop distance in pips", "Risk")
self._trailing_step_pips = self.Param("TrailingStepPips", 100.0) \
.SetDisplay("Trailing Step", "Minimum trailing stop increment in pips", "Risk")
self._jaw_buffer = []
self._teeth_buffer = []
self._lips_buffer = []
self._entry_price = 0.0
self._long_stop = None
self._long_take = None
self._long_breakeven = False
self._long_best = 0.0
self._short_stop = None
self._short_take = None
self._short_breakeven = False
self._short_best = 0.0
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
@property
def JawLength(self): return self._jaw_length.Value
@JawLength.setter
def JawLength(self, v): self._jaw_length.Value = v
@property
def TeethLength(self): return self._teeth_length.Value
@TeethLength.setter
def TeethLength(self, v): self._teeth_length.Value = v
@property
def LipsLength(self): return self._lips_length.Value
@LipsLength.setter
def LipsLength(self, v): self._lips_length.Value = v
@property
def JawShift(self): return self._jaw_shift.Value
@JawShift.setter
def JawShift(self, v): self._jaw_shift.Value = v
@property
def TeethShift(self): return self._teeth_shift.Value
@TeethShift.setter
def TeethShift(self, v): self._teeth_shift.Value = v
@property
def LipsShift(self): return self._lips_shift.Value
@LipsShift.setter
def LipsShift(self, v): self._lips_shift.Value = v
@property
def EnableLong(self): return self._enable_long.Value
@EnableLong.setter
def EnableLong(self, v): self._enable_long.Value = v
@property
def EnableShort(self): return self._enable_short.Value
@EnableShort.setter
def EnableShort(self, v): self._enable_short.Value = v
@property
def StopLossPips(self): return self._stop_loss_pips.Value
@StopLossPips.setter
def StopLossPips(self, v): self._stop_loss_pips.Value = v
@property
def TakeProfitPips(self): return self._take_profit_pips.Value
@TakeProfitPips.setter
def TakeProfitPips(self, v): self._take_profit_pips.Value = v
@property
def ZeroLevelPips(self): return self._zero_level_pips.Value
@ZeroLevelPips.setter
def ZeroLevelPips(self, v): self._zero_level_pips.Value = v
@property
def TrailingStopPips(self): return self._trailing_stop_pips.Value
@TrailingStopPips.setter
def TrailingStopPips(self, v): self._trailing_stop_pips.Value = v
@property
def TrailingStepPips(self): return self._trailing_step_pips.Value
@TrailingStepPips.setter
def TrailingStepPips(self, v): self._trailing_step_pips.Value = v
def OnReseted(self):
super(alligator_trend_strategy, self).OnReseted()
self._jaw_buffer = []
self._teeth_buffer = []
self._lips_buffer = []
self._entry_price = 0.0
self._reset_long()
self._reset_short()
def OnStarted2(self, time):
super(alligator_trend_strategy, self).OnStarted2(time)
jaw = SmoothedMovingAverage()
jaw.Length = self.JawLength
teeth = SmoothedMovingAverage()
teeth.Length = self.TeethLength
lips = SmoothedMovingAverage()
lips.Length = self.LipsLength
self._jaw_ind = jaw
self._teeth_ind = teeth
self._lips_ind = lips
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, jaw)
self.DrawIndicator(area, teeth)
self.DrawIndicator(area, lips)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
median = (float(candle.HighPrice) + float(candle.LowPrice)) / 2.0
jaw_res = process_float(self._jaw_ind, Decimal(median), candle.CloseTime, True)
teeth_res = process_float(self._teeth_ind, Decimal(median), candle.CloseTime, True)
lips_res = process_float(self._lips_ind, Decimal(median), candle.CloseTime, True)
if not jaw_res.IsFormed or not teeth_res.IsFormed or not lips_res.IsFormed:
return
jaw_val = float(jaw_res.Value)
teeth_val = float(teeth_res.Value)
lips_val = float(lips_res.Value)
jaw_shifted = self._get_shifted(self._jaw_buffer, jaw_val, self.JawShift)
teeth_shifted = self._get_shifted(self._teeth_buffer, teeth_val, self.TeethShift)
lips_shifted = self._get_shifted(self._lips_buffer, lips_val, self.LipsShift)
if jaw_shifted is None or teeth_shifted is None or lips_shifted is None:
return
if not self._jaw_ind.IsFormed:
return
if self._manage_position(candle):
return
bullish = lips_shifted > teeth_shifted and teeth_shifted > jaw_shifted
bearish = lips_shifted < teeth_shifted and teeth_shifted < jaw_shifted
if self.Position == 0:
if bullish and self.EnableLong:
self.BuyMarket()
price = float(candle.ClosePrice)
self._entry_price = price
dist_stop = self._get_price_by_pips(self.StopLossPips) if float(self.StopLossPips) > 0 else None
dist_take = self._get_price_by_pips(self.TakeProfitPips) if float(self.TakeProfitPips) > 0 else None
self._long_stop = price - dist_stop if dist_stop else None
self._long_take = price + dist_take if dist_take else None
self._long_breakeven = False
self._long_best = price
elif bearish and self.EnableShort:
self.SellMarket()
price = float(candle.ClosePrice)
self._entry_price = price
dist_stop = self._get_price_by_pips(self.StopLossPips) if float(self.StopLossPips) > 0 else None
dist_take = self._get_price_by_pips(self.TakeProfitPips) if float(self.TakeProfitPips) > 0 else None
self._short_stop = price + dist_stop if dist_stop else None
self._short_take = price - dist_take if dist_take else None
self._short_breakeven = False
self._short_best = price
def _manage_position(self, candle):
if self.Position > 0:
if self._entry_price == 0:
return False
self._long_best = max(self._long_best, float(candle.HighPrice))
if self._long_take is not None and float(candle.HighPrice) >= self._long_take:
self.SellMarket()
self._reset_long()
return True
if self._long_stop is not None and float(candle.LowPrice) <= self._long_stop:
self.SellMarket()
self._reset_long()
return True
if self.ZeroLevelPips > 0 and not self._long_breakeven and self._long_stop is not None and self._entry_price > self._long_stop:
zero_dist = self._get_price_by_pips(self.ZeroLevelPips)
if self._long_best - self._entry_price >= zero_dist:
self._long_stop = self._entry_price
self._long_breakeven = True
if self.TrailingStopPips > 0:
trail_dist = self._get_price_by_pips(self.TrailingStopPips)
step = self._get_price_by_pips(self.TrailingStepPips)
candidate = self._long_best - trail_dist
if self._long_stop is None or candidate - self._long_stop >= step:
self._long_stop = candidate
elif self.Position < 0:
if self._entry_price == 0:
return False
self._short_best = min(self._short_best, float(candle.LowPrice)) if self._short_best > 0 else float(candle.LowPrice)
if self._short_take is not None and float(candle.LowPrice) <= self._short_take:
self.BuyMarket()
self._reset_short()
return True
if self._short_stop is not None and float(candle.HighPrice) >= self._short_stop:
self.BuyMarket()
self._reset_short()
return True
if self.ZeroLevelPips > 0 and not self._short_breakeven and self._short_stop is not None and self._entry_price < self._short_stop:
zero_dist = self._get_price_by_pips(self.ZeroLevelPips)
if self._entry_price - float(candle.LowPrice) >= zero_dist:
self._short_stop = self._entry_price
self._short_breakeven = True
if self.TrailingStopPips > 0:
trail_dist = self._get_price_by_pips(self.TrailingStopPips)
step = self._get_price_by_pips(self.TrailingStepPips)
candidate = self._short_best + trail_dist
if self._short_stop is None or self._short_stop - candidate >= step:
self._short_stop = candidate
else:
self._reset_long()
self._reset_short()
return False
def _get_shifted(self, buffer, value, shift):
if shift <= 0:
return value
buffer.append(value)
if len(buffer) <= shift:
return None
result = buffer[0]
buffer.pop(0)
return result
def _get_price_by_pips(self, pips):
if pips <= 0:
return 0.0
sec = self.Security
step = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None and float(sec.PriceStep) > 0 else 1.0
return float(pips) * step
def _reset_long(self):
self._long_stop = None
self._long_take = None
self._long_breakeven = False
self._long_best = 0.0
def _reset_short(self):
self._short_stop = None
self._short_take = None
self._short_breakeven = False
self._short_best = 0.0
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return alligator_trend_strategy()