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 that extrapolates future prices using the Burg autoregressive model and opens trades when forecasted swings exceed thresholds.
/// Converted from the MetaTrader Burg Extrapolator expert.
/// </summary>
public class BurgExtrapolatorStrategy : Strategy
{
private readonly StrategyParam<decimal> _riskPercent;
private readonly StrategyParam<int> _maxPositions;
private readonly StrategyParam<decimal> _minProfitPips;
private readonly StrategyParam<decimal> _maxLossPips;
private readonly StrategyParam<decimal> _takeProfitPips;
private readonly StrategyParam<decimal> _stopLossPips;
private readonly StrategyParam<decimal> _trailingStopPips;
private readonly StrategyParam<int> _pastBars;
private readonly StrategyParam<decimal> _modelOrderFraction;
private readonly StrategyParam<bool> _useMomentum;
private readonly StrategyParam<bool> _useRateOfChange;
private readonly StrategyParam<decimal> _orderVolume;
private readonly StrategyParam<DataType> _candleType;
private decimal[] _openHistory = Array.Empty<decimal>();
private decimal[] _inputSeries = Array.Empty<decimal>();
private double[] _inputBuffer = Array.Empty<double>();
private double[] _coefficients = Array.Empty<double>();
private double[] _predictions = Array.Empty<double>();
private double[] _forwardErrors = Array.Empty<double>();
private double[] _backwardErrors = Array.Empty<double>();
private decimal[] _priceForecast = Array.Empty<decimal>();
private int _historyCapacity;
private int _openCount;
private int _modelOrder;
private int _forecastSteps;
private int _effectivePastBars;
private decimal _pipSize;
/// <summary>
/// Risk percent of equity per trade.
/// </summary>
public decimal RiskPercent
{
get => _riskPercent.Value;
set => _riskPercent.Value = value;
}
/// <summary>
/// Maximum simultaneous positions in the same direction.
/// </summary>
public int MaxPositions
{
get => _maxPositions.Value;
set => _maxPositions.Value = value;
}
/// <summary>
/// Minimum predicted profit in pips required to open a position.
/// </summary>
public decimal MinProfitPips
{
get => _minProfitPips.Value;
set => _minProfitPips.Value = value;
}
/// <summary>
/// Maximum tolerated loss in pips that triggers position close.
/// </summary>
public decimal MaxLossPips
{
get => _maxLossPips.Value;
set => _maxLossPips.Value = value;
}
/// <summary>
/// Take profit distance in pips.
/// </summary>
public decimal TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Stop loss distance in pips.
/// </summary>
public decimal StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Trailing stop distance in pips.
/// </summary>
public decimal TrailingStopPips
{
get => _trailingStopPips.Value;
set => _trailingStopPips.Value = value;
}
/// <summary>
/// Number of past bars used for the Burg model input.
/// </summary>
public int PastBars
{
get => _pastBars.Value;
set => _pastBars.Value = value;
}
/// <summary>
/// Fraction of past bars that determines the autoregressive order.
/// </summary>
public decimal ModelOrderFraction
{
get => _modelOrderFraction.Value;
set => _modelOrderFraction.Value = value;
}
/// <summary>
/// Enables logarithmic momentum input instead of raw prices.
/// </summary>
public bool UseMomentum
{
get => _useMomentum.Value;
set => _useMomentum.Value = value;
}
/// <summary>
/// Enables rate of change input when momentum is disabled.
/// </summary>
public bool UseRateOfChange
{
get => _useRateOfChange.Value;
set => _useRateOfChange.Value = value;
}
/// <summary>
/// Base order volume when risk calculation is not available.
/// </summary>
public decimal OrderVolume
{
get => _orderVolume.Value;
set => _orderVolume.Value = value;
}
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes <see cref="BurgExtrapolatorStrategy"/>.
/// </summary>
public BurgExtrapolatorStrategy()
{
_riskPercent = Param(nameof(RiskPercent), 5m)
.SetDisplay("Risk %", "Risk percent per trade", "Money")
.SetNotNegative();
_maxPositions = Param(nameof(MaxPositions), 1)
.SetDisplay("Max Positions", "Maximum simultaneous trades", "Risk")
.SetGreaterThanZero();
_minProfitPips = Param(nameof(MinProfitPips), 2m)
.SetDisplay("Min Profit", "Minimum predicted profit (pips)", "Signals")
.SetNotNegative();
_maxLossPips = Param(nameof(MaxLossPips), 5m)
.SetDisplay("Max Loss", "Maximum tolerated loss (pips)", "Risk")
.SetNotNegative();
_takeProfitPips = Param(nameof(TakeProfitPips), 0m)
.SetDisplay("Take Profit", "Take profit distance (pips)", "Risk")
.SetNotNegative();
_stopLossPips = Param(nameof(StopLossPips), 5m)
.SetDisplay("Stop Loss", "Stop loss distance (pips)", "Risk")
.SetNotNegative();
_trailingStopPips = Param(nameof(TrailingStopPips), 10m)
.SetDisplay("Trailing Stop", "Trailing stop distance (pips)", "Risk")
.SetNotNegative();
_pastBars = Param(nameof(PastBars), 50)
.SetDisplay("Past Bars", "Bars used for Burg model", "Model")
.SetGreaterThanZero();
_modelOrderFraction = Param(nameof(ModelOrderFraction), 0.37m)
.SetDisplay("Model Order", "Fraction of bars used for AR order", "Model")
.SetRange(0.1m, 0.9m);
_useMomentum = Param(nameof(UseMomentum), true)
.SetDisplay("Use Momentum", "Use logarithmic momentum input", "Model");
_useRateOfChange = Param(nameof(UseRateOfChange), false)
.SetDisplay("Use ROC", "Use rate of change input when momentum is off", "Model");
_orderVolume = Param(nameof(OrderVolume), 1m)
.SetDisplay("Order Volume", "Fallback order volume", "Money")
.SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetBuffers();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_pipSize = Security?.PriceStep ?? 1m;
var decimals = Security?.Decimals ?? 0;
if (decimals is 3 or 5)
_pipSize *= 10m;
EnsureCapacity();
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
StartProtection(
takeProfit: TakeProfitPips > 0m ? new Unit(TakeProfitPips * _pipSize, UnitTypes.Absolute) : null,
stopLoss: StopLossPips > 0m ? new Unit(StopLossPips * _pipSize, UnitTypes.Absolute) : null,
isStopTrailing: TrailingStopPips > 0m);
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
EnsureCapacity();
PushOpen(candle.OpenPrice);
if (_openCount < _historyCapacity)
return;
var currentOpen = _openHistory[_openCount - 1];
if (!TryBuildInputSeries(out var average))
return;
// no bound indicators; skip only until enough bars collected
if (!TryCalculateSignals(average, currentOpen, out var openSignal, out var closeSignal))
return;
var hasPosition = Position != 0m;
if (hasPosition)
{
if (Position > 0m && (closeSignal == -1 || openSignal == -1))
{
SellMarket();
return;
}
if (Position < 0m && (closeSignal == 1 || openSignal == 1))
{
BuyMarket();
return;
}
}
if (openSignal == 0)
return;
var volume = CalculateOrderVolume();
if (volume <= 0m)
return;
var maxExposure = MaxPositions * volume;
if (openSignal > 0)
{
if (Position < maxExposure)
{
var remaining = maxExposure - Math.Max(Position, 0m);
var tradeVolume = Math.Min(volume, remaining);
if (tradeVolume > 0m)
BuyMarket();
}
}
else if (openSignal < 0)
{
var shortExposure = Math.Abs(Math.Min(Position, 0m));
if (shortExposure < maxExposure)
{
var remaining = maxExposure - shortExposure;
var tradeVolume = Math.Min(volume, remaining);
if (tradeVolume > 0m)
SellMarket();
}
}
}
private void ResetBuffers()
{
_openHistory = Array.Empty<decimal>();
_inputSeries = Array.Empty<decimal>();
_inputBuffer = Array.Empty<double>();
_coefficients = Array.Empty<double>();
_predictions = Array.Empty<double>();
_forwardErrors = Array.Empty<double>();
_backwardErrors = Array.Empty<double>();
_priceForecast = Array.Empty<decimal>();
_pipSize = 0m;
_historyCapacity = 0;
_openCount = 0;
_modelOrder = 1;
_forecastSteps = 1;
_effectivePastBars = 0;
}
private void EnsureCapacity()
{
var bars = Math.Max(PastBars, 3);
var momentumEnabled = UseMomentum;
var rocEnabled = !momentumEnabled && UseRateOfChange;
var requiredHistory = momentumEnabled || rocEnabled ? bars + 1 : bars;
if (_effectivePastBars != bars)
{
_effectivePastBars = bars;
_inputSeries = new decimal[bars];
_inputBuffer = new double[bars];
_forwardErrors = new double[bars];
_backwardErrors = new double[bars];
_openHistory = new decimal[requiredHistory];
_historyCapacity = requiredHistory;
_openCount = 0;
}
else if (_historyCapacity != requiredHistory)
{
_openHistory = new decimal[requiredHistory];
_historyCapacity = requiredHistory;
_openCount = 0;
}
var order = (int)Math.Floor((double)(ModelOrderFraction * bars));
if (order < 1)
order = 1;
if (order >= bars)
order = bars - 1;
if (order < 1)
order = 1;
var nf = bars - order - 1;
if (nf < 1)
nf = 1;
if (_coefficients.Length != order + 1)
_coefficients = new double[order + 1];
if (_predictions.Length != nf + 1)
_predictions = new double[nf + 1];
if (_priceForecast.Length != nf + 1)
_priceForecast = new decimal[nf + 1];
_modelOrder = order;
_forecastSteps = nf;
}
private void PushOpen(decimal open)
{
if (_historyCapacity == 0)
return;
if (_openCount < _historyCapacity)
{
_openHistory[_openCount++] = open;
}
else
{
Array.Copy(_openHistory, 1, _openHistory, 0, _historyCapacity - 1);
_openHistory[_historyCapacity - 1] = open;
}
}
private bool TryBuildInputSeries(out decimal average)
{
average = 0m;
var bars = _effectivePastBars;
if (bars == 0 || _openCount < _historyCapacity)
return false;
var momentumEnabled = UseMomentum;
var rocEnabled = !momentumEnabled && UseRateOfChange;
if (momentumEnabled)
{
for (var i = 0; i < bars; i++)
{
var prev = _openHistory[i];
var next = _openHistory[i + 1];
if (prev <= 0m || next <= 0m)
{
_inputSeries[i] = 0m;
}
else
{
var ratio = next / prev;
_inputSeries[i] = (decimal)Math.Log((double)ratio);
}
}
}
else if (rocEnabled)
{
for (var i = 0; i < bars; i++)
{
var prev = _openHistory[i];
var next = _openHistory[i + 1];
if (prev == 0m)
{
_inputSeries[i] = 0m;
}
else
{
_inputSeries[i] = next / prev - 1m;
}
}
}
else
{
for (var i = 0; i < bars; i++)
average += _openHistory[i];
average /= bars;
for (var i = 0; i < bars; i++)
_inputSeries[i] = _openHistory[i] - average;
}
for (var i = 0; i < bars; i++)
_inputBuffer[i] = (double)_inputSeries[i];
return true;
}
private bool TryCalculateSignals(decimal average, decimal currentOpen, out int openSignal, out int closeSignal)
{
openSignal = 0;
closeSignal = 0;
var bars = _effectivePastBars;
if (bars == 0 || _modelOrder < 1 || _forecastSteps < 1)
return false;
Array.Clear(_coefficients, 0, _coefficients.Length);
Array.Clear(_predictions, 0, _predictions.Length);
Array.Copy(_inputBuffer, _forwardErrors, bars);
Array.Copy(_inputBuffer, _backwardErrors, bars);
ComputeBurgCoefficients(bars);
ForecastSeries(bars);
var momentumEnabled = UseMomentum;
var rocEnabled = !momentumEnabled && UseRateOfChange;
if (momentumEnabled)
{
_priceForecast[0] = currentOpen;
for (var i = 1; i <= _forecastSteps; i++)
{
var prev = _priceForecast[i - 1];
var next = prev * (decimal)Math.Exp(_predictions[i]);
_priceForecast[i] = next;
}
}
else if (rocEnabled)
{
_priceForecast[0] = currentOpen;
for (var i = 1; i <= _forecastSteps; i++)
{
var prev = _priceForecast[i - 1];
_priceForecast[i] = prev * (1m + (decimal)_predictions[i]);
}
}
else
{
for (var i = 0; i <= _forecastSteps; i++)
_priceForecast[i] = (decimal)_predictions[i] + average;
}
var minProfit = MinProfitPips * _pipSize;
var maxLoss = MaxLossPips * _pipSize;
var ymax = _priceForecast[0];
var ymin = _priceForecast[0];
var imax = 0;
var imin = 0;
for (var i = 1; i < _forecastSteps; i++)
{
var value = _priceForecast[i];
if (value > ymax && openSignal == 0)
{
ymax = value;
imax = i;
if (imin == 0 && ymax - ymin >= maxLoss)
closeSignal = 1;
if (imin == 0 && ymax - ymin >= minProfit)
openSignal = 1;
}
if (value < ymin && openSignal == 0)
{
ymin = value;
imin = i;
if (imax == 0 && ymax - ymin >= maxLoss)
closeSignal = -1;
if (imax == 0 && ymax - ymin >= minProfit)
openSignal = -1;
}
}
return true;
}
private void ComputeBurgCoefficients(int bars)
{
var den = 0.0;
for (var i = 0; i < bars; i++)
{
den += _inputBuffer[i] * _inputBuffer[i];
}
den *= 2.0;
var reflection = 0.0;
for (var k = 1; k <= _modelOrder; k++)
{
double num = 0.0;
for (var i = k; i < bars; i++)
{
num += _forwardErrors[i] * _backwardErrors[i - 1];
}
var left = _forwardErrors[k - 1];
var right = _backwardErrors[bars - 1];
var denom = (1.0 - reflection * reflection) * den - left * left - right * right;
reflection = Math.Abs(denom) > double.Epsilon ? -2.0 * num / denom : 0.0;
_coefficients[k] = reflection;
var half = k / 2;
for (var i = 1; i <= half; i++)
{
var ki = k - i;
var temp = _coefficients[i];
_coefficients[i] += reflection * _coefficients[ki];
if (i != ki)
{
_coefficients[ki] += reflection * temp;
}
}
if (k < _modelOrder)
{
for (var i = bars - 1; i >= k; i--)
{
var temp = _forwardErrors[i];
_forwardErrors[i] += reflection * _backwardErrors[i - 1];
_backwardErrors[i] = _backwardErrors[i - 1] + reflection * temp;
}
}
}
}
private void ForecastSeries(int bars)
{
for (var n = bars - 1; n < bars + _forecastSteps; n++)
{
double sum = 0.0;
for (var i = 1; i <= _modelOrder; i++)
{
var index = n - i;
if (index < bars)
{
sum -= _coefficients[i] * _inputBuffer[index];
}
else
{
var pfIndex = index - bars + 1;
if (pfIndex >= 0 && pfIndex < _predictions.Length)
{
sum -= _coefficients[i] * _predictions[pfIndex];
}
}
}
var targetIndex = n - bars + 1;
if (targetIndex >= 0 && targetIndex < _predictions.Length)
{
_predictions[targetIndex] = sum;
}
}
}
private decimal CalculateOrderVolume()
{
if (StopLossPips <= 0m || RiskPercent <= 0m)
{
return OrderVolume;
}
var equity = Portfolio?.CurrentValue ?? 0m;
if (equity <= 0m)
{
return OrderVolume;
}
var riskAmount = equity * RiskPercent / 100m;
var stopDistance = StopLossPips * _pipSize;
if (stopDistance <= 0m)
{
return OrderVolume;
}
var volume = riskAmount / stopDistance;
return volume > 0m ? volume : OrderVolume;
}
}
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, Math, Array
from StockSharp.Messages import DataType, CandleStates, UnitTypes, Unit
from StockSharp.Algo.Strategies import Strategy
class burg_extrapolator_strategy(Strategy):
"""
Strategy that extrapolates future prices using the Burg autoregressive model
and opens trades when forecasted swings exceed thresholds.
"""
def __init__(self):
super(burg_extrapolator_strategy, self).__init__()
self._risk_percent = self.Param("RiskPercent", 5.0) \
.SetDisplay("Risk %", "Risk percent per trade", "Money")
self._max_positions = self.Param("MaxPositions", 1) \
.SetDisplay("Max Positions", "Maximum simultaneous trades", "Risk")
self._min_profit_pips = self.Param("MinProfitPips", 2.0) \
.SetDisplay("Min Profit", "Minimum predicted profit (pips)", "Signals")
self._max_loss_pips = self.Param("MaxLossPips", 5.0) \
.SetDisplay("Max Loss", "Maximum tolerated loss (pips)", "Risk")
self._take_profit_pips = self.Param("TakeProfitPips", 0.0) \
.SetDisplay("Take Profit", "Take profit distance (pips)", "Risk")
self._stop_loss_pips = self.Param("StopLossPips", 5.0) \
.SetDisplay("Stop Loss", "Stop loss distance (pips)", "Risk")
self._trailing_stop_pips = self.Param("TrailingStopPips", 10.0) \
.SetDisplay("Trailing Stop", "Trailing stop distance (pips)", "Risk")
self._past_bars = self.Param("PastBars", 50) \
.SetDisplay("Past Bars", "Bars used for Burg model", "Model")
self._model_order_fraction = self.Param("ModelOrderFraction", 0.37) \
.SetDisplay("Model Order", "Fraction of bars used for AR order", "Model")
self._use_momentum = self.Param("UseMomentum", True) \
.SetDisplay("Use Momentum", "Use logarithmic momentum input", "Model")
self._use_rate_of_change = self.Param("UseRateOfChange", False) \
.SetDisplay("Use ROC", "Use rate of change input when momentum is off", "Model")
self._order_volume = self.Param("OrderVolume", 1.0) \
.SetDisplay("Order Volume", "Fallback order volume", "Money")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._open_history = []
self._pip_size = 0.0
self._effective_past_bars = 0
self._model_order = 1
self._forecast_steps = 1
self._history_capacity = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(burg_extrapolator_strategy, self).OnReseted()
self._open_history = []
self._pip_size = 0.0
self._effective_past_bars = 0
self._model_order = 1
self._forecast_steps = 1
self._history_capacity = 0
def OnStarted2(self, time):
super(burg_extrapolator_strategy, self).OnStarted2(time)
self._pip_size = self.Security.PriceStep if self.Security.PriceStep is not None else 1.0
decimals = self.Security.Decimals if self.Security.Decimals is not None else 0
if decimals in (3, 5):
self._pip_size *= 10.0
self._ensure_capacity()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.on_process).Start()
tp = None
sl = None
tp_pips = self._take_profit_pips.Value
sl_pips = self._stop_loss_pips.Value
trailing_pips = self._trailing_stop_pips.Value
if tp_pips > 0:
tp = Unit(tp_pips * self._pip_size, UnitTypes.Absolute)
if sl_pips > 0:
sl = Unit(sl_pips * self._pip_size, UnitTypes.Absolute)
self.StartProtection(tp, sl, trailing_pips > 0)
def _ensure_capacity(self):
bars = max(self._past_bars.Value, 3)
momentum_enabled = self._use_momentum.Value
roc_enabled = not momentum_enabled and self._use_rate_of_change.Value
required = bars + 1 if (momentum_enabled or roc_enabled) else bars
if self._effective_past_bars != bars:
self._effective_past_bars = bars
self._open_history = []
self._history_capacity = required
order = int(math.floor(self._model_order_fraction.Value * bars))
if order < 1:
order = 1
if order >= bars:
order = bars - 1
if order < 1:
order = 1
nf = bars - order - 1
if nf < 1:
nf = 1
self._model_order = order
self._forecast_steps = nf
def on_process(self, candle):
if candle.State != CandleStates.Finished:
return
self._ensure_capacity()
self._open_history.append(float(candle.OpenPrice))
if len(self._open_history) > self._history_capacity:
self._open_history = self._open_history[-self._history_capacity:]
if len(self._open_history) < self._history_capacity:
return
bars = self._effective_past_bars
momentum_enabled = self._use_momentum.Value
roc_enabled = not momentum_enabled and self._use_rate_of_change.Value
# Build input series
input_buffer = [0.0] * bars
average = 0.0
if momentum_enabled:
for i in range(bars):
prev_val = self._open_history[i]
next_val = self._open_history[i + 1]
if prev_val <= 0 or next_val <= 0:
input_buffer[i] = 0.0
else:
input_buffer[i] = math.log(next_val / prev_val)
elif roc_enabled:
for i in range(bars):
prev_val = self._open_history[i]
next_val = self._open_history[i + 1]
if prev_val == 0:
input_buffer[i] = 0.0
else:
input_buffer[i] = next_val / prev_val - 1.0
else:
for i in range(bars):
average += self._open_history[i]
average /= bars
for i in range(bars):
input_buffer[i] = self._open_history[i] - average
# Burg coefficients
order = self._model_order
nf = self._forecast_steps
coefficients = [0.0] * (order + 1)
forward_errors = list(input_buffer)
backward_errors = list(input_buffer)
den = sum(v * v for v in input_buffer) * 2.0
reflection = 0.0
for k in range(1, order + 1):
num = sum(forward_errors[i] * backward_errors[i - 1] for i in range(k, bars))
left = forward_errors[k - 1]
right = backward_errors[bars - 1]
denom = (1.0 - reflection * reflection) * den - left * left - right * right
reflection = -2.0 * num / denom if abs(denom) > 1e-15 else 0.0
coefficients[k] = reflection
half = k // 2
for i in range(1, half + 1):
ki = k - i
temp = coefficients[i]
coefficients[i] += reflection * coefficients[ki]
if i != ki:
coefficients[ki] += reflection * temp
if k < order:
for i in range(bars - 1, k - 1, -1):
temp = forward_errors[i]
forward_errors[i] += reflection * backward_errors[i - 1]
backward_errors[i] = backward_errors[i - 1] + reflection * temp
# Forecast
predictions = [0.0] * (nf + 1)
for n in range(bars - 1, bars + nf):
s = 0.0
for i in range(1, order + 1):
idx = n - i
if idx < bars:
s -= coefficients[i] * input_buffer[idx]
else:
pf_idx = idx - bars + 1
if 0 <= pf_idx < len(predictions):
s -= coefficients[i] * predictions[pf_idx]
target = n - bars + 1
if 0 <= target < len(predictions):
predictions[target] = s
# Convert to price forecast
current_open = self._open_history[-1]
price_forecast = [0.0] * (nf + 1)
if momentum_enabled:
price_forecast[0] = current_open
for i in range(1, nf + 1):
price_forecast[i] = price_forecast[i - 1] * math.exp(predictions[i])
elif roc_enabled:
price_forecast[0] = current_open
for i in range(1, nf + 1):
price_forecast[i] = price_forecast[i - 1] * (1.0 + predictions[i])
else:
for i in range(nf + 1):
price_forecast[i] = predictions[i] + average
# Evaluate signals
min_profit = self._min_profit_pips.Value * self._pip_size
max_loss = self._max_loss_pips.Value * self._pip_size
ymax = price_forecast[0]
ymin = price_forecast[0]
imax = 0
imin = 0
open_signal = 0
close_signal = 0
for i in range(1, nf):
value = price_forecast[i]
if value > ymax and open_signal == 0:
ymax = value
imax = i
if imin == 0 and ymax - ymin >= max_loss:
close_signal = 1
if imin == 0 and ymax - ymin >= min_profit:
open_signal = 1
if value < ymin and open_signal == 0:
ymin = value
imin = i
if imax == 0 and ymax - ymin >= max_loss:
close_signal = -1
if imax == 0 and ymax - ymin >= min_profit:
open_signal = -1
# Trade
has_position = self.Position != 0
if has_position:
if self.Position > 0 and (close_signal == -1 or open_signal == -1):
self.SellMarket()
return
if self.Position < 0 and (close_signal == 1 or open_signal == 1):
self.BuyMarket()
return
if open_signal == 0:
return
if open_signal > 0 and self.Position < self._max_positions.Value * self._order_volume.Value:
self.BuyMarket()
elif open_signal < 0:
short_exposure = abs(min(self.Position, 0))
if short_exposure < self._max_positions.Value * self._order_volume.Value:
self.SellMarket()
def CreateClone(self):
return burg_extrapolator_strategy()