Color PEMA Envelopes Sistema Digit
O Color PEMA Envelopes Sistema Digit reproduz a lógica do especialista MetaTrader
Exp_Color_PEMA_Envelopes_Digit_System.mq5. A estratégia avalia os códigos de cor
produzidos pelo indicador Color PEMA Envelopes: quando uma vela fecha fora da
banda superior ou inferior, o indicador pinta uma cor especial, e quando o preço
volta a entrar no canal, uma operação é acionada na direção do rompimento.
Como funciona
- A estratégia constrói uma EMA Polinomial de oito estágios (PEMA) usando comprimentos fracionários, exatamente como no indicador original. O resultado é arredondado para a precisão configurada e deslocado pelo deslocamento de preço opcional.
- Envelopes superior e inferior são criados aplicando um desvio percentual ao redor do valor PEMA.
- Cada vela finalizada recebe um código de cor dependendo de sua relação com os envelopes deslocados:
4/3: fechamento acima da banda superior (corpo de alta/baixa).1/0: fechamento abaixo da banda inferior (corpo de alta/baixa).2: o preço permanece dentro do envelope.
- A estratégia lê a cor que ocorreu na vela
SignalBar + 1e a compara com a cor da velaSignalBar. Isso imita as chamadasCopyBufferdo consultor especialista. - Quando a cor mais antiga indica um rompimento acima da banda superior e a cor mais recente retorna para dentro do canal, uma entrada comprada é permitida (se habilitada) e qualquer posição vendida é fechada. A lógica espelhada é usada para entradas vendidas e para fechar posições compradas.
- Ordens de stop-loss e take-profit protetoras são gerenciadas através do módulo de risco do StockSharp.
Parâmetros
CandleType– período usado para análise e trading.TradeVolume– quantidade enviada com ordens de mercado.EmaLength– comprimento fracionário usado por cada camada EMA na cadeia PEMA.AppliedPrices– preço fonte (fechamento, abertura, mediano, ponderado, seguidor de tendência, DeMark, etc.).DeviationPercent– distância percentual para ambos os envelopes ao redor de PEMA.Shift– número de velas completadas usadas para deslocar a comparação do envelope.PriceShift– deslocamento absoluto adicional aplicado a ambos os envelopes.Digit– dígitos de precisão extras ao arredondar a saída PEMA.SignalBar– quantas velas fechadas atrás ler a cor atual (a cor mais antiga é tomada uma barra mais atrás).AllowBuyOpen/AllowSellOpen– habilitar ou desabilitar novas entradas compradas/vendidas.AllowBuyClose/AllowSellClose– permitir fechar posições compradas/vendidas em sinais opostos.StopLossPoints– distância de stop protetor em pontos de preço (multiplicado porPriceStep).TakeProfitPoints– distância do alvo de lucro em pontos de preço.
Valores padrão
CandleType = TimeSpan.FromHours(4).TimeFrame()TradeVolume = 1mEmaLength = 50.01mAppliedPrices = AppliedPrices.CloseDeviationPercent = 0.1mShift = 1PriceShift = 0mDigit = 2SignalBar = 1AllowBuyOpen = trueAllowSellOpen = trueAllowBuyClose = trueAllowSellClose = trueStopLossPoints = 1000mTakeProfitPoints = 2000m
Filtros
- Categoria: Rompimento / Re-entrada no canal
- Direção: Comprado/Vendido
- Indicadores: Envelopes de EMA Polinomial
- Stops: Sim (stop-loss e take-profit baseados em pontos)
- Período: Swing (padrão 4H)
- Nível de risco: Moderado – opera apenas quando o preço retorna de um extremo
- Sazonalidade: Nenhuma
- Redes neurais: Não
- Divergência: Não
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()