N Candles v5 策略
概述
N Candles v5 策略会寻找连续同向的蜡烛,并在满足条件时沿同一方向开仓。 原始的 MQL 版本由 Vladimir Karputov 编写,此处将其迁移到 StockSharp 的 高级 API。策略仅处理已完成的蜡烛,可用于任意时间框架,默认使用 1 小时 K 线。
交易逻辑
- 每根蜡烛收盘后,策略判断其为阳线(收盘价高于开盘价)、阴线 (收盘价低于开盘价)或横盘(收盘价等于开盘价)。
- 连续阳线会增加多头计数并重置空头计数,连续阴线则相反;横盘蜡烛 会将两个计数同时归零。
- 当阳线计数达到
CandlesCount且当前净持仓为零或为空头时,策略按 市价买入。若存在空头仓位,会先行平仓,再按照TradeVolume建立多头。 - 当阴线计数达到
CandlesCount且当前净持仓为零或为多头时,策略按 市价卖出。若存在多头仓位,会先平仓,再建立空头。 - 只有在启用
UseTradingHours并且时间位于StartHour与EndHour之间时才允许新开仓。止盈、止损和追踪止损在时段之外仍然生效,以保证 风险控制。 MaxNetVolume限制了绝对仓位规模,避免持仓超过指定上限,保持了 原版脚本的风险约束。
风险控制
- 止盈 / 止损 – 以点数表示,根据标的的价格步长转换为绝对价格。 将数值设为 0 可关闭对应功能。
- 追踪止损 – 当价格相对入场价移动
TrailingStopPips点时激活,之后 每当价格再前进TrailingStepPips点就会收紧止损水平。 - 交易时段过滤 –
UseTradingHours打开后,策略仅在指定时段内开仓, 但会在任意时间继续处理已有仓位的风险。 - 最大净仓位 – 绝对持仓不会超过
MaxNetVolume。
参数
| 参数 | 说明 | 默认值 |
|---|---|---|
TradeVolume |
新开仓时使用的交易量。 | 1 |
CandlesCount |
触发信号所需的连续同向蜡烛数量。 | 3 |
TakeProfitPips |
止盈距离(点),0 表示关闭。 | 50 |
StopLossPips |
止损距离(点),0 表示关闭。 | 50 |
TrailingStopPips |
激活追踪止损的距离(点),0 表示关闭。 | 10 |
TrailingStepPips |
收紧追踪止损所需的追加移动距离(点)。 | 4 |
UseTradingHours |
是否启用交易时段过滤。 | true |
StartHour |
允许开仓的起始小时(0–23)。 | 11 |
EndHour |
允许开仓的结束小时(0–23)。 | 18 |
MaxNetVolume |
允许的最大净仓位规模。 | 2 |
CandleType |
用于分析的蜡烛类型,默认 1 小时。 | TimeSpan.FromHours(1) |
使用建议
- 策略通过
SubscribeCandles订阅蜡烛数据,适用于提供蜡烛序列的任何市场 品种。 - 由于逻辑基于已收盘蜡烛,在噪声较低的日内或更高级别时间框架上表现更 稳定。
- 根据标的的最小价格变动和点差调整止盈、止损与追踪参数,避免过度紧密。
- 在点差波动较大的品种上运行时,建议先用历史数据验证追踪止损设置,防止 因正常波动而提前出场。
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>
/// Detects a sequence of identical candles and opens trades in the same direction.
/// Implements optional take profit, stop loss, trailing stop and trading hour filter.
/// </summary>
public class NCandlesV5Strategy : Strategy
{
private readonly StrategyParam<int> _candlesCount;
private readonly StrategyParam<decimal> _takeProfitPips;
private readonly StrategyParam<decimal> _stopLossPips;
private readonly StrategyParam<decimal> _trailingStopPips;
private readonly StrategyParam<decimal> _trailingStepPips;
private readonly StrategyParam<bool> _useTradingHours;
private readonly StrategyParam<int> _startHour;
private readonly StrategyParam<int> _endHour;
private readonly StrategyParam<decimal> _volumeParam;
private readonly StrategyParam<decimal> _maxNetVolume;
private readonly StrategyParam<DataType> _candleType;
private int _bullishCount;
private int _bearishCount;
private decimal? _longEntryPrice;
private decimal? _longTakeProfit;
private decimal? _longStopLoss;
private decimal? _longTrailingStop;
private decimal? _shortEntryPrice;
private decimal? _shortTakeProfit;
private decimal? _shortStopLoss;
private decimal? _shortTrailingStop;
/// <summary>
/// Initializes a new instance of <see cref="NCandlesV5Strategy"/>.
/// </summary>
public NCandlesV5Strategy()
{
_volumeParam = Param(nameof(TradeVolume), 1m)
.SetDisplay("Trade Volume", "Order volume for entries", "Trading")
.SetGreaterThanZero();
_candlesCount = Param(nameof(CandlesCount), 3)
.SetDisplay("Candles Count", "Number of identical candles required", "General")
.SetGreaterThanZero();
_takeProfitPips = Param(nameof(TakeProfitPips), 50m)
.SetDisplay("Take Profit (pips)", "Take profit distance in pips", "Risk");
_stopLossPips = Param(nameof(StopLossPips), 50m)
.SetDisplay("Stop Loss (pips)", "Stop loss distance in pips", "Risk");
_trailingStopPips = Param(nameof(TrailingStopPips), 10m)
.SetDisplay("Trailing Stop (pips)", "Trailing stop activation distance", "Risk");
_trailingStepPips = Param(nameof(TrailingStepPips), 4m)
.SetDisplay("Trailing Step (pips)", "Increment required to tighten trailing stop", "Risk");
_useTradingHours = Param(nameof(UseTradingHours), true)
.SetDisplay("Use Trading Hours", "Enable trading session filter", "Trading");
_startHour = Param(nameof(StartHour), 11)
.SetRange(0, 23)
.SetDisplay("Start Hour", "Hour when trading is allowed to start", "Trading");
_endHour = Param(nameof(EndHour), 18)
.SetRange(0, 23)
.SetDisplay("End Hour", "Hour when trading is allowed to stop", "Trading");
_maxNetVolume = Param(nameof(MaxNetVolume), 2m)
.SetDisplay("Max Net Volume", "Maximum absolute net position", "Risk")
.SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to analyze", "General");
Volume = _volumeParam.Value;
}
/// <summary>
/// Trade volume used for new entries.
/// </summary>
public decimal TradeVolume
{
get => _volumeParam.Value;
set
{
_volumeParam.Value = value;
Volume = value;
}
}
/// <summary>
/// Number of consecutive identical candles required for a signal.
/// </summary>
public int CandlesCount
{
get => _candlesCount.Value;
set => _candlesCount.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 activation distance in pips.
/// </summary>
public decimal TrailingStopPips
{
get => _trailingStopPips.Value;
set => _trailingStopPips.Value = value;
}
/// <summary>
/// Trailing step distance in pips.
/// </summary>
public decimal TrailingStepPips
{
get => _trailingStepPips.Value;
set => _trailingStepPips.Value = value;
}
/// <summary>
/// Enables the trading hour filter.
/// </summary>
public bool UseTradingHours
{
get => _useTradingHours.Value;
set => _useTradingHours.Value = value;
}
/// <summary>
/// First hour of the allowed trading window.
/// </summary>
public int StartHour
{
get => _startHour.Value;
set => _startHour.Value = value;
}
/// <summary>
/// Last hour of the allowed trading window.
/// </summary>
public int EndHour
{
get => _endHour.Value;
set => _endHour.Value = value;
}
/// <summary>
/// Maximum absolute net position allowed.
/// </summary>
public decimal MaxNetVolume
{
get => _maxNetVolume.Value;
set => _maxNetVolume.Value = value;
}
/// <summary>
/// Candle type used for pattern detection.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
Volume = TradeVolume;
ResetState();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
if (UseTradingHours && StartHour >= EndHour)
throw new InvalidOperationException("Start hour must be less than end hour when trading hours filter is enabled.");
Volume = TradeVolume;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
// Work only with completed candles to avoid premature signals.
if (candle.State != CandleStates.Finished)
return;
// Refresh trailing and exit logic before looking for new opportunities.
UpdateRiskManagement(candle);
var direction = GetDirection(candle);
// Track bullish and bearish streak length.
if (direction == 1)
{
_bullishCount++;
_bearishCount = 0;
}
else if (direction == -1)
{
_bearishCount++;
_bullishCount = 0;
}
else
{
_bullishCount = 0;
_bearishCount = 0;
}
var tradingAllowed = !UseTradingHours || (candle.OpenTime.Hour >= StartHour && candle.OpenTime.Hour <= EndHour);
// Skip entries outside the configured session window.
if (!tradingAllowed)
return;
var volume = TradeVolume;
if (volume <= 0m)
return;
var step = Security?.PriceStep ?? 1m;
// Use instrument price step to translate pip distances to absolute prices.
if (_bullishCount >= CandlesCount && Position <= 0m)
{
// Enter long after detecting the required number of bullish candles in a row.
var orderVolume = volume + Math.Max(0m, -Position);
if (orderVolume > 0m && Math.Abs(Position + orderVolume) <= MaxNetVolume)
{
BuyMarket();
SetupLongState(candle, step);
}
ResetCounters();
}
else if (_bearishCount >= CandlesCount && Position >= 0m)
{
// Enter short after detecting the required number of bearish candles in a row.
var orderVolume = volume + Math.Max(0m, Position);
if (orderVolume > 0m && Math.Abs(Position - orderVolume) <= MaxNetVolume)
{
SellMarket();
SetupShortState(candle, step);
}
ResetCounters();
}
}
private void UpdateRiskManagement(ICandleMessage candle)
{
if (Position > 0m)
{
ManageLongPosition(candle);
}
else
{
ClearLongState();
}
if (Position < 0m)
{
ManageShortPosition(candle);
}
else
{
ClearShortState();
}
}
private void ManageLongPosition(ICandleMessage candle)
{
if (_longEntryPrice is null)
// Capture entry price if it was not stored yet (for example after restart).
_longEntryPrice = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
var close = candle.ClosePrice;
var high = candle.HighPrice;
var low = candle.LowPrice;
var trailingDistance = TrailingStopPips > 0m ? TrailingStopPips * step : 0m;
var trailingStep = TrailingStepPips > 0m ? TrailingStepPips * step : 0m;
if (TrailingStopPips > 0m && _longEntryPrice is decimal entry)
{
// Update trailing stop level according to the latest candle.
if (_longTrailingStop is null)
{
if (close - trailingDistance > entry)
_longTrailingStop = entry;
}
else
{
var newLevel = close - trailingDistance;
if (newLevel - trailingStep > _longTrailingStop)
_longTrailingStop = newLevel;
}
}
else
{
_longTrailingStop = null;
}
var exitVolume = Position > 0m ? Position : 0m;
var closed = false;
// Exit the long position when any protective target is triggered.
if (!closed && _longTakeProfit is decimal takeProfit && high >= takeProfit)
{
if (exitVolume > 0m)
SellMarket();
closed = true;
}
if (!closed && _longStopLoss is decimal stopLoss && low <= stopLoss)
{
if (exitVolume > 0m)
SellMarket();
closed = true;
}
if (!closed && _longTrailingStop is decimal trailingStop && low <= trailingStop)
{
if (exitVolume > 0m)
SellMarket();
closed = true;
}
if (closed)
ClearLongState();
}
private void ManageShortPosition(ICandleMessage candle)
{
if (_shortEntryPrice is null)
// Capture entry price if it was not stored yet (for example after restart).
_shortEntryPrice = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
var close = candle.ClosePrice;
var high = candle.HighPrice;
var low = candle.LowPrice;
var trailingDistance = TrailingStopPips > 0m ? TrailingStopPips * step : 0m;
var trailingStep = TrailingStepPips > 0m ? TrailingStepPips * step : 0m;
if (TrailingStopPips > 0m && _shortEntryPrice is decimal entry)
{
// Update trailing stop level for the active short position.
if (_shortTrailingStop is null)
{
if (close + trailingDistance < entry)
_shortTrailingStop = entry;
}
else
{
var newLevel = close + trailingDistance;
if (newLevel + trailingStep < _shortTrailingStop)
_shortTrailingStop = newLevel;
}
}
else
{
_shortTrailingStop = null;
}
var exitVolume = Position < 0m ? -Position : 0m;
var closed = false;
// Exit the short position when any protective target is triggered.
if (!closed && _shortTakeProfit is decimal takeProfit && low <= takeProfit)
{
if (exitVolume > 0m)
BuyMarket();
closed = true;
}
if (!closed && _shortStopLoss is decimal stopLoss && high >= stopLoss)
{
if (exitVolume > 0m)
BuyMarket();
closed = true;
}
if (!closed && _shortTrailingStop is decimal trailingStop && high >= trailingStop)
{
if (exitVolume > 0m)
BuyMarket();
closed = true;
}
if (closed)
ClearShortState();
}
private static int GetDirection(ICandleMessage candle)
{
if (candle.ClosePrice > candle.OpenPrice)
return 1;
if (candle.ClosePrice < candle.OpenPrice)
return -1;
return 0;
}
private void SetupLongState(ICandleMessage candle, decimal step)
{
var entryPrice = candle.ClosePrice;
// Store reference levels for long-side risk management.
_longEntryPrice = entryPrice;
_longTakeProfit = TakeProfitPips > 0m ? entryPrice + TakeProfitPips * step : null;
_longStopLoss = StopLossPips > 0m ? entryPrice - StopLossPips * step : null;
_longTrailingStop = null;
ClearShortState();
}
private void SetupShortState(ICandleMessage candle, decimal step)
{
var entryPrice = candle.ClosePrice;
// Store reference levels for short-side risk management.
_shortEntryPrice = entryPrice;
_shortTakeProfit = TakeProfitPips > 0m ? entryPrice - TakeProfitPips * step : null;
_shortStopLoss = StopLossPips > 0m ? entryPrice + StopLossPips * step : null;
_shortTrailingStop = null;
ClearLongState();
}
private void ClearLongState()
{
_longEntryPrice = null;
_longTakeProfit = null;
_longStopLoss = null;
_longTrailingStop = null;
}
private void ClearShortState()
{
_shortEntryPrice = null;
_shortTakeProfit = null;
_shortStopLoss = null;
_shortTrailingStop = null;
}
private void ResetState()
{
ResetCounters();
ClearLongState();
ClearShortState();
}
private void ResetCounters()
{
_bullishCount = 0;
_bearishCount = 0;
}
}
import clr
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
from StockSharp.Algo.Strategies import Strategy
class n_candles_v5_strategy(Strategy):
"""N Candles v5: trades after N consecutive same-direction candles with SL/TP/trailing."""
def __init__(self):
super(n_candles_v5_strategy, self).__init__()
self._volume_param = self.Param("TradeVolume", 1.0) \
.SetGreaterThanZero() \
.SetDisplay("Trade Volume", "Order volume for entries", "Trading")
self._candles_count = self.Param("CandlesCount", 3) \
.SetGreaterThanZero() \
.SetDisplay("Candles Count", "Number of identical candles required", "General")
self._take_profit_pips = self.Param("TakeProfitPips", 50.0) \
.SetDisplay("Take Profit (pips)", "Take profit distance in pips", "Risk")
self._stop_loss_pips = self.Param("StopLossPips", 50.0) \
.SetDisplay("Stop Loss (pips)", "Stop loss distance in pips", "Risk")
self._trailing_stop_pips = self.Param("TrailingStopPips", 10.0) \
.SetDisplay("Trailing Stop (pips)", "Trailing stop activation distance", "Risk")
self._trailing_step_pips = self.Param("TrailingStepPips", 4.0) \
.SetDisplay("Trailing Step (pips)", "Increment required to tighten trailing stop", "Risk")
self._use_trading_hours = self.Param("UseTradingHours", True) \
.SetDisplay("Use Trading Hours", "Enable trading session filter", "Trading")
self._start_hour = self.Param("StartHour", 11) \
.SetDisplay("Start Hour", "Hour when trading is allowed to start", "Trading")
self._end_hour = self.Param("EndHour", 18) \
.SetDisplay("End Hour", "Hour when trading is allowed to stop", "Trading")
self._max_net_volume = self.Param("MaxNetVolume", 2.0) \
.SetGreaterThanZero() \
.SetDisplay("Max Net Volume", "Maximum absolute net position", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to analyze", "General")
self._bullish_count = 0
self._bearish_count = 0
self._long_entry_price = None
self._long_take_profit = None
self._long_stop_loss = None
self._long_trailing_stop = None
self._short_entry_price = None
self._short_take_profit = None
self._short_stop_loss = None
self._short_trailing_stop = None
@property
def TradeVolume(self):
return float(self._volume_param.Value)
@property
def CandlesCount(self):
return int(self._candles_count.Value)
@property
def TakeProfitPips(self):
return float(self._take_profit_pips.Value)
@property
def StopLossPips(self):
return float(self._stop_loss_pips.Value)
@property
def TrailingStopPips(self):
return float(self._trailing_stop_pips.Value)
@property
def TrailingStepPips(self):
return float(self._trailing_step_pips.Value)
@property
def UseTradingHours(self):
return self._use_trading_hours.Value
@property
def StartHour(self):
return int(self._start_hour.Value)
@property
def EndHour(self):
return int(self._end_hour.Value)
@property
def MaxNetVolume(self):
return float(self._max_net_volume.Value)
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(n_candles_v5_strategy, self).OnStarted2(time)
self._bullish_count = 0
self._bearish_count = 0
self._clear_long_state()
self._clear_short_state()
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
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
h = float(candle.HighPrice)
lo = float(candle.LowPrice)
self._update_risk_management(candle)
# Determine direction
if close > open_p:
direction = 1
elif close < open_p:
direction = -1
else:
direction = 0
if direction == 1:
self._bullish_count += 1
self._bearish_count = 0
elif direction == -1:
self._bearish_count += 1
self._bullish_count = 0
else:
self._bullish_count = 0
self._bearish_count = 0
trading_allowed = not self.UseTradingHours or (candle.OpenTime.Hour >= self.StartHour and candle.OpenTime.Hour <= self.EndHour)
if not trading_allowed:
return
volume = self.TradeVolume
if volume <= 0:
return
sec = self.Security
step = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None else 1.0
if self._bullish_count >= self.CandlesCount and self.Position <= 0:
order_volume = volume + max(0.0, -self.Position)
if order_volume > 0 and abs(self.Position + order_volume) <= self.MaxNetVolume:
self.BuyMarket()
self._setup_long_state(candle, step)
self._reset_counters()
elif self._bearish_count >= self.CandlesCount and self.Position >= 0:
order_volume = volume + max(0.0, self.Position)
if order_volume > 0 and abs(self.Position - order_volume) <= self.MaxNetVolume:
self.SellMarket()
self._setup_short_state(candle, step)
self._reset_counters()
def _update_risk_management(self, candle):
if self.Position > 0:
self._manage_long_position(candle)
else:
self._clear_long_state()
if self.Position < 0:
self._manage_short_position(candle)
else:
self._clear_short_state()
def _manage_long_position(self, candle):
if self._long_entry_price is None:
self._long_entry_price = float(candle.ClosePrice)
sec = self.Security
step = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None else 1.0
close = float(candle.ClosePrice)
h = float(candle.HighPrice)
lo = float(candle.LowPrice)
trailing_distance = self.TrailingStopPips * step if self.TrailingStopPips > 0 else 0.0
trailing_step = self.TrailingStepPips * step if self.TrailingStepPips > 0 else 0.0
if self.TrailingStopPips > 0 and self._long_entry_price is not None:
entry = self._long_entry_price
if self._long_trailing_stop is None:
if close - trailing_distance > entry:
self._long_trailing_stop = entry
else:
new_level = close - trailing_distance
if new_level - trailing_step > self._long_trailing_stop:
self._long_trailing_stop = new_level
else:
self._long_trailing_stop = None
closed = False
if not closed and self._long_take_profit is not None and h >= self._long_take_profit:
if self.Position > 0:
self.SellMarket()
closed = True
if not closed and self._long_stop_loss is not None and lo <= self._long_stop_loss:
if self.Position > 0:
self.SellMarket()
closed = True
if not closed and self._long_trailing_stop is not None and lo <= self._long_trailing_stop:
if self.Position > 0:
self.SellMarket()
closed = True
if closed:
self._clear_long_state()
def _manage_short_position(self, candle):
if self._short_entry_price is None:
self._short_entry_price = float(candle.ClosePrice)
sec = self.Security
step = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None else 1.0
close = float(candle.ClosePrice)
h = float(candle.HighPrice)
lo = float(candle.LowPrice)
trailing_distance = self.TrailingStopPips * step if self.TrailingStopPips > 0 else 0.0
trailing_step = self.TrailingStepPips * step if self.TrailingStepPips > 0 else 0.0
if self.TrailingStopPips > 0 and self._short_entry_price is not None:
entry = self._short_entry_price
if self._short_trailing_stop is None:
if close + trailing_distance < entry:
self._short_trailing_stop = entry
else:
new_level = close + trailing_distance
if new_level + trailing_step < self._short_trailing_stop:
self._short_trailing_stop = new_level
else:
self._short_trailing_stop = None
closed = False
if not closed and self._short_take_profit is not None and lo <= self._short_take_profit:
if self.Position < 0:
self.BuyMarket()
closed = True
if not closed and self._short_stop_loss is not None and h >= self._short_stop_loss:
if self.Position < 0:
self.BuyMarket()
closed = True
if not closed and self._short_trailing_stop is not None and h >= self._short_trailing_stop:
if self.Position < 0:
self.BuyMarket()
closed = True
if closed:
self._clear_short_state()
def _setup_long_state(self, candle, step):
entry_price = float(candle.ClosePrice)
self._long_entry_price = entry_price
self._long_take_profit = entry_price + self.TakeProfitPips * step if self.TakeProfitPips > 0 else None
self._long_stop_loss = entry_price - self.StopLossPips * step if self.StopLossPips > 0 else None
self._long_trailing_stop = None
self._clear_short_state()
def _setup_short_state(self, candle, step):
entry_price = float(candle.ClosePrice)
self._short_entry_price = entry_price
self._short_take_profit = entry_price - self.TakeProfitPips * step if self.TakeProfitPips > 0 else None
self._short_stop_loss = entry_price + self.StopLossPips * step if self.StopLossPips > 0 else None
self._short_trailing_stop = None
self._clear_long_state()
def _clear_long_state(self):
self._long_entry_price = None
self._long_take_profit = None
self._long_stop_loss = None
self._long_trailing_stop = None
def _clear_short_state(self):
self._short_entry_price = None
self._short_take_profit = None
self._short_stop_loss = None
self._short_trailing_stop = None
def _reset_counters(self):
self._bullish_count = 0
self._bearish_count = 0
def OnReseted(self):
super(n_candles_v5_strategy, self).OnReseted()
self._bullish_count = 0
self._bearish_count = 0
self._clear_long_state()
self._clear_short_state()
def CreateClone(self):
return n_candles_v5_strategy()