Color PEMA Envelopes Digit System
The Color PEMA Envelopes Digit System reproduces the logic of the MetaTrader expert
Exp_Color_PEMA_Envelopes_Digit_System.mq5. The strategy evaluates the color codes
produced by the Color PEMA Envelopes indicator: when a candle closes outside of the
upper or lower band the indicator paints a special color, and once price re-enters the
channel a trade is triggered in the direction of the breakout.
How it works
- The strategy builds an eight-stage Polynomial EMA (PEMA) using fractional lengths, exactly as in the original indicator. The result is rounded to the configured precision and shifted by the optional price offset.
- Upper and lower envelopes are created by applying a percentage deviation around the PEMA value.
- Each finished candle receives a color code depending on its relationship to the shifted envelopes:
4/3: close above the upper band (bullish/bearish body).1/0: close below the lower band (bullish/bearish body).2: price remains inside the envelope.
- The strategy reads the color that occurred on the
SignalBar + 1candle and compares it with the color of theSignalBarcandle. This mimics theCopyBuffercalls from the expert advisor. - When the older color indicates a breakout above the upper band and the more recent color returns inside the channel, a long entry is allowed (if enabled) and any short position is closed. The mirror logic is used for short entries and for closing long positions.
- Protective stop-loss and take-profit orders are managed through StockSharp's risk module.
Parameters
CandleType– timeframe used for analysis and trading.TradeVolume– quantity sent with market orders.EmaLength– fractional length used by every EMA layer in the PEMA chain.AppliedPrices– source price (close, open, median, weighted, trend-follow, DeMark, etc.).DeviationPercent– percentage distance for both envelopes around PEMA.Shift– number of completed candles used to offset the envelope comparison.PriceShift– additional absolute shift applied to both envelopes.Digit– extra precision digits when rounding the PEMA output.SignalBar– how many closed candles back to read the current color from (the older color is taken one bar further).AllowBuyOpen/AllowSellOpen– enable or disable new long/short entries.AllowBuyClose/AllowSellClose– permit closing long/short positions on opposite signals.StopLossPoints– protective stop distance in price points (multiplied byPriceStep).TakeProfitPoints– profit target distance in price points.
Default values
CandleType = TimeSpan.FromHours(4).TimeFrame()TradeVolume = 1mEmaLength = 50.01mAppliedPrices = AppliedPrices.CloseDeviationPercent = 0.1mShift = 1PriceShift = 0mDigit = 2SignalBar = 1AllowBuyOpen = trueAllowSellOpen = trueAllowBuyClose = trueAllowSellClose = trueStopLossPoints = 1000mTakeProfitPoints = 2000m
Filters
- Category: Breakout / Channel re-entry
- Direction: Long & Short
- Indicators: Polynomial EMA envelopes
- Stops: Yes (point-based stop-loss and take-profit)
- Timeframe: Swing (default 4H)
- Risk: Moderate – trades only when price returns from an extreme
- Seasonality: None
- Machine Learning: No
- Divergence: No
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>
/// Strategy based on the Color PEMA Envelopes Digit indicator.
/// A long position is opened when price breaks above the upper envelope and then returns inside it,
/// while a short position is opened on a mirror setup around the lower envelope.
/// Previous color codes from the original indicator are used to detect these transitions.
/// </summary>
public class ColorPemaEnvelopesDigitSystemStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _emaLength;
private readonly StrategyParam<AppliedPrices> _appliedPrice;
private readonly StrategyParam<decimal> _deviationPercent;
private readonly StrategyParam<int> _shift;
private readonly StrategyParam<decimal> _priceShift;
private readonly StrategyParam<int> _digit;
private readonly StrategyParam<int> _signalBar;
private readonly StrategyParam<bool> _allowBuyOpen;
private readonly StrategyParam<bool> _allowSellOpen;
private readonly StrategyParam<bool> _allowBuyClose;
private readonly StrategyParam<bool> _allowSellClose;
private readonly StrategyParam<decimal> _stopLossPoints;
private readonly StrategyParam<decimal> _takeProfitPoints;
private readonly StrategyParam<decimal> _tradeVolume;
private readonly PemaIndicator _pema = new();
private readonly List<decimal> _upperHistory = new();
private readonly List<decimal> _lowerHistory = new();
private readonly List<int> _colorHistory = new();
/// <summary>
/// Initializes a new instance of <see cref="ColorPemaEnvelopesDigitSystemStrategy"/>.
/// </summary>
public ColorPemaEnvelopesDigitSystemStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe used for calculations", "General");
_tradeVolume = Param(nameof(TradeVolume), 1m)
.SetGreaterThanZero()
.SetDisplay("Trade Volume", "Order volume used for entries", "Trading");
_emaLength = Param(nameof(EmaLength), 50.01m)
.SetGreaterThanZero()
.SetDisplay("PEMA Length", "Length of each EMA stage in PEMA", "Indicator");
_appliedPrice = Param(nameof(AppliedPrice), AppliedPrices.Close)
.SetDisplay("Applied Price", "Price source passed to PEMA", "Indicator");
_deviationPercent = Param(nameof(DeviationPercent), 0.1m)
.SetGreaterThanZero()
.SetDisplay("Envelope Deviation", "Percentage width of envelopes", "Indicator");
_shift = Param(nameof(Shift), 1)
.SetRange(0, 10)
.SetDisplay("Shift", "Bars used to offset envelope comparison", "Indicator");
_priceShift = Param(nameof(PriceShift), 0m)
.SetDisplay("Price Shift", "Additional absolute shift applied to envelopes", "Indicator");
_digit = Param(nameof(Digit), 2)
.SetRange(0, 8)
.SetDisplay("Rounding Digits", "Extra precision digits for rounding", "Indicator");
_signalBar = Param(nameof(SignalBar), 1)
.SetRange(1, 10)
.SetDisplay("Signal Bar", "How many completed bars back to check colors", "Logic");
_allowBuyOpen = Param(nameof(AllowBuyOpen), true)
.SetDisplay("Allow Buy Open", "Enable new long entries", "Logic");
_allowSellOpen = Param(nameof(AllowSellOpen), true)
.SetDisplay("Allow Sell Open", "Enable new short entries", "Logic");
_allowBuyClose = Param(nameof(AllowBuyClose), true)
.SetDisplay("Allow Buy Close", "Allow closing long positions on opposite signal", "Logic");
_allowSellClose = Param(nameof(AllowSellClose), true)
.SetDisplay("Allow Sell Close", "Allow closing short positions on opposite signal", "Logic");
_stopLossPoints = Param(nameof(StopLossPoints), 10m)
.SetRange(0m, 100000m)
.SetDisplay("Stop Loss Points", "Distance for protective stop", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 20m)
.SetRange(0m, 100000m)
.SetDisplay("Take Profit Points", "Distance for profit target", "Risk");
}
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Order volume used for entries.
/// </summary>
public decimal TradeVolume
{
get => _tradeVolume.Value;
set => _tradeVolume.Value = value;
}
/// <summary>
/// Length of each EMA layer inside PEMA.
/// </summary>
public decimal EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// Price source passed to PEMA.
/// </summary>
public AppliedPrices AppliedPrice
{
get => _appliedPrice.Value;
set => _appliedPrice.Value = value;
}
/// <summary>
/// Percentage width of the envelopes around PEMA.
/// </summary>
public decimal DeviationPercent
{
get => _deviationPercent.Value;
set => _deviationPercent.Value = value;
}
/// <summary>
/// Bars used to offset envelope comparison.
/// </summary>
public int Shift
{
get => _shift.Value;
set => _shift.Value = value;
}
/// <summary>
/// Additional absolute shift applied to envelopes.
/// </summary>
public decimal PriceShift
{
get => _priceShift.Value;
set => _priceShift.Value = value;
}
/// <summary>
/// Extra precision digits for rounding PEMA.
/// </summary>
public int Digit
{
get => _digit.Value;
set => _digit.Value = value;
}
/// <summary>
/// Completed bars back to inspect for signals.
/// </summary>
public int SignalBar
{
get => _signalBar.Value;
set => _signalBar.Value = value;
}
/// <summary>
/// Enable opening of long positions.
/// </summary>
public bool AllowBuyOpen
{
get => _allowBuyOpen.Value;
set => _allowBuyOpen.Value = value;
}
/// <summary>
/// Enable opening of short positions.
/// </summary>
public bool AllowSellOpen
{
get => _allowSellOpen.Value;
set => _allowSellOpen.Value = value;
}
/// <summary>
/// Allow closing of long positions on opposite signal.
/// </summary>
public bool AllowBuyClose
{
get => _allowBuyClose.Value;
set => _allowBuyClose.Value = value;
}
/// <summary>
/// Allow closing of short positions on opposite signal.
/// </summary>
public bool AllowSellClose
{
get => _allowSellClose.Value;
set => _allowSellClose.Value = value;
}
/// <summary>
/// Distance to the protective stop in price points.
/// </summary>
public decimal StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Distance to the profit target in price points.
/// </summary>
public decimal TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_pema.Reset();
_upperHistory.Clear();
_lowerHistory.Clear();
_colorHistory.Clear();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_pema.Length = EmaLength;
_pema.Digit = Digit;
_pema.PriceStep = Security?.PriceStep ?? 1m;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _pema);
DrawOwnTrades(area);
}
var step = Security?.PriceStep ?? 1m;
StartProtection(
takeProfit: new Unit(TakeProfitPoints * step, UnitTypes.Absolute),
stopLoss: new Unit(StopLossPoints * step, UnitTypes.Absolute));
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
{
return;
}
var price = GetAppliedPrice(candle);
// Calculate PEMA base value for the current candle.
var pemaValue = _pema.Process(new DecimalIndicatorValue(_pema, price, candle.OpenTime));
if (!pemaValue.IsFinal)
{
return;
}
var pema = pemaValue.GetValue<decimal>();
var upperCurrent = (1m + DeviationPercent / 100m) * pema + PriceShift;
var lowerCurrent = (1m - DeviationPercent / 100m) * pema + PriceShift;
var shift = Math.Max(0, Shift);
decimal? upperForColor;
decimal? lowerForColor;
if (shift == 0)
{
upperForColor = upperCurrent;
lowerForColor = lowerCurrent;
}
else
{
upperForColor = _upperHistory.Count >= shift ? _upperHistory[0] : (decimal?)null;
lowerForColor = _lowerHistory.Count >= shift ? _lowerHistory[0] : (decimal?)null;
}
// Determine the color code based on envelope breakouts.
var currentColor = CalculateColor(candle, upperForColor, lowerForColor);
if (!_pema.IsFormed)
{
UpdateHistories(currentColor, upperCurrent, lowerCurrent, shift);
return;
}
var hasRecentColor = TryGetColor(SignalBar, out var recentColor);
var hasOlderColor = TryGetColor(SignalBar + 1, out var olderColor);
var buyOpenSignal = false;
var sellOpenSignal = false;
var buyCloseSignal = false;
var sellCloseSignal = false;
// Evaluate signals using stored color history to reproduce the MQL logic.
if (hasOlderColor)
{
if (olderColor > 2)
{
if (AllowBuyOpen && hasRecentColor && recentColor < 3)
buyOpenSignal = true;
if (AllowSellClose)
sellCloseSignal = true;
}
else if (olderColor < 2)
{
if (AllowSellOpen && hasRecentColor && recentColor > 1)
sellOpenSignal = true;
if (AllowBuyClose)
buyCloseSignal = true;
}
}
// Close positions according to signal permissions.
if (buyCloseSignal && Position > 0)
SellMarket();
if (sellCloseSignal && Position < 0)
BuyMarket();
// Open new trades after handling position closures.
if (buyOpenSignal && Position <= 0)
{
BuyMarket();
}
else if (sellOpenSignal && Position >= 0)
{
SellMarket();
}
UpdateHistories(currentColor, upperCurrent, lowerCurrent, shift);
}
private decimal GetAppliedPrice(ICandleMessage candle)
{
var open = candle.OpenPrice;
var high = candle.HighPrice;
var low = candle.LowPrice;
var close = candle.ClosePrice;
return AppliedPrice switch
{
AppliedPrices.Close => close,
AppliedPrices.Open => open,
AppliedPrices.High => high,
AppliedPrices.Low => low,
AppliedPrices.Median => (high + low) / 2m,
AppliedPrices.Typical => (close + high + low) / 3m,
AppliedPrices.Weighted => (2m * close + high + low) / 4m,
AppliedPrices.Simple => (open + close) / 2m,
AppliedPrices.Quarter => (open + close + high + low) / 4m,
AppliedPrices.TrendFollow0 => close > open ? high : close < open ? low : close,
AppliedPrices.TrendFollow1 => close > open ? (high + close) / 2m : close < open ? (low + close) / 2m : close,
AppliedPrices.Demark => CalculateDemarkPrice(open, high, low, close),
_ => close,
};
}
private static decimal CalculateDemarkPrice(decimal open, decimal high, decimal low, decimal close)
{
var res = high + low + close;
if (close < open)
res = (res + low) / 2m;
else if (close > open)
res = (res + high) / 2m;
else
res = (res + close) / 2m;
return ((res - low) + (res - high)) / 2m;
}
private static int CalculateColor(ICandleMessage candle, decimal? upper, decimal? lower)
{
const int defaultColor = 2;
var color = defaultColor;
if (upper is decimal up)
{
if (candle.ClosePrice > up)
color = candle.OpenPrice <= candle.ClosePrice ? 4 : 3;
}
if (lower is decimal down)
{
if (candle.ClosePrice < down)
color = candle.OpenPrice > candle.ClosePrice ? 0 : 1;
}
return color;
}
private bool TryGetColor(int barsAgo, out int color)
{
if (barsAgo <= 0 || _colorHistory.Count < barsAgo)
{
color = default;
return false;
}
color = _colorHistory[^barsAgo];
return true;
}
private void UpdateHistories(int currentColor, decimal upperCurrent, decimal lowerCurrent, int shift)
{
_colorHistory.Add(currentColor);
var maxColors = Math.Max(3, Math.Max(shift, SignalBar) + 3);
while (_colorHistory.Count > maxColors)
{
try { _colorHistory.RemoveAt(0); } catch { break; }
}
if (shift > 0)
{
_upperHistory.Add(upperCurrent);
while (_upperHistory.Count > shift)
{
try { _upperHistory.RemoveAt(0); } catch { break; }
}
_lowerHistory.Add(lowerCurrent);
while (_lowerHistory.Count > shift)
{
try { _lowerHistory.RemoveAt(0); } catch { break; }
}
}
}
/// <summary>
/// Price source options for PEMA calculation.
/// </summary>
public enum AppliedPrices
{
Close = 1,
Open,
High,
Low,
Median,
Typical,
Weighted,
Simple,
Quarter,
TrendFollow0,
TrendFollow1,
Demark
}
private class PemaIndicator : BaseIndicator
{
public decimal Length { get; set; } = 50.01m;
public int Digit { get; set; } = 2;
public decimal PriceStep { get; set; } = 1m;
private readonly decimal[] _emaValues = new decimal[8];
private bool _hasHistory;
private int _count;
protected override IIndicatorValue OnProcess(IIndicatorValue input)
{
var price = input.GetValue<decimal>();
var length = Length <= 0m ? 1m : Length;
var alpha = 2m / (length + 1m);
var oneMinusAlpha = 1m - alpha;
var current = price;
for (var i = 0; i < _emaValues.Length; i++)
{
var prev = _hasHistory ? _emaValues[i] : current;
var ema = alpha * current + oneMinusAlpha * prev;
_emaValues[i] = ema;
current = ema;
}
_hasHistory = true;
_count++;
var pema = 8m * _emaValues[0]
- 28m * _emaValues[1]
+ 56m * _emaValues[2]
- 70m * _emaValues[3]
+ 56m * _emaValues[4]
- 28m * _emaValues[5]
+ 8m * _emaValues[6]
- _emaValues[7];
var digits = Math.Max(0, Digit);
var step = PriceStep > 0m ? PriceStep : 1m;
var factor = step * (decimal)Math.Pow(10, digits);
if (factor > 0m)
pema = Math.Round(pema / factor, MidpointRounding.AwayFromZero) * factor;
IsFormed = _count > 8;
return new DecimalIndicatorValue(this, pema, input.Time) { IsFinal = true };
}
public override void Reset()
{
base.Reset();
Array.Clear(_emaValues, 0, _emaValues.Length);
_hasHistory = false;
_count = 0;
}
}
}
import clr
import math
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class color_pema_envelopes_digit_system_strategy(Strategy):
"""PEMA Envelopes with color-coded breakout signals and SL/TP protection."""
def __init__(self):
super(color_pema_envelopes_digit_system_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe used for calculations", "General")
self._ema_length = self.Param("EmaLength", 50.01) \
.SetGreaterThanZero() \
.SetDisplay("PEMA Length", "Length of each EMA stage in PEMA", "Indicator")
self._deviation_pct = self.Param("DeviationPercent", 0.1) \
.SetGreaterThanZero() \
.SetDisplay("Envelope Deviation", "Percentage width of envelopes", "Indicator")
self._shift = self.Param("Shift", 1) \
.SetDisplay("Shift", "Bars used to offset envelope comparison", "Indicator")
self._price_shift = self.Param("PriceShift", 0.0) \
.SetDisplay("Price Shift", "Additional absolute shift applied to envelopes", "Indicator")
self._digit = self.Param("Digit", 2) \
.SetDisplay("Rounding Digits", "Extra precision digits for rounding", "Indicator")
self._signal_bar = self.Param("SignalBar", 1) \
.SetDisplay("Signal Bar", "How many completed bars back to check colors", "Logic")
self._allow_buy_open = self.Param("AllowBuyOpen", True) \
.SetDisplay("Allow Buy Open", "Enable new long entries", "Logic")
self._allow_sell_open = self.Param("AllowSellOpen", True) \
.SetDisplay("Allow Sell Open", "Enable new short entries", "Logic")
self._allow_buy_close = self.Param("AllowBuyClose", True) \
.SetDisplay("Allow Buy Close", "Allow closing long positions on opposite signal", "Logic")
self._allow_sell_close = self.Param("AllowSellClose", True) \
.SetDisplay("Allow Sell Close", "Allow closing short positions on opposite signal", "Logic")
self._stop_loss_points = self.Param("StopLossPoints", 10.0) \
.SetDisplay("Stop Loss Points", "Distance for protective stop", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 20.0) \
.SetDisplay("Take Profit Points", "Distance for profit target", "Risk")
# PEMA state
self._ema_values = [0.0] * 8
self._has_history = False
self._pema_count = 0
# History buffers
self._upper_history = []
self._lower_history = []
self._color_history = []
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def DeviationPercent(self):
return self._deviation_pct.Value
@property
def Shift(self):
return self._shift.Value
@property
def PriceShift(self):
return self._price_shift.Value
@property
def Digit(self):
return self._digit.Value
@property
def SignalBar(self):
return self._signal_bar.Value
@property
def AllowBuyOpen(self):
return self._allow_buy_open.Value
@property
def AllowSellOpen(self):
return self._allow_sell_open.Value
@property
def AllowBuyClose(self):
return self._allow_buy_close.Value
@property
def AllowSellClose(self):
return self._allow_sell_close.Value
@property
def StopLossPoints(self):
return self._stop_loss_points.Value
@property
def TakeProfitPoints(self):
return self._take_profit_points.Value
def OnStarted2(self, time):
super(color_pema_envelopes_digit_system_strategy, self).OnStarted2(time)
self._ema_values = [0.0] * 8
self._has_history = False
self._pema_count = 0
self._upper_history = []
self._lower_history = []
self._color_history = []
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
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
sl = float(self.StopLossPoints) * step
tp = float(self.TakeProfitPoints) * step
if sl > 0 or tp > 0:
self.StartProtection(
takeProfit=Unit(tp, UnitTypes.Absolute) if tp > 0 else None,
stopLoss=Unit(sl, UnitTypes.Absolute) if sl > 0 else None
)
def _calc_pema(self, price):
length = float(self.EmaLength)
if length <= 0:
length = 1.0
alpha = 2.0 / (length + 1.0)
one_minus = 1.0 - alpha
current = price
for i in range(8):
prev = self._ema_values[i] if self._has_history else current
ema = alpha * current + one_minus * prev
self._ema_values[i] = ema
current = ema
self._has_history = True
self._pema_count += 1
pema = (8.0 * self._ema_values[0]
- 28.0 * self._ema_values[1]
+ 56.0 * self._ema_values[2]
- 70.0 * self._ema_values[3]
+ 56.0 * self._ema_values[4]
- 28.0 * self._ema_values[5]
+ 8.0 * self._ema_values[6]
- self._ema_values[7])
digits = max(0, int(self.Digit))
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
factor = step * (10.0 ** digits)
if factor > 0:
pema = round(pema / factor) * factor
is_formed = self._pema_count > 8
return pema, is_formed
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
pema, is_formed = self._calc_pema(price)
dev = float(self.DeviationPercent)
ps = float(self.PriceShift)
upper_current = (1.0 + dev / 100.0) * pema + ps
lower_current = (1.0 - dev / 100.0) * pema + ps
shift = max(0, int(self.Shift))
if shift == 0:
upper_for_color = upper_current
lower_for_color = lower_current
else:
upper_for_color = self._upper_history[0] if len(self._upper_history) >= shift else None
lower_for_color = self._lower_history[0] if len(self._lower_history) >= shift else None
current_color = self._calc_color(candle, upper_for_color, lower_for_color)
if not is_formed:
self._update_histories(current_color, upper_current, lower_current, shift)
return
sig_bar = int(self.SignalBar)
has_recent, recent_color = self._try_get_color(sig_bar)
has_older, older_color = self._try_get_color(sig_bar + 1)
buy_open_signal = False
sell_open_signal = False
buy_close_signal = False
sell_close_signal = False
if has_older:
if older_color > 2:
if self.AllowBuyOpen and has_recent and recent_color < 3:
buy_open_signal = True
if self.AllowSellClose:
sell_close_signal = True
elif older_color < 2:
if self.AllowSellOpen and has_recent and recent_color > 1:
sell_open_signal = True
if self.AllowBuyClose:
buy_close_signal = True
if buy_close_signal and self.Position > 0:
self.SellMarket()
if sell_close_signal and self.Position < 0:
self.BuyMarket()
if buy_open_signal and self.Position <= 0:
self.BuyMarket()
elif sell_open_signal and self.Position >= 0:
self.SellMarket()
self._update_histories(current_color, upper_current, lower_current, shift)
def _calc_color(self, candle, upper, lower):
color = 2
close = float(candle.ClosePrice)
o = float(candle.OpenPrice)
if upper is not None:
if close > upper:
color = 4 if o <= close else 3
if lower is not None:
if close < lower:
color = 0 if o > close else 1
return color
def _try_get_color(self, bars_ago):
if bars_ago <= 0 or len(self._color_history) < bars_ago:
return False, 0
return True, self._color_history[-bars_ago]
def _update_histories(self, current_color, upper_current, lower_current, shift):
self._color_history.append(current_color)
max_colors = max(3, max(shift, int(self.SignalBar)) + 3)
while len(self._color_history) > max_colors:
self._color_history.pop(0)
if shift > 0:
self._upper_history.append(upper_current)
while len(self._upper_history) > shift:
self._upper_history.pop(0)
self._lower_history.append(lower_current)
while len(self._lower_history) > shift:
self._lower_history.pop(0)
def OnReseted(self):
super(color_pema_envelopes_digit_system_strategy, self).OnReseted()
self._ema_values = [0.0] * 8
self._has_history = False
self._pema_count = 0
self._upper_history = []
self._lower_history = []
self._color_history = []
def CreateClone(self):
return color_pema_envelopes_digit_system_strategy()