ColorJFatl Digit TM Plus Strategy
Overview
The ColorJFatl Digit TM Plus strategy is a direct port of the MetaTrader 5 expert advisor Exp_ColorJFatl_Digit_Tm_Plus. It trades slope reversals of a Fast Adaptive Trend Line (FATL) that is smoothed with a Jurik Moving Average (JMA). The original indicator publishes three colors (up, flat, down). The strategy reacts when the color on the latest finished bar changes and aligns the position with the new slope.
The StockSharp implementation keeps the high-level behaviour of the MQL
version: orders are generated on closed candles, optional time-based exits are
available, and the lot sizing input is represented by the TradeVolume
parameter.
Signal logic
Indicator calculation
- Prices are fed through the 39-tap FATL digital filter supplied with the original indicator.
- The filtered series is smoothed with a Jurik Moving Average. The length, applied price and rounding precision can be customised through parameters.
- The color state is determined by the sign of the difference between the
current and the previous smoothed values:
2for bullish slope,0for bearish slope and1for neutral/unchanged.
Entry conditions
- Long entry – enabled by
EnableBuyEntries. Triggered when the current bar color becomes2while the previous bar color was less than2. Any existing short position is closed first whenEnableSellExitsis true. - Short entry – enabled by
EnableSellEntries. Triggered when the current bar color becomes0while the previous color was greater than0. Any existing long position is closed first whenEnableBuyExitsis true. - Only one position can be open at a time. Orders are sent at the close of the confirming candle.
- Long entry – enabled by
Exit conditions
- Slope reversal exits – when the slope flips in the opposite direction
the corresponding
EnableBuyExitsorEnableSellExitsflag will close the open position. - Time based exit – if
UseTimeExitis enabled, a position is closed after holding it forHoldingMinutesminutes. - Protective levels –
StopLossPointsandTakeProfitPointsare expressed in price steps. They are evaluated on every finished candle by comparing the session high/low with the entry price.
- Slope reversal exits – when the slope flips in the opposite direction
the corresponding
Parameters
| Parameter | Description |
|---|---|
TradeVolume |
Quantity used for market entries. |
StopLossPoints |
Protective stop distance in price steps. Set to 0 to disable. |
TakeProfitPoints |
Profit target distance in price steps. Set to 0 to disable. |
EnableBuyEntries / EnableSellEntries |
Enable or disable long/short entries. |
EnableBuyExits / EnableSellExits |
Enable or disable slope-based exits. |
UseTimeExit |
Enables the timed exit logic. |
HoldingMinutes |
Holding period in minutes when the timed exit is active. |
CandleType |
Time frame used for calculations (default 4 hours). |
JmaLength |
Jurik Moving Average smoothing length applied to the FATL output. |
AppliedPrices |
Price source for the digital filter (close, open, median, Demark, etc.). |
RoundingDigits |
Number of digits used when rounding the smoothed line. |
SignalBar |
Offset of the finished bar used to evaluate the indicator state. |
Notes
- The strategy processes only fully completed candles and therefore works well with historical backtests.
AppliedPrices.Demarkreproduces the same calculation as the original MQL indicator.- Because StockSharp handles order execution asynchronously, the internal tracking of the entry price is updated whenever a new position is opened and cleared whenever an exit order is submitted.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// ColorJFatl Digit TM Plus strategy converted from MQL.
/// Trades slope changes of a Jurik smoothed FATL digital filter and
/// optionally applies time based and price based exits.
/// </summary>
public class ColorJfatlDigitTmPlusStrategy : Strategy
{
private static readonly decimal[] FatlCoefficients =
[
0.4360409450m, 0.3658689069m, 0.2460452079m, 0.1104506886m,
-0.0054034585m, -0.0760367731m, -0.0933058722m, -0.0670110374m,
-0.0190795053m, 0.0259609206m, 0.0502044896m, 0.0477818607m,
0.0249252327m, -0.0047706151m, -0.0272432537m, -0.0338917071m,
-0.0244141482m, -0.0055774838m, 0.0128149838m, 0.0226522218m,
0.0208778257m, 0.0100299086m, -0.0036771622m, -0.0136744850m,
-0.0160483392m, -0.0108597376m, -0.0016060704m, 0.0069480557m,
0.0110573605m, 0.0095711419m, 0.0040444064m, -0.0023824623m,
-0.0067093714m, -0.0072003400m, -0.0047717710m, 0.0005541115m,
0.0007860160m, 0.0130129076m, 0.0040364019m,
];
private readonly StrategyParam<decimal> _tradeVolume;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private readonly StrategyParam<bool> _enableBuyEntries;
private readonly StrategyParam<bool> _enableSellEntries;
private readonly StrategyParam<bool> _enableBuyExits;
private readonly StrategyParam<bool> _enableSellExits;
private readonly StrategyParam<bool> _useTimeExit;
private readonly StrategyParam<int> _holdingMinutes;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _jmaLength;
private readonly StrategyParam<AppliedPrices> _appliedPrice;
private readonly StrategyParam<int> _digitRounding;
private readonly StrategyParam<int> _signalBar;
private ExponentialMovingAverage _jma;
private readonly List<decimal> _priceBuffer = new();
private readonly List<int> _colorHistory = new();
private decimal? _previousLine;
private DateTimeOffset? _entryTime;
/// <summary>
/// Trading volume used for market orders.
/// </summary>
public decimal TradeVolume
{
get => _tradeVolume.Value;
set => _tradeVolume.Value = value;
}
/// <summary>
/// Stop loss distance in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take profit distance in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Enables long entries when an up-slope appears.
/// </summary>
public bool EnableBuyEntries
{
get => _enableBuyEntries.Value;
set => _enableBuyEntries.Value = value;
}
/// <summary>
/// Enables short entries when a down-slope appears.
/// </summary>
public bool EnableSellEntries
{
get => _enableSellEntries.Value;
set => _enableSellEntries.Value = value;
}
/// <summary>
/// Enables long exit when the filter turns bearish.
/// </summary>
public bool EnableBuyExits
{
get => _enableBuyExits.Value;
set => _enableBuyExits.Value = value;
}
/// <summary>
/// Enables short exit when the filter turns bullish.
/// </summary>
public bool EnableSellExits
{
get => _enableSellExits.Value;
set => _enableSellExits.Value = value;
}
/// <summary>
/// Enables the time based exit.
/// </summary>
public bool UseTimeExit
{
get => _useTimeExit.Value;
set => _useTimeExit.Value = value;
}
/// <summary>
/// Holding period in minutes for the time based exit.
/// </summary>
public int HoldingMinutes
{
get => _holdingMinutes.Value;
set => _holdingMinutes.Value = value;
}
/// <summary>
/// Candle type used for indicator calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Jurik smoothing length applied to the digital filter.
/// </summary>
public int JmaLength
{
get => _jmaLength.Value;
set => _jmaLength.Value = value;
}
/// <summary>
/// Applied price option for the digital filter input.
/// </summary>
public AppliedPrices AppliedPrice
{
get => _appliedPrice.Value;
set => _appliedPrice.Value = value;
}
/// <summary>
/// Precision multiplier used for rounding indicator values.
/// </summary>
public int DigitRounding
{
get => _digitRounding.Value;
set => _digitRounding.Value = value;
}
/// <summary>
/// Number of finished bars to look back for signals.
/// </summary>
public int SignalBar
{
get => _signalBar.Value;
set => _signalBar.Value = value;
}
/// <summary>
/// Applied price options matching the original MQL enumeration.
/// </summary>
public enum AppliedPrices
{
Close = 1,
Open,
High,
Low,
Median,
Typical,
Weighted,
AverageOC,
AverageOHLC,
TrendFollow1,
TrendFollow2,
Demark,
}
/// <summary>
/// Constructor.
/// </summary>
public ColorJfatlDigitTmPlusStrategy()
{
_tradeVolume = Param(nameof(TradeVolume), 1m)
.SetGreaterThanZero()
.SetDisplay("Volume", "Order volume", "Trading");
_stopLossPoints = Param(nameof(StopLossPoints), 0)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop loss distance in price steps (0=disabled)", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 0)
.SetNotNegative()
.SetDisplay("Take Profit", "Take profit distance in price steps (0=disabled)", "Risk");
_enableBuyEntries = Param(nameof(EnableBuyEntries), true)
.SetDisplay("Enable Long Entry", "Allow opening long positions", "Signals");
_enableSellEntries = Param(nameof(EnableSellEntries), true)
.SetDisplay("Enable Short Entry", "Allow opening short positions", "Signals");
_enableBuyExits = Param(nameof(EnableBuyExits), true)
.SetDisplay("Enable Long Exit", "Allow closing long positions", "Signals");
_enableSellExits = Param(nameof(EnableSellExits), true)
.SetDisplay("Enable Short Exit", "Allow closing short positions", "Signals");
_useTimeExit = Param(nameof(UseTimeExit), false)
.SetDisplay("Use Time Exit", "Enable time based exit", "Exits");
_holdingMinutes = Param(nameof(HoldingMinutes), 240)
.SetGreaterThanZero()
.SetDisplay("Holding Minutes", "Exit after holding for N minutes", "Exits");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Source candles", "General");
_jmaLength = Param(nameof(JmaLength), 14)
.SetGreaterThanZero()
.SetDisplay("JMA Length", "Jurik smoothing length", "Indicator")
.SetOptimize(3, 30, 1);
_appliedPrice = Param(nameof(AppliedPrice), AppliedPrices.Close)
.SetDisplay("Applied Price", "Price source for the filter", "Indicator");
_digitRounding = Param(nameof(DigitRounding), 0)
.SetNotNegative()
.SetDisplay("Digit Rounding", "Rounding precision multiplier", "Indicator");
_signalBar = Param(nameof(SignalBar), 1)
.SetGreaterThanZero()
.SetDisplay("Signal Bar", "Number of finished bars used for signals", "Indicator");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_jma = null;
_priceBuffer.Clear();
_colorHistory.Clear();
_previousLine = null;
_entryTime = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
Volume = TradeVolume;
_jma = new ExponentialMovingAverage { Length = JmaLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var priceStep = Security?.PriceStep ?? 0m;
Unit takeProfitUnit = null;
Unit stopLossUnit = null;
if (TakeProfitPoints > 0 && priceStep > 0m)
takeProfitUnit = new Unit(TakeProfitPoints * priceStep, UnitTypes.Absolute);
if (StopLossPoints > 0 && priceStep > 0m)
stopLossUnit = new Unit(StopLossPoints * priceStep, UnitTypes.Absolute);
StartProtection(takeProfit: takeProfitUnit, stopLoss: stopLossUnit);
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var price = GetAppliedPrice(candle);
_priceBuffer.Add(price);
if (_priceBuffer.Count > FatlCoefficients.Length)
_priceBuffer.RemoveAt(0);
if (_priceBuffer.Count < FatlCoefficients.Length)
return;
var fatl = 0m;
for (var i = 0; i < FatlCoefficients.Length; i++)
fatl += FatlCoefficients[i] * _priceBuffer[_priceBuffer.Count - 1 - i];
var jmaValue = _jma.Process(new DecimalIndicatorValue(_jma, fatl, candle.OpenTime) { IsFinal = true });
if (!_jma.IsFormed)
return;
var roundedLine = RoundToStep(jmaValue.ToDecimal(), GetRoundingStep());
var color = 1;
if (_previousLine.HasValue)
{
var diff = roundedLine - _previousLine.Value;
if (diff > 0m)
color = 2;
else if (diff < 0m)
color = 0;
else if (_colorHistory.Count > 0)
color = _colorHistory[0];
}
_previousLine = roundedLine;
_colorHistory.Insert(0, color);
if (_colorHistory.Count > 100)
_colorHistory.RemoveAt(_colorHistory.Count - 1);
if (_colorHistory.Count <= SignalBar)
return;
var currentColor = _colorHistory[SignalBar - 1];
var previousColor = _colorHistory[SignalBar];
// Time-based exit
if (UseTimeExit && Position != 0 && _entryTime is not null && HoldingMinutes > 0)
{
var elapsed = candle.CloseTime - _entryTime.Value;
if (elapsed >= TimeSpan.FromMinutes(HoldingMinutes))
{
if (Position > 0)
SellMarket();
else if (Position < 0)
BuyMarket();
_entryTime = null;
}
}
var buyOpenSignal = EnableBuyEntries && currentColor == 2 && previousColor != 2;
var sellCloseSignal = EnableSellExits && currentColor == 2;
var sellOpenSignal = EnableSellEntries && currentColor == 0 && previousColor != 0;
var buyCloseSignal = EnableBuyExits && currentColor == 0;
if (buyCloseSignal && Position > 0)
{
SellMarket();
_entryTime = null;
}
if (sellCloseSignal && Position < 0)
{
BuyMarket();
_entryTime = null;
}
if (buyOpenSignal && Position == 0)
{
BuyMarket();
_entryTime = candle.CloseTime;
}
if (sellOpenSignal && Position == 0)
{
SellMarket();
_entryTime = candle.CloseTime;
}
}
private decimal GetAppliedPrice(ICandleMessage candle)
=> AppliedPrice switch
{
AppliedPrices.Close => candle.ClosePrice,
AppliedPrices.Open => candle.OpenPrice,
AppliedPrices.High => candle.HighPrice,
AppliedPrices.Low => candle.LowPrice,
AppliedPrices.Median => (candle.HighPrice + candle.LowPrice) / 2m,
AppliedPrices.Typical => (candle.ClosePrice + candle.HighPrice + candle.LowPrice) / 3m,
AppliedPrices.Weighted => (2m * candle.ClosePrice + candle.HighPrice + candle.LowPrice) / 4m,
AppliedPrices.AverageOC => (candle.OpenPrice + candle.ClosePrice) / 2m,
AppliedPrices.AverageOHLC => (candle.OpenPrice + candle.ClosePrice + candle.HighPrice + candle.LowPrice) / 4m,
AppliedPrices.TrendFollow1 => candle.ClosePrice > candle.OpenPrice
? candle.HighPrice
: candle.ClosePrice < candle.OpenPrice
? candle.LowPrice
: candle.ClosePrice,
AppliedPrices.TrendFollow2 => candle.ClosePrice > candle.OpenPrice
? (candle.HighPrice + candle.ClosePrice) / 2m
: candle.ClosePrice < candle.OpenPrice
? (candle.LowPrice + candle.ClosePrice) / 2m
: candle.ClosePrice,
AppliedPrices.Demark => GetDemarkPrice(candle),
_ => candle.ClosePrice,
};
private static decimal GetDemarkPrice(ICandleMessage candle)
{
var res = candle.HighPrice + candle.LowPrice + candle.ClosePrice;
if (candle.ClosePrice < candle.OpenPrice)
res = (res + candle.LowPrice) / 2m;
else if (candle.ClosePrice > candle.OpenPrice)
res = (res + candle.HighPrice) / 2m;
else
res = (res + candle.ClosePrice) / 2m;
return ((res - candle.LowPrice) + (res - candle.HighPrice)) / 2m;
}
private decimal GetRoundingStep()
{
var step = Security?.PriceStep ?? 0m;
if (step <= 0m)
return 0m;
var multiplier = (decimal)Math.Pow(10, DigitRounding);
return step * multiplier;
}
private static decimal RoundToStep(decimal value, decimal step)
{
if (step <= 0m)
return value;
return Math.Round(value / step, MidpointRounding.AwayFromZero) * step;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.BusinessEntities")
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, UnitTypes, Unit
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
# Applied price constants
PRICE_CLOSE = 1
PRICE_OPEN = 2
PRICE_HIGH = 3
PRICE_LOW = 4
PRICE_MEDIAN = 5
PRICE_TYPICAL = 6
PRICE_WEIGHTED = 7
PRICE_AVERAGE_OC = 8
PRICE_AVERAGE_OHLC = 9
PRICE_TREND_FOLLOW1 = 10
PRICE_TREND_FOLLOW2 = 11
PRICE_DEMARK = 12
_FATL_COEFF = [
0.4360409450, 0.3658689069, 0.2460452079, 0.1104506886,
-0.0054034585, -0.0760367731, -0.0933058722, -0.0670110374,
-0.0190795053, 0.0259609206, 0.0502044896, 0.0477818607,
0.0249252327, -0.0047706151, -0.0272432537, -0.0338917071,
-0.0244141482, -0.0055774838, 0.0128149838, 0.0226522218,
0.0208778257, 0.0100299086, -0.0036771622, -0.0136744850,
-0.0160483392, -0.0108597376, -0.0016060704, 0.0069480557,
0.0110573605, 0.0095711419, 0.0040444064, -0.0023824623,
-0.0067093714, -0.0072003400, -0.0047717710, 0.0005541115,
0.0007860160, 0.0130129076, 0.0040364019,
]
_FATL_LEN = len(_FATL_COEFF)
class color_jfatl_digit_tm_plus_strategy(Strategy):
def __init__(self):
super(color_jfatl_digit_tm_plus_strategy, self).__init__()
self._trade_volume = self.Param("TradeVolume", Decimal(1))
self._stop_loss_points = self.Param("StopLossPoints", 0)
self._take_profit_points = self.Param("TakeProfitPoints", 0)
self._enable_buy_entries = self.Param("EnableBuyEntries", True)
self._enable_sell_entries = self.Param("EnableSellEntries", True)
self._enable_buy_exits = self.Param("EnableBuyExits", True)
self._enable_sell_exits = self.Param("EnableSellExits", True)
self._use_time_exit = self.Param("UseTimeExit", False)
self._holding_minutes = self.Param("HoldingMinutes", 240)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._jma_length = self.Param("JmaLength", 14)
self._applied_price = self.Param("AppliedPrice", PRICE_CLOSE)
self._digit_rounding = self.Param("DigitRounding", 0)
self._signal_bar = self.Param("SignalBar", 1)
self._jma = None
self._price_buffer = []
self._color_history = []
self._previous_line = None
self._entry_time = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(color_jfatl_digit_tm_plus_strategy, self).OnStarted2(time)
self.Volume = self._trade_volume.Value
self._jma = ExponentialMovingAverage()
self._jma.Length = self._jma_length.Value
self._price_buffer = []
self._color_history = []
self._previous_line = None
self._entry_time = None
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._process_candle).Start()
sec = self.Security
price_step = sec.PriceStep if sec is not None and sec.PriceStep is not None else Decimal(0)
take_profit_unit = None
stop_loss_unit = None
tp = self._take_profit_points.Value
sl = self._stop_loss_points.Value
if tp > 0 and price_step > Decimal(0):
take_profit_unit = Unit(Decimal(tp) * price_step, UnitTypes.Absolute)
if sl > 0 and price_step > Decimal(0):
stop_loss_unit = Unit(Decimal(sl) * price_step, UnitTypes.Absolute)
self.StartProtection(take_profit_unit, stop_loss_unit)
def _get_applied_price(self, candle):
ap = self._applied_price.Value
o = float(candle.OpenPrice)
h = float(candle.HighPrice)
low = float(candle.LowPrice)
c = float(candle.ClosePrice)
if ap == PRICE_CLOSE:
return c
elif ap == PRICE_OPEN:
return o
elif ap == PRICE_HIGH:
return h
elif ap == PRICE_LOW:
return low
elif ap == PRICE_MEDIAN:
return (h + low) / 2.0
elif ap == PRICE_TYPICAL:
return (c + h + low) / 3.0
elif ap == PRICE_WEIGHTED:
return (2.0 * c + h + low) / 4.0
elif ap == PRICE_AVERAGE_OC:
return (o + c) / 2.0
elif ap == PRICE_AVERAGE_OHLC:
return (o + c + h + low) / 4.0
elif ap == PRICE_TREND_FOLLOW1:
if c > o:
return h
elif c < o:
return low
else:
return c
elif ap == PRICE_TREND_FOLLOW2:
if c > o:
return (h + c) / 2.0
elif c < o:
return (low + c) / 2.0
else:
return c
elif ap == PRICE_DEMARK:
return self._get_demark_price(o, h, low, c)
else:
return c
def _get_demark_price(self, o, h, low, c):
res = h + low + c
if c < o:
res = (res + low) / 2.0
elif c > o:
res = (res + h) / 2.0
else:
res = (res + c) / 2.0
return ((res - low) + (res - h)) / 2.0
def _get_rounding_step(self):
sec = self.Security
step = sec.PriceStep if sec is not None and sec.PriceStep is not None else Decimal(0)
if step <= Decimal(0):
return 0.0
multiplier = Math.Pow(10.0, float(self._digit_rounding.Value))
return float(step) * multiplier
def _round_to_step(self, value, step):
if step <= 0.0:
return value
return round(value / step) * step
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
price = self._get_applied_price(candle)
self._price_buffer.append(price)
if len(self._price_buffer) > _FATL_LEN:
self._price_buffer.pop(0)
if len(self._price_buffer) < _FATL_LEN:
return
fatl = 0.0
for i in range(_FATL_LEN):
fatl += _FATL_COEFF[i] * self._price_buffer[len(self._price_buffer) - 1 - i]
jma_result = process_float(self._jma, Decimal(fatl), candle.OpenTime, True)
if not self._jma.IsFormed:
return
jma_val = float(jma_result.Value)
rounding_step = self._get_rounding_step()
rounded_line = self._round_to_step(jma_val, rounding_step)
color = 1
if self._previous_line is not None:
diff = rounded_line - self._previous_line
if diff > 0:
color = 2
elif diff < 0:
color = 0
elif len(self._color_history) > 0:
color = self._color_history[0]
self._previous_line = rounded_line
self._color_history.insert(0, color)
if len(self._color_history) > 100:
self._color_history.pop()
signal_bar = self._signal_bar.Value
if len(self._color_history) <= signal_bar:
return
current_color = self._color_history[signal_bar - 1]
previous_color = self._color_history[signal_bar]
# Time-based exit
if self._use_time_exit.Value and self.Position != 0 and self._entry_time is not None and self._holding_minutes.Value > 0:
elapsed = candle.CloseTime.Subtract(self._entry_time)
if elapsed >= TimeSpan.FromMinutes(self._holding_minutes.Value):
if self.Position > 0:
self.SellMarket()
elif self.Position < 0:
self.BuyMarket()
self._entry_time = None
buy_open_signal = self._enable_buy_entries.Value and current_color == 2 and previous_color != 2
sell_close_signal = self._enable_sell_exits.Value and current_color == 2
sell_open_signal = self._enable_sell_entries.Value and current_color == 0 and previous_color != 0
buy_close_signal = self._enable_buy_exits.Value and current_color == 0
if buy_close_signal and self.Position > 0:
self.SellMarket()
self._entry_time = None
if sell_close_signal and self.Position < 0:
self.BuyMarket()
self._entry_time = None
if buy_open_signal and self.Position == 0:
self.BuyMarket()
self._entry_time = candle.CloseTime
if sell_open_signal and self.Position == 0:
self.SellMarket()
self._entry_time = candle.CloseTime
def OnReseted(self):
super(color_jfatl_digit_tm_plus_strategy, self).OnReseted()
self._jma = None
self._price_buffer = []
self._color_history = []
self._previous_line = None
self._entry_time = None
def CreateClone(self):
return color_jfatl_digit_tm_plus_strategy()