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;
using StockSharp.Algo;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Port of the Exp_BlauCMI MetaTrader strategy using the Blau Candle Momentum Index.
/// </summary>
public class ExpBlauCmiStrategy : Strategy
{
/// <summary>
/// Price sources supported by the strategy.
/// </summary>
public enum AppliedPrices
{
Close = 1,
Open,
High,
Low,
Median,
Typical,
Weighted,
Simple,
Quarter,
TrendFollow0,
TrendFollow1,
Demark
}
/// <summary>
/// Smoothing modes used in the multi-stage averages.
/// </summary>
public enum SmoothingMethods
{
Simple,
Exponential,
Smoothed,
LinearWeighted
}
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<SmoothingMethods> _smoothingMethod;
private readonly StrategyParam<int> _momentumLength;
private readonly StrategyParam<int> _firstSmoothingLength;
private readonly StrategyParam<int> _secondSmoothingLength;
private readonly StrategyParam<int> _thirdSmoothingLength;
private readonly StrategyParam<int> _signalBar;
private readonly StrategyParam<AppliedPrices> _priceForClose;
private readonly StrategyParam<AppliedPrices> _priceForOpen;
private readonly StrategyParam<bool> _allowLongEntry;
private readonly StrategyParam<bool> _allowShortEntry;
private readonly StrategyParam<bool> _allowLongExit;
private readonly StrategyParam<bool> _allowShortExit;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private readonly StrategyParam<decimal> _orderVolume;
private DecimalLengthIndicator _momentumStage1 = null!;
private DecimalLengthIndicator _momentumStage2 = null!;
private DecimalLengthIndicator _momentumStage3 = null!;
private DecimalLengthIndicator _absStage1 = null!;
private DecimalLengthIndicator _absStage2 = null!;
private DecimalLengthIndicator _absStage3 = null!;
private readonly List<decimal> _priceBuffer = new();
private readonly List<decimal> _indicatorHistory = new();
private decimal _priceStep;
private decimal _stopLossDistance;
private decimal _takeProfitDistance;
/// <summary>
/// Initializes a new instance of the <see cref="ExpBlauCmiStrategy"/> class.
/// </summary>
public ExpBlauCmiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe used for BlauCMI calculations", "General");
_smoothingMethod = Param(nameof(MomentumSmoothing), SmoothingMethods.Exponential)
.SetDisplay("Smoothing Method", "Averaging mode for the BlauCMI stages", "Indicator");
_momentumLength = Param(nameof(MomentumLength), 1)
.SetGreaterThanZero()
.SetDisplay("Momentum Depth", "Bars between compared prices", "Indicator");
_firstSmoothingLength = Param(nameof(FirstSmoothingLength), 20)
.SetGreaterThanZero()
.SetDisplay("First Smoothing", "Length of the first BlauCMI smoothing", "Indicator");
_secondSmoothingLength = Param(nameof(SecondSmoothingLength), 5)
.SetGreaterThanZero()
.SetDisplay("Second Smoothing", "Length of the second BlauCMI smoothing", "Indicator");
_thirdSmoothingLength = Param(nameof(ThirdSmoothingLength), 3)
.SetGreaterThanZero()
.SetDisplay("Third Smoothing", "Length of the third BlauCMI smoothing", "Indicator");
_signalBar = Param(nameof(SignalBar), 1)
.SetGreaterThanZero()
.SetDisplay("Signal Shift", "Number of closed bars used for signals", "Trading");
_priceForClose = Param(nameof(PriceForClose), AppliedPrices.Close)
.SetDisplay("Momentum Price", "Price type for the leading leg", "Indicator");
_priceForOpen = Param(nameof(PriceForOpen), AppliedPrices.Open)
.SetDisplay("Reference Price", "Price type compared against the delayed bar", "Indicator");
_allowLongEntry = Param(nameof(AllowLongEntry), true)
.SetDisplay("Allow Long Entry", "Enable opening long trades", "Trading");
_allowShortEntry = Param(nameof(AllowShortEntry), true)
.SetDisplay("Allow Short Entry", "Enable opening short trades", "Trading");
_allowLongExit = Param(nameof(AllowLongExit), true)
.SetDisplay("Allow Long Exit", "Enable closing long trades on opposite signals", "Trading");
_allowShortExit = Param(nameof(AllowShortExit), true)
.SetDisplay("Allow Short Exit", "Enable closing short trades on opposite signals", "Trading");
_stopLossPoints = Param(nameof(StopLossPoints), 1000)
.SetRange(0, 100000)
.SetDisplay("Stop-Loss Points", "Distance to stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 2000)
.SetRange(0, 100000)
.SetDisplay("Take-Profit Points", "Distance to take-profit in price steps", "Risk");
_orderVolume = Param(nameof(OrderVolume), 1m)
.SetGreaterThanZero()
.SetDisplay("Order Volume", "Contract volume used for entries", "Trading");
}
/// <summary>
/// Candle type used for indicator calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Averaging method for momentum smoothing stages.
/// </summary>
public SmoothingMethods MomentumSmoothing
{
get => _smoothingMethod.Value;
set => _smoothingMethod.Value = value;
}
/// <summary>
/// Bars between the compared prices when computing raw momentum.
/// </summary>
public int MomentumLength
{
get => _momentumLength.Value;
set => _momentumLength.Value = value;
}
/// <summary>
/// Length of the first momentum smoothing stage.
/// </summary>
public int FirstSmoothingLength
{
get => _firstSmoothingLength.Value;
set => _firstSmoothingLength.Value = value;
}
/// <summary>
/// Length of the second momentum smoothing stage.
/// </summary>
public int SecondSmoothingLength
{
get => _secondSmoothingLength.Value;
set => _secondSmoothingLength.Value = value;
}
/// <summary>
/// Length of the third momentum smoothing stage.
/// </summary>
public int ThirdSmoothingLength
{
get => _thirdSmoothingLength.Value;
set => _thirdSmoothingLength.Value = value;
}
/// <summary>
/// Index of the closed bar that produces trading signals.
/// </summary>
public int SignalBar
{
get => _signalBar.Value;
set => _signalBar.Value = value;
}
/// <summary>
/// Applied price for the front leg of momentum.
/// </summary>
public AppliedPrices PriceForClose
{
get => _priceForClose.Value;
set => _priceForClose.Value = value;
}
/// <summary>
/// Applied price for the delayed leg of momentum.
/// </summary>
public AppliedPrices PriceForOpen
{
get => _priceForOpen.Value;
set => _priceForOpen.Value = value;
}
/// <summary>
/// Allow opening long positions.
/// </summary>
public bool AllowLongEntry
{
get => _allowLongEntry.Value;
set => _allowLongEntry.Value = value;
}
/// <summary>
/// Allow opening short positions.
/// </summary>
public bool AllowShortEntry
{
get => _allowShortEntry.Value;
set => _allowShortEntry.Value = value;
}
/// <summary>
/// Allow closing long positions when an opposite signal appears.
/// </summary>
public bool AllowLongExit
{
get => _allowLongExit.Value;
set => _allowLongExit.Value = value;
}
/// <summary>
/// Allow closing short positions when an opposite signal appears.
/// </summary>
public bool AllowShortExit
{
get => _allowShortExit.Value;
set => _allowShortExit.Value = value;
}
/// <summary>
/// Stop-loss distance measured in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take-profit distance measured in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Order volume used for market entries.
/// </summary>
public decimal OrderVolume
{
get => _orderVolume.Value;
set => _orderVolume.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_priceBuffer.Clear();
_indicatorHistory.Clear();
_priceStep = 0m;
_stopLossDistance = 0m;
_takeProfitDistance = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_priceStep = Security?.PriceStep ?? 1m;
_stopLossDistance = StopLossPoints > 0 ? StopLossPoints * _priceStep : 0m;
_takeProfitDistance = TakeProfitPoints > 0 ? TakeProfitPoints * _priceStep : 0m;
StartProtection(
TakeProfitPoints > 0 ? new Unit(_takeProfitDistance, UnitTypes.Absolute) : null,
StopLossPoints > 0 ? new Unit(_stopLossDistance, UnitTypes.Absolute) : null);
Volume = Math.Abs(OrderVolume);
_momentumStage1 = CreateMovingAverage(MomentumSmoothing, FirstSmoothingLength);
_absStage1 = CreateMovingAverage(MomentumSmoothing, FirstSmoothingLength);
_momentumStage2 = CreateMovingAverage(MomentumSmoothing, SecondSmoothingLength);
_absStage2 = CreateMovingAverage(MomentumSmoothing, SecondSmoothingLength);
_momentumStage3 = CreateMovingAverage(MomentumSmoothing, ThirdSmoothingLength);
_absStage3 = CreateMovingAverage(MomentumSmoothing, ThirdSmoothingLength);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private DecimalLengthIndicator CreateMovingAverage(SmoothingMethods method, int length)
{
var normalized = Math.Max(1, length);
return method switch
{
SmoothingMethods.Simple => new SMA { Length = normalized },
SmoothingMethods.Smoothed => new SmoothedMovingAverage { Length = normalized },
SmoothingMethods.LinearWeighted => new WeightedMovingAverage { Length = normalized },
_ => new EMA { Length = normalized }
};
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var frontPrice = GetAppliedPrice(candle, PriceForClose);
var referencePrice = GetAppliedPrice(candle, PriceForOpen);
var momentumDepth = Math.Max(1, MomentumLength);
_priceBuffer.Add(referencePrice);
while (_priceBuffer.Count > momentumDepth)
try { _priceBuffer.RemoveAt(0); } catch { break; }
if (_priceBuffer.Count < momentumDepth)
return;
var delayedPrice = _priceBuffer[0];
var momentum = frontPrice - delayedPrice;
var absMomentum = Math.Abs(momentum);
var time = candle.ServerTime;
var stage1 = _momentumStage1.Process(new DecimalIndicatorValue(_momentumStage1, momentum, time) { IsFinal = true }).ToDecimal();
var absStage1 = _absStage1.Process(new DecimalIndicatorValue(_absStage1, absMomentum, time) { IsFinal = true }).ToDecimal();
var stage2 = _momentumStage2.Process(new DecimalIndicatorValue(_momentumStage2, stage1, time) { IsFinal = true }).ToDecimal();
var absStage2 = _absStage2.Process(new DecimalIndicatorValue(_absStage2, absStage1, time) { IsFinal = true }).ToDecimal();
var stage3Value = _momentumStage3.Process(new DecimalIndicatorValue(_momentumStage3, stage2, time) { IsFinal = true });
var absStage3Value = _absStage3.Process(new DecimalIndicatorValue(_absStage3, absStage2, time) { IsFinal = true });
if (!stage3Value.IsFormed || !absStage3Value.IsFormed)
return;
var denominator = absStage3Value.ToDecimal();
if (denominator == 0m)
return;
var cmi = 100m * stage3Value.ToDecimal() / denominator;
_indicatorHistory.Add(cmi);
var required = SignalBar + 3;
if (_indicatorHistory.Count > required)
_indicatorHistory.RemoveRange(0, _indicatorHistory.Count - required);
var index = _indicatorHistory.Count - 1 - SignalBar;
if (index < 2)
return;
var value0 = _indicatorHistory[index];
var value1 = _indicatorHistory[index - 1];
var value2 = _indicatorHistory[index - 2];
var buySignal = value1 < value2 && value0 > value1;
var sellSignal = value1 > value2 && value0 < value1;
if (Position > 0 && AllowLongExit && sellSignal)
{
SellMarket();
}
if (Position < 0 && AllowShortExit && buySignal)
{
BuyMarket();
}
if (Position != 0)
return;
if (buySignal && AllowLongEntry)
{
BuyMarket();
}
else if (sellSignal && AllowShortEntry)
{
SellMarket();
}
}
private static decimal GetAppliedPrice(ICandleMessage candle, AppliedPrices price)
{
return price 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.Simple => (candle.OpenPrice + candle.ClosePrice) / 2m,
AppliedPrices.Quarter => (candle.OpenPrice + candle.ClosePrice + candle.HighPrice + candle.LowPrice) / 4m,
AppliedPrices.TrendFollow0 => candle.ClosePrice > candle.OpenPrice
? candle.HighPrice
: candle.ClosePrice < candle.OpenPrice
? candle.LowPrice
: candle.ClosePrice,
AppliedPrices.TrendFollow1 => 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 baseValue = candle.HighPrice + candle.LowPrice + candle.ClosePrice;
if (candle.ClosePrice < candle.OpenPrice)
baseValue = (baseValue + candle.LowPrice) / 2m;
else if (candle.ClosePrice > candle.OpenPrice)
baseValue = (baseValue + candle.HighPrice) / 2m;
else
baseValue = (baseValue + candle.ClosePrice) / 2m;
return ((baseValue - candle.LowPrice) + (baseValue - candle.HighPrice)) / 2m;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Algo.Indicators import (
ExponentialMovingAverage,
SimpleMovingAverage,
SmoothedMovingAverage,
WeightedMovingAverage,
)
from indicator_extensions import *
class exp_blau_cmi_strategy(Strategy):
"""Blau Candle Momentum Index: triple-smoothed momentum ratio with configurable price sources."""
def __init__(self):
super(exp_blau_cmi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe used for BlauCMI calculations", "General")
# 0=EMA, 1=SMA, 2=Smoothed, 3=LWMA
self._smoothing_method = self.Param("MomentumSmoothing", 0) \
.SetDisplay("Smoothing Method", "Averaging mode for BlauCMI stages", "Indicator")
self._momentum_length = self.Param("MomentumLength", 1) \
.SetGreaterThanZero() \
.SetDisplay("Momentum Depth", "Bars between compared prices", "Indicator")
self._first_smoothing_length = self.Param("FirstSmoothingLength", 20) \
.SetGreaterThanZero() \
.SetDisplay("First Smoothing", "Length of first BlauCMI smoothing", "Indicator")
self._second_smoothing_length = self.Param("SecondSmoothingLength", 5) \
.SetGreaterThanZero() \
.SetDisplay("Second Smoothing", "Length of second BlauCMI smoothing", "Indicator")
self._third_smoothing_length = self.Param("ThirdSmoothingLength", 3) \
.SetGreaterThanZero() \
.SetDisplay("Third Smoothing", "Length of third BlauCMI smoothing", "Indicator")
self._signal_bar = self.Param("SignalBar", 1) \
.SetGreaterThanZero() \
.SetDisplay("Signal Shift", "Number of closed bars used for signals", "Trading")
# Price types: 1=Close, 2=Open, 3=High, 4=Low, 5=Median, 6=Typical, 7=Weighted
self._price_for_close = self.Param("PriceForClose", 1) \
.SetDisplay("Momentum Price", "Price type for the leading leg", "Indicator")
self._price_for_open = self.Param("PriceForOpen", 2) \
.SetDisplay("Reference Price", "Price type compared against the delayed bar", "Indicator")
self._allow_long_entry = self.Param("AllowLongEntry", True) \
.SetDisplay("Allow Long Entry", "Enable opening long trades", "Trading")
self._allow_short_entry = self.Param("AllowShortEntry", True) \
.SetDisplay("Allow Short Entry", "Enable opening short trades", "Trading")
self._allow_long_exit = self.Param("AllowLongExit", True) \
.SetDisplay("Allow Long Exit", "Enable closing long on opposite signals", "Trading")
self._allow_short_exit = self.Param("AllowShortExit", True) \
.SetDisplay("Allow Short Exit", "Enable closing short on opposite signals", "Trading")
self._stop_loss_points = self.Param("StopLossPoints", 1000) \
.SetDisplay("Stop-Loss Points", "Distance to stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 2000) \
.SetDisplay("Take-Profit Points", "Distance to take-profit in price steps", "Risk")
self._order_volume = self.Param("OrderVolume", 1.0) \
.SetGreaterThanZero() \
.SetDisplay("Order Volume", "Contract volume used for entries", "Trading")
self._price_buffer = []
self._indicator_history = []
self._price_step = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def SmoothingMethod(self):
return int(self._smoothing_method.Value)
@property
def MomentumLength(self):
return int(self._momentum_length.Value)
@property
def FirstSmoothingLength(self):
return int(self._first_smoothing_length.Value)
@property
def SecondSmoothingLength(self):
return int(self._second_smoothing_length.Value)
@property
def ThirdSmoothingLength(self):
return int(self._third_smoothing_length.Value)
@property
def SignalBar(self):
return int(self._signal_bar.Value)
@property
def PriceForClose(self):
return int(self._price_for_close.Value)
@property
def PriceForOpen(self):
return int(self._price_for_open.Value)
@property
def AllowLongEntry(self):
return self._allow_long_entry.Value
@property
def AllowShortEntry(self):
return self._allow_short_entry.Value
@property
def AllowLongExit(self):
return self._allow_long_exit.Value
@property
def AllowShortExit(self):
return self._allow_short_exit.Value
@property
def StopLossPoints(self):
return int(self._stop_loss_points.Value)
@property
def TakeProfitPoints(self):
return int(self._take_profit_points.Value)
@property
def OrderVolume(self):
return float(self._order_volume.Value)
def _create_ma(self, method, length):
n = max(1, length)
if method == 1:
ma = SimpleMovingAverage()
elif method == 2:
ma = SmoothedMovingAverage()
elif method == 3:
ma = WeightedMovingAverage()
else:
ma = ExponentialMovingAverage()
ma.Length = n
return ma
def _get_applied_price(self, candle, price_type):
c = float(candle.ClosePrice)
o = float(candle.OpenPrice)
h = float(candle.HighPrice)
lo = float(candle.LowPrice)
if price_type == 1:
return c
elif price_type == 2:
return o
elif price_type == 3:
return h
elif price_type == 4:
return lo
elif price_type == 5:
return (h + lo) / 2.0
elif price_type == 6:
return (c + h + lo) / 3.0
elif price_type == 7:
return (2.0 * c + h + lo) / 4.0
return c
def OnStarted2(self, time):
super(exp_blau_cmi_strategy, self).OnStarted2(time)
self._price_buffer = []
self._indicator_history = []
sec = self.Security
self._price_step = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None and float(sec.PriceStep) > 0 else 1.0
sl_dist = self.StopLossPoints * self._price_step if self.StopLossPoints > 0 else 0.0
tp_dist = self.TakeProfitPoints * self._price_step if self.TakeProfitPoints > 0 else 0.0
tp = Unit(tp_dist, UnitTypes.Absolute) if tp_dist > 0 else None
sl = Unit(sl_dist, UnitTypes.Absolute) if sl_dist > 0 else None
if tp is not None and sl is not None:
self.StartProtection(takeProfit=tp, stopLoss=sl)
elif tp is not None:
self.StartProtection(takeProfit=tp)
elif sl is not None:
self.StartProtection(stopLoss=sl)
self._m_stage1 = self._create_ma(self.SmoothingMethod, self.FirstSmoothingLength)
self._a_stage1 = self._create_ma(self.SmoothingMethod, self.FirstSmoothingLength)
self._m_stage2 = self._create_ma(self.SmoothingMethod, self.SecondSmoothingLength)
self._a_stage2 = self._create_ma(self.SmoothingMethod, self.SecondSmoothingLength)
self._m_stage3 = self._create_ma(self.SmoothingMethod, self.ThirdSmoothingLength)
self._a_stage3 = self._create_ma(self.SmoothingMethod, self.ThirdSmoothingLength)
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)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
front_price = self._get_applied_price(candle, self.PriceForClose)
ref_price = self._get_applied_price(candle, self.PriceForOpen)
momentum_depth = max(1, self.MomentumLength)
self._price_buffer.append(ref_price)
while len(self._price_buffer) > momentum_depth:
self._price_buffer.pop(0)
if len(self._price_buffer) < momentum_depth:
return
delayed_price = self._price_buffer[0]
momentum = front_price - delayed_price
abs_momentum = abs(momentum)
t = candle.ServerTime
def _proc(ind, val):
return float(process_float(ind, Decimal(val), t, True).Value)
s1 = _proc(self._m_stage1, momentum)
a1 = _proc(self._a_stage1, abs_momentum)
s2 = _proc(self._m_stage2, s1)
a2 = _proc(self._a_stage2, a1)
s3_val = process_float(self._m_stage3, Decimal(s2), t, True)
a3_val = process_float(self._a_stage3, Decimal(a2), t, True)
if not s3_val.IsFormed or not a3_val.IsFormed:
return
denominator = float(a3_val.Value)
if denominator == 0:
return
cmi = 100.0 * float(s3_val.Value) / denominator
self._indicator_history.append(cmi)
required = self.SignalBar + 3
if len(self._indicator_history) > required:
self._indicator_history = self._indicator_history[-required:]
index = len(self._indicator_history) - 1 - self.SignalBar
if index < 2:
return
v0 = self._indicator_history[index]
v1 = self._indicator_history[index - 1]
v2 = self._indicator_history[index - 2]
buy_signal = v1 < v2 and v0 > v1
sell_signal = v1 > v2 and v0 < v1
if self.Position > 0 and self.AllowLongExit and sell_signal:
self.SellMarket()
if self.Position < 0 and self.AllowShortExit and buy_signal:
self.BuyMarket()
if self.Position != 0:
return
if buy_signal and self.AllowLongEntry:
self.BuyMarket()
elif sell_signal and self.AllowShortEntry:
self.SellMarket()
def OnReseted(self):
super(exp_blau_cmi_strategy, self).OnReseted()
self._price_buffer = []
self._indicator_history = []
self._price_step = 0.0
def CreateClone(self):
return exp_blau_cmi_strategy()