Clouds Trade 2 策略
本策略为 Vladimir Karputov 的 "cloud's trade 2" EA 的 C# 版本。它结合了两次最近的比尔·威廉姆斯分形信号以及在超买/超卖区域的随机指标交叉来捕捉突破。风控部分复刻原始输入,提供固定止损止盈、带步长的移动止损以及按金额和点数锁定利润的功能。
交易逻辑
- 数据源:单一时间框蜡烛线(默认 15 分钟)。
- 指标:
- 随机指标,使用可配置的 %K 回溯长度、平滑长度和 %D 平滑。
- 五根蜡烛的滑动高低价窗口,用于重建上下分形。
- 开仓条件:
- 做多:最新的两个有效分形均为下分形,或 %D 下降到 20 以下并向下穿越 %K。当前不得持有仓位,并且“每日一次”过滤器允许开仓。
- 做空:最新两个分形均为上分形,或 %D 升至 80 以上并向上穿越 %K。
- 平仓与风控:
- 以入场价为基准的固定止损与止盈距离。
- 可选的移动止损,仅在浮盈超过“移动距离 + 步长”后上调(或下调)止损。
- 当未实现收益达到设定的金额或点数时立即平仓。
- 为贴近 MQL 版本,止损/止盈通过检查蜡烛最高价与最低价进行模拟。
参数说明
- Order Volume:每次开仓的基础手数。
- Stop/Take Offsets:止损与止盈的绝对价格距离;若要还原原始 EA 的“点”设置,需要根据交易品种的最小价格变动来调整。
- Trailing Stop & Step:移动止损的距离与最小步长。
- Min Profit (Currency / Points):按金额或价格差触发的提前平仓阈值。
- Use Fractals / Use Stochastic:分别启用分形或随机指标信号。
- One Trade Per Day:限制每天只开一次新仓。
- Stochastic Settings:%K、Slowing 与 %D 的长度。
- Candle Type:用于计算信号的蜡烛时间框架。
备注
- 盈亏判断采用“价格变动 × 仓位”近似原策略中的佣金和掉期调整。
- 移动止损的触发条件与 MQL 脚本一致,需要超过设定距离再加步长才会移动。
- 在外汇品种中,可将止损/止盈距离设为所需点数乘以
Point(例如五位报价的 50 点 ≈ 0.005)。
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>
/// Port of the "cloud's trade 2" MQL5 strategy that combines stochastic reversals with fractal confirmations.
/// </summary>
public class CloudsTrade2Strategy : Strategy
{
private readonly StrategyParam<decimal> _orderVolume;
private readonly StrategyParam<decimal> _stopLossOffset;
private readonly StrategyParam<decimal> _takeProfitOffset;
private readonly StrategyParam<decimal> _trailingStopOffset;
private readonly StrategyParam<decimal> _trailingStepOffset;
private readonly StrategyParam<decimal> _minProfitCurrency;
private readonly StrategyParam<decimal> _minProfitPoints;
private readonly StrategyParam<bool> _useFractals;
private readonly StrategyParam<bool> _useStochastic;
private readonly StrategyParam<bool> _oneTradePerDay;
private readonly StrategyParam<int> _kPeriod;
private readonly StrategyParam<int> _dPeriod;
private readonly StrategyParam<int> _slowingPeriod;
private readonly StrategyParam<DataType> _candleType;
private StochasticOscillator _stochastic;
private decimal _priorK;
private decimal _priorD;
private decimal _lastK;
private decimal _lastD;
private bool _hasPriorStoch;
private bool _hasLastStoch;
private decimal _h1;
private decimal _h2;
private decimal _h3;
private decimal _h4;
private decimal _h5;
private decimal _l1;
private decimal _l2;
private decimal _l3;
private decimal _l4;
private decimal _l5;
private FractalTypes? _latestFractal;
private FractalTypes? _previousFractal;
private int _fractalBufferCount;
private decimal? _stopPrice;
private decimal? _takeProfitPrice;
private decimal _entryPrice;
private DateTime? _lastEntryDate;
private enum FractalTypes
{
Up,
Down
}
public decimal OrderVolume
{
get => _orderVolume.Value;
set => _orderVolume.Value = value;
}
public decimal StopLossOffset
{
get => _stopLossOffset.Value;
set => _stopLossOffset.Value = value;
}
public decimal TakeProfitOffset
{
get => _takeProfitOffset.Value;
set => _takeProfitOffset.Value = value;
}
public decimal TrailingStopOffset
{
get => _trailingStopOffset.Value;
set => _trailingStopOffset.Value = value;
}
public decimal TrailingStepOffset
{
get => _trailingStepOffset.Value;
set => _trailingStepOffset.Value = value;
}
public decimal MinProfitCurrency
{
get => _minProfitCurrency.Value;
set => _minProfitCurrency.Value = value;
}
public decimal MinProfitPoints
{
get => _minProfitPoints.Value;
set => _minProfitPoints.Value = value;
}
public bool UseFractals
{
get => _useFractals.Value;
set => _useFractals.Value = value;
}
public bool UseStochastic
{
get => _useStochastic.Value;
set => _useStochastic.Value = value;
}
public bool OneTradePerDay
{
get => _oneTradePerDay.Value;
set => _oneTradePerDay.Value = value;
}
public int KPeriod
{
get => _kPeriod.Value;
set => _kPeriod.Value = value;
}
public int DPeriod
{
get => _dPeriod.Value;
set => _dPeriod.Value = value;
}
public int SlowingPeriod
{
get => _slowingPeriod.Value;
set => _slowingPeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public CloudsTrade2Strategy()
{
_orderVolume = Param(nameof(OrderVolume), 1m)
.SetGreaterThanZero()
.SetDisplay("Order Volume", "Default order volume", "General");
_stopLossOffset = Param(nameof(StopLossOffset), 0.005m)
.SetDisplay("Stop Loss Offset", "Stop loss distance in price units", "Risk");
_takeProfitOffset = Param(nameof(TakeProfitOffset), 0.005m)
.SetDisplay("Take Profit Offset", "Take profit distance in price units", "Risk");
_trailingStopOffset = Param(nameof(TrailingStopOffset), 0m)
.SetDisplay("Trailing Stop Offset", "Trailing stop distance in price units", "Risk");
_trailingStepOffset = Param(nameof(TrailingStepOffset), 0.0005m)
.SetDisplay("Trailing Step", "Minimum price improvement for trailing", "Risk");
_minProfitCurrency = Param(nameof(MinProfitCurrency), 10m)
.SetDisplay("Min Profit (Currency)", "Close position when unrealized profit reaches this amount", "Exit");
_minProfitPoints = Param(nameof(MinProfitPoints), 0.001m)
.SetDisplay("Min Profit (Points)", "Close position after this favorable price move", "Exit");
_useFractals = Param(nameof(UseFractals), true)
.SetDisplay("Use Fractals", "Enable fractal based signals", "Signals");
_useStochastic = Param(nameof(UseStochastic), false)
.SetDisplay("Use Stochastic", "Enable stochastic based signals", "Signals");
_oneTradePerDay = Param(nameof(OneTradePerDay), true)
.SetDisplay("One Trade Per Day", "Allow only one entry per trading day", "Risk");
_kPeriod = Param(nameof(KPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("%K Period", "Lookback for stochastic calculation", "Stochastic");
_dPeriod = Param(nameof(DPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("%D Period", "Smoothing length for %D line", "Stochastic");
_slowingPeriod = Param(nameof(SlowingPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("Slowing", "Smoothing length for %K line", "Stochastic");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for signal evaluation", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_priorK = 0m;
_priorD = 0m;
_lastK = 0m;
_lastD = 0m;
_hasPriorStoch = false;
_hasLastStoch = false;
_h1 = _h2 = _h3 = _h4 = _h5 = 0m;
_l1 = _l2 = _l3 = _l4 = _l5 = 0m;
_latestFractal = null;
_previousFractal = null;
_fractalBufferCount = 0;
_stopPrice = null;
_takeProfitPrice = null;
_entryPrice = 0m;
_lastEntryDate = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
Volume = OrderVolume;
var subscription = SubscribeCandles(CandleType);
if (UseStochastic)
{
_stochastic = new StochasticOscillator
{
K = { Length = KPeriod },
D = { Length = DPeriod }
};
subscription
.BindEx(_stochastic, ProcessCandle)
.Start();
}
else
{
subscription
.Bind(ProcessCandleWithoutStochastic)
.Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
if (_stochastic != null)
DrawIndicator(area, _stochastic);
DrawOwnTrades(area);
}
}
private void ProcessCandleWithoutStochastic(ICandleMessage candle)
=> ProcessCandle(candle, null);
private void ProcessCandle(ICandleMessage candle, IIndicatorValue stochValue)
{
if (candle.State != CandleStates.Finished)
return;
Volume = OrderVolume;
// Evaluate indicator signals for the finished candle
var stochSignal = EvaluateStochasticSignal(stochValue);
UpdateFractals(candle);
var fractalSignal = GetFractalSignal();
HandleOpenPosition(candle);
var signal = 0;
if (stochSignal == 2 || fractalSignal == 2)
signal = 2;
else if (stochSignal == 1 || fractalSignal == 1)
signal = 1;
if (signal == 0)
return;
if (Position != 0)
return;
if (OneTradePerDay && _lastEntryDate.HasValue && _lastEntryDate.Value == candle.OpenTime.Date)
return;
if (signal == 1)
{
BuyMarket(OrderVolume);
InitializeTargets(candle.ClosePrice, true);
_lastEntryDate = candle.OpenTime.Date;
}
else if (signal == 2)
{
SellMarket(OrderVolume);
InitializeTargets(candle.ClosePrice, false);
_lastEntryDate = candle.OpenTime.Date;
}
}
private int EvaluateStochasticSignal(IIndicatorValue stochValue)
{
if (!UseStochastic || stochValue is not StochasticOscillatorValue typed)
return 0;
if (typed.K is not decimal currentK || typed.D is not decimal currentD)
return 0;
// Seed the buffers with the first finalized stochastic values
if (!_hasLastStoch)
{
_lastK = currentK;
_lastD = currentD;
_hasLastStoch = true;
return 0;
}
if (!_hasPriorStoch)
{
_priorK = _lastK;
_priorD = _lastD;
_lastK = currentK;
_lastD = currentD;
_hasPriorStoch = true;
return 0;
}
var sellSignal = _lastD >= 80m && _priorD <= _priorK && _lastD >= _lastK;
var buySignal = _lastD <= 20m && _priorD >= _priorK && _lastD <= _lastK;
_priorK = _lastK;
_priorD = _lastD;
_lastK = currentK;
_lastD = currentD;
if (sellSignal)
return 2;
if (buySignal)
return 1;
return 0;
}
private void UpdateFractals(ICandleMessage candle)
{
// Shift the rolling window so that index 3 represents the potential fractal point
_h1 = _h2;
_h2 = _h3;
_h3 = _h4;
_h4 = _h5;
_h5 = candle.HighPrice;
_l1 = _l2;
_l2 = _l3;
_l3 = _l4;
_l4 = _l5;
_l5 = candle.LowPrice;
if (_fractalBufferCount < 5)
{
_fractalBufferCount++;
return;
}
var upFractal = _h3 > _h1 && _h3 > _h2 && _h3 > _h4 && _h3 > _h5;
var downFractal = _l3 < _l1 && _l3 < _l2 && _l3 < _l4 && _l3 < _l5;
if (upFractal)
RegisterFractal(FractalTypes.Up);
if (downFractal)
RegisterFractal(FractalTypes.Down);
}
private int GetFractalSignal()
{
if (!UseFractals)
return 0;
if (_latestFractal is null || _previousFractal is null)
return 0;
if (_latestFractal == FractalTypes.Up && _previousFractal == FractalTypes.Up)
return 2;
if (_latestFractal == FractalTypes.Down && _previousFractal == FractalTypes.Down)
return 1;
return 0;
}
private void RegisterFractal(FractalTypes type)
{
_previousFractal = _latestFractal;
_latestFractal = type;
}
private void HandleOpenPosition(ICandleMessage candle)
{
if (Position == 0)
return;
if (Position > 0)
{
// Manage protective logic for long positions
UpdateTrailing(candle, true);
if (_stopPrice is decimal stop && candle.LowPrice <= stop)
{
SellMarket(Math.Abs(Position));
ResetTradeState();
return;
}
if (_takeProfitPrice is decimal take && candle.HighPrice >= take)
{
SellMarket(Math.Abs(Position));
ResetTradeState();
return;
}
var profit = (candle.ClosePrice - _entryPrice) * Position;
var priceGain = candle.ClosePrice - _entryPrice;
if (MinProfitCurrency > 0m && profit >= MinProfitCurrency)
{
SellMarket(Math.Abs(Position));
ResetTradeState();
return;
}
if (MinProfitPoints > 0m && priceGain >= MinProfitPoints)
{
SellMarket(Math.Abs(Position));
ResetTradeState();
}
}
else if (Position < 0)
{
// Manage protective logic for short positions
UpdateTrailing(candle, false);
if (_stopPrice is decimal stop && candle.HighPrice >= stop)
{
BuyMarket(Math.Abs(Position));
ResetTradeState();
return;
}
if (_takeProfitPrice is decimal take && candle.LowPrice <= take)
{
BuyMarket(Math.Abs(Position));
ResetTradeState();
return;
}
var profit = (_entryPrice - candle.ClosePrice) * Math.Abs(Position);
var priceGain = _entryPrice - candle.ClosePrice;
if (MinProfitCurrency > 0m && profit >= MinProfitCurrency)
{
BuyMarket(Math.Abs(Position));
ResetTradeState();
return;
}
if (MinProfitPoints > 0m && priceGain >= MinProfitPoints)
{
BuyMarket(Math.Abs(Position));
ResetTradeState();
}
}
}
private void UpdateTrailing(ICandleMessage candle, bool isLong)
{
// Follow the original trailing stop rules using configurable offsets
if (TrailingStopOffset <= 0m)
return;
if (isLong)
{
var profitDistance = candle.ClosePrice - _entryPrice;
if (profitDistance > TrailingStopOffset + TrailingStepOffset)
{
var newStop = candle.ClosePrice - TrailingStopOffset;
if (_stopPrice is not decimal currentStop || newStop > currentStop + TrailingStepOffset)
_stopPrice = newStop;
}
}
else
{
var profitDistance = _entryPrice - candle.ClosePrice;
if (profitDistance > TrailingStopOffset + TrailingStepOffset)
{
var newStop = candle.ClosePrice + TrailingStopOffset;
if (_stopPrice is not decimal currentStop || newStop < currentStop - TrailingStepOffset)
_stopPrice = newStop;
}
}
}
private void InitializeTargets(decimal entryPrice, bool isLong)
{
// Store the latest entry price and prepare static protective levels
_entryPrice = entryPrice;
if (isLong)
{
_stopPrice = StopLossOffset > 0m ? entryPrice - StopLossOffset : null;
_takeProfitPrice = TakeProfitOffset > 0m ? entryPrice + TakeProfitOffset : null;
}
else
{
_stopPrice = StopLossOffset > 0m ? entryPrice + StopLossOffset : null;
_takeProfitPrice = TakeProfitOffset > 0m ? entryPrice - TakeProfitOffset : null;
}
}
private void ResetTradeState()
{
_stopPrice = null;
_takeProfitPrice = null;
_entryPrice = 0m;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from StockSharp.Algo.Indicators import StochasticOscillator
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Messages import DataType, CandleStates
from System import TimeSpan, Math
class clouds_trade2_strategy(Strategy):
# FractalTypes: 0=Up, 1=Down
FRACTAL_UP = 0
FRACTAL_DOWN = 1
def __init__(self):
super(clouds_trade2_strategy, self).__init__()
self._order_volume = self.Param("OrderVolume", 1.0)
self._stop_loss_offset = self.Param("StopLossOffset", 0.005)
self._take_profit_offset = self.Param("TakeProfitOffset", 0.005)
self._trailing_stop_offset = self.Param("TrailingStopOffset", 0.0)
self._trailing_step_offset = self.Param("TrailingStepOffset", 0.0005)
self._min_profit_currency = self.Param("MinProfitCurrency", 10.0)
self._min_profit_points = self.Param("MinProfitPoints", 0.001)
self._use_fractals = self.Param("UseFractals", True)
self._use_stochastic = self.Param("UseStochastic", False)
self._one_trade_per_day = self.Param("OneTradePerDay", True)
self._k_period = self.Param("KPeriod", 5)
self._d_period = self.Param("DPeriod", 3)
self._slowing_period = self.Param("SlowingPeriod", 3)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._stochastic = None
# Stochastic history
self._prior_k = 0.0
self._prior_d = 0.0
self._last_k = 0.0
self._last_d = 0.0
self._has_prior_stoch = False
self._has_last_stoch = False
# Fractal buffer (5-candle rolling window)
self._h1 = 0.0
self._h2 = 0.0
self._h3 = 0.0
self._h4 = 0.0
self._h5 = 0.0
self._l1 = 0.0
self._l2 = 0.0
self._l3 = 0.0
self._l4 = 0.0
self._l5 = 0.0
self._latest_fractal = None
self._previous_fractal = None
self._fractal_buffer_count = 0
# Position management
self._stop_price = None
self._take_profit_price = None
self._entry_price = 0.0
self._last_entry_date = None
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(clouds_trade2_strategy, self).OnStarted2(time)
if self._use_stochastic.Value:
self._stochastic = StochasticOscillator()
self._stochastic.K.Length = self._k_period.Value
self._stochastic.D.Length = self._d_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
# Process stochastic manually if enabled
stoch_signal = 0
if self._use_stochastic.Value and self._stochastic is not None:
stoch_result = self._stochastic.Process(candle)
if not stoch_result.IsEmpty and self._stochastic.IsFormed:
stoch_signal = self._evaluate_stochastic_signal(stoch_result)
# Update fractals
self._update_fractals(candle)
fractal_signal = self._get_fractal_signal()
# Handle open position
self._handle_open_position(candle)
# Determine combined signal
signal = 0
if stoch_signal == 2 or fractal_signal == 2:
signal = 2
elif stoch_signal == 1 or fractal_signal == 1:
signal = 1
if signal == 0:
return
if self.Position != 0:
return
if self._one_trade_per_day.Value and self._last_entry_date is not None and self._last_entry_date == candle.OpenTime.Date:
return
if signal == 1:
self.BuyMarket(self._order_volume.Value)
self._initialize_targets(float(candle.ClosePrice), True)
self._last_entry_date = candle.OpenTime.Date
elif signal == 2:
self.SellMarket(self._order_volume.Value)
self._initialize_targets(float(candle.ClosePrice), False)
self._last_entry_date = candle.OpenTime.Date
def _evaluate_stochastic_signal(self, stoch_value):
# Extract K and D values from the complex indicator value
try:
current_k = float(stoch_value.GetValue[0]) if hasattr(stoch_value, 'GetValue') else None
current_d = float(stoch_value.GetValue[1]) if hasattr(stoch_value, 'GetValue') else None
except:
try:
current_k = float(stoch_value)
current_d = None
except:
return 0
if current_k is None:
return 0
if current_d is None:
current_d = current_k
if not self._has_last_stoch:
self._last_k = current_k
self._last_d = current_d
self._has_last_stoch = True
return 0
if not self._has_prior_stoch:
self._prior_k = self._last_k
self._prior_d = self._last_d
self._last_k = current_k
self._last_d = current_d
self._has_prior_stoch = True
return 0
sell_signal = self._last_d >= 80.0 and self._prior_d <= self._prior_k and self._last_d >= self._last_k
buy_signal = self._last_d <= 20.0 and self._prior_d >= self._prior_k and self._last_d <= self._last_k
self._prior_k = self._last_k
self._prior_d = self._last_d
self._last_k = current_k
self._last_d = current_d
if sell_signal:
return 2
if buy_signal:
return 1
return 0
def _update_fractals(self, candle):
# Shift the rolling window
self._h1 = self._h2
self._h2 = self._h3
self._h3 = self._h4
self._h4 = self._h5
self._h5 = float(candle.HighPrice)
self._l1 = self._l2
self._l2 = self._l3
self._l3 = self._l4
self._l4 = self._l5
self._l5 = float(candle.LowPrice)
if self._fractal_buffer_count < 5:
self._fractal_buffer_count += 1
return
up_fractal = self._h3 > self._h1 and self._h3 > self._h2 and self._h3 > self._h4 and self._h3 > self._h5
down_fractal = self._l3 < self._l1 and self._l3 < self._l2 and self._l3 < self._l4 and self._l3 < self._l5
if up_fractal:
self._register_fractal(self.FRACTAL_UP)
if down_fractal:
self._register_fractal(self.FRACTAL_DOWN)
def _get_fractal_signal(self):
if not self._use_fractals.Value:
return 0
if self._latest_fractal is None or self._previous_fractal is None:
return 0
# Two consecutive up fractals = sell signal
if self._latest_fractal == self.FRACTAL_UP and self._previous_fractal == self.FRACTAL_UP:
return 2
# Two consecutive down fractals = buy signal
if self._latest_fractal == self.FRACTAL_DOWN and self._previous_fractal == self.FRACTAL_DOWN:
return 1
return 0
def _register_fractal(self, fractal_type):
self._previous_fractal = self._latest_fractal
self._latest_fractal = fractal_type
def _handle_open_position(self, candle):
if self.Position == 0:
return
if self.Position > 0:
self._update_trailing(candle, True)
if self._stop_price is not None and float(candle.LowPrice) <= self._stop_price:
self.SellMarket(abs(self.Position))
self._reset_trade_state()
return
if self._take_profit_price is not None and float(candle.HighPrice) >= self._take_profit_price:
self.SellMarket(abs(self.Position))
self._reset_trade_state()
return
profit = (float(candle.ClosePrice) - self._entry_price) * self.Position
price_gain = float(candle.ClosePrice) - self._entry_price
if self._min_profit_currency.Value > 0 and profit >= self._min_profit_currency.Value:
self.SellMarket(abs(self.Position))
self._reset_trade_state()
return
if self._min_profit_points.Value > 0 and price_gain >= self._min_profit_points.Value:
self.SellMarket(abs(self.Position))
self._reset_trade_state()
elif self.Position < 0:
self._update_trailing(candle, False)
if self._stop_price is not None and float(candle.HighPrice) >= self._stop_price:
self.BuyMarket(abs(self.Position))
self._reset_trade_state()
return
if self._take_profit_price is not None and float(candle.LowPrice) <= self._take_profit_price:
self.BuyMarket(abs(self.Position))
self._reset_trade_state()
return
profit = (self._entry_price - float(candle.ClosePrice)) * abs(self.Position)
price_gain = self._entry_price - float(candle.ClosePrice)
if self._min_profit_currency.Value > 0 and profit >= self._min_profit_currency.Value:
self.BuyMarket(abs(self.Position))
self._reset_trade_state()
return
if self._min_profit_points.Value > 0 and price_gain >= self._min_profit_points.Value:
self.BuyMarket(abs(self.Position))
self._reset_trade_state()
def _update_trailing(self, candle, is_long):
if self._trailing_stop_offset.Value <= 0:
return
if is_long:
profit_distance = float(candle.ClosePrice) - self._entry_price
if profit_distance > self._trailing_stop_offset.Value + self._trailing_step_offset.Value:
new_stop = float(candle.ClosePrice) - self._trailing_stop_offset.Value
if self._stop_price is None or new_stop > self._stop_price + self._trailing_step_offset.Value:
self._stop_price = new_stop
else:
profit_distance = self._entry_price - float(candle.ClosePrice)
if profit_distance > self._trailing_stop_offset.Value + self._trailing_step_offset.Value:
new_stop = float(candle.ClosePrice) + self._trailing_stop_offset.Value
if self._stop_price is None or new_stop < self._stop_price - self._trailing_step_offset.Value:
self._stop_price = new_stop
def _initialize_targets(self, entry_price, is_long):
self._entry_price = entry_price
if is_long:
self._stop_price = entry_price - self._stop_loss_offset.Value if self._stop_loss_offset.Value > 0 else None
self._take_profit_price = entry_price + self._take_profit_offset.Value if self._take_profit_offset.Value > 0 else None
else:
self._stop_price = entry_price + self._stop_loss_offset.Value if self._stop_loss_offset.Value > 0 else None
self._take_profit_price = entry_price - self._take_profit_offset.Value if self._take_profit_offset.Value > 0 else None
def _reset_trade_state(self):
self._stop_price = None
self._take_profit_price = None
self._entry_price = 0.0
def OnReseted(self):
super(clouds_trade2_strategy, self).OnReseted()
self._stochastic = None
self._prior_k = 0.0
self._prior_d = 0.0
self._last_k = 0.0
self._last_d = 0.0
self._has_prior_stoch = False
self._has_last_stoch = False
self._h1 = 0.0
self._h2 = 0.0
self._h3 = 0.0
self._h4 = 0.0
self._h5 = 0.0
self._l1 = 0.0
self._l2 = 0.0
self._l3 = 0.0
self._l4 = 0.0
self._l5 = 0.0
self._latest_fractal = None
self._previous_fractal = None
self._fractal_buffer_count = 0
self._stop_price = None
self._take_profit_price = None
self._entry_price = 0.0
self._last_entry_date = None
def CreateClone(self):
return clouds_trade2_strategy()