Color PEMA Envelopes Digit System
Color PEMA Envelopes Digit System 将 MetaTrader 专家
Exp_Color_PEMA_Envelopes_Digit_System.mq5 迁移到 StockSharp。
策略读取 Color PEMA Envelopes 指标产生的颜色代码:当收盘价突破包络线后
指标着色,随后价格回到通道内部时,按照突破方向开仓。
策略流程
- 构建八层的 PEMA(Polynomial EMA),长度可以为小数,与原指标完全一致。
结果按照
Digit参数指定的精度进行四舍五入,并可通过PriceShift做绝对平移。 - 根据
DeviationPercent在 PEMA 周围生成上下包络线。 - 每根完成的 K 线依据其与平移后包络线的关系被赋予颜色代码:
4/3:收盘价高于上轨(多头/空头实体)。1/0:收盘价低于下轨(多头/空头实体)。2:价格位于通道内部。
- 策略读取
SignalBar + 1根之前的颜色并与SignalBar根之前的颜色比较,模拟原 EA 中的CopyBuffer调用。 - 当较早的颜色显示向上突破而后一根重新回到通道内时(并且允许多头开仓), 系统先平掉空头仓位,再开多仓。向下突破时执行对称的空头逻辑。
- 止损和止盈距离通过 StockSharp 的保护模块自动管理。
参数说明
CandleType– 使用的 K 线类型/周期。TradeVolume– 市价单下单数量。EmaLength– PEMA 各层 EMA 的长度(可为小数)。AppliedPrices– 计算用的价格来源(收盘、开盘、中价、加权价、TrendFollow、DeMark 等)。DeviationPercent– 包络线的百分比宽度。Shift– 计算颜色时向后偏移的已完成 K 线数量。PriceShift– 对 PEMA 的附加绝对偏移。Digit– PEMA 结果额外保留的小数位数。SignalBar– 读取当前颜色所回溯的 K 线数量(再往前一根用于“上一颜色”)。AllowBuyOpen/AllowSellOpen– 是否允许新的多头/空头开仓。AllowBuyClose/AllowSellClose– 是否允许在反向信号下平掉多头/空头。StopLossPoints– 止损距离,单位为价格点(乘以PriceStep)。TakeProfitPoints– 止盈距离,单位为价格点。
默认值
CandleType = TimeSpan.FromHours(4).TimeFrame()TradeVolume = 1mEmaLength = 50.01mAppliedPrices = AppliedPrices.CloseDeviationPercent = 0.1mShift = 1PriceShift = 0mDigit = 2SignalBar = 1AllowBuyOpen = trueAllowSellOpen = trueAllowBuyClose = trueAllowSellClose = trueStopLossPoints = 1000mTakeProfitPoints = 2000m
筛选信息
- 类型:突破 / 通道回归
- 方向:双向(多头与空头)
- 指标:多层 PEMA 包络线
- 止损:有(点数止损与止盈)
- 周期:波段(默认 4 小时)
- 风险:中等 —— 仅在价格回到通道内时建仓
- 季节性:无
- 机器学习:无
- 背离:无
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()