Tages-Bruchpunkt-Strategie
Überblick
Die Tages-Bruchpunkt-Strategie ist eine StockSharp-Portierung des MetaTrader 5-Experten «Daily BreakPoint» (Build 19498). Der Algorithmus überwacht den Abstand zwischen dem aktuellen Preis und der täglichen Eröffnung. Wenn die Bewegung von der täglichen Eröffnung einen konfigurierbaren Schwellenwert überschreitet und die vorherige Kerze strenge Körpergrößenanforderungen erfüllt, tritt die Strategie in Richtung des Ausbruchs ein oder dreht die bestehende Exposition, abhängig vom CloseBySignal-Flag.
Die Strategie arbeitet gleichzeitig mit zwei Datenstreams:
- Intraday-Kerzen, definiert durch den
CandleType-Parameter, für die Signalgenerierung. - Tageskerzen, um den letzten Sitzungseröffnungspreis zu verfolgen.
Handelslogik
- Wenn eine neue Intraday-Kerze schließt, liest die Strategie den letzten täglichen Eröffnungspreis und berechnet die Ausbruchsniveaus mit
BreakPointPips(in absolute Preise über die Tick-Größe des Instruments umgerechnet). - Die Körpergröße der kürzlich geschlossenen Kerze muss innerhalb des Bereichs
[LastBarSizeMinPips, LastBarSizeMaxPips]liegen. - Bullisches Setup
- Die Kerze muss über ihrer Eröffnung schließen (
Close > Open). - Der Schlusskurs muss mindestens
BreakPointPipsüber der täglichen Eröffnung liegen. - Der Ausbruchspreis (tägliche Eröffnung + Bruchpunkt) muss innerhalb des Kerzenkörpers liegen.
- Wenn
CloseBySignal = false, öffnet die Strategie eine Long-Position. Andernfalls schließt sie jede offene Long-Exposition und eröffnet eine Short-Position.
- Die Kerze muss über ihrer Eröffnung schließen (
- Bärisches Setup spiegelt den bullischen Fall: eine bärische Kerze, deren Schlusskurs mindestens
BreakPointPipsunter der täglichen Eröffnung liegt und deren Körper das Ausbruchsniveau enthält, löst entweder einen Short-Einstieg (CloseBySignal = false) oder eine Umkehr in eine Long-Position (CloseBySignal = true) aus. - Orders werden als Marktorders mit dem konfigurierten
OrderVolumegesendet. Die Positionsgröße ist kumulativ, sodass mehrere Signale die Position in beide Richtungen skalieren können.
Risikomanagement
- Stop-Loss / Take-Profit: Optionale feste Ziele definiert in Pips (
StopLossPips,TakeProfitPips). Wenn auf null gesetzt, ist das entsprechende Level deaktiviert. Die Strategie wertet Kerzen-Hochs und -Tiefs aus, um Treffer zu erkennen. - Trailing-Stop: Aktiviert wenn
TrailingStopPips > 0. Sobald der offene GewinnTrailingStopPips + TrailingStepPipsüberschreitet, wird der Stop umTrailingStopPipshinter dem Preis her gezogen. Der Schritt-Parameter verhindert häufige Stop-Anpassungen in flachen Märkten. - Alle Preisabstände werden aus Pips über den
PriceStepdes Instruments umgerechnet. Bei 3- oder 5-Dezimalstellen-Kursstellung entspricht ein Pip zehn Preisschritten, was das ursprüngliche Experten-Verhalten repliziert.
Parameter
| Name | Beschreibung |
|---|---|
OrderVolume |
Basisvolumen für jede Marktorder. |
CloseBySignal |
Wenn true, schließt die Strategie bestehende Positionen und öffnet die entgegengesetzte Richtung, wenn ein Ausbruchssignal erscheint. |
BreakPointPips |
Abstand von der täglichen Eröffnung erforderlich, um einen Ausbruch zu bestätigen. |
LastBarSizeMinPips / LastBarSizeMaxPips |
Minimale und maximale Körpergröße der Auslösekerze. |
TrailingStopPips |
Trailing-Stop-Abstand. Auf 0 setzen zum Deaktivieren. |
TrailingStepPips |
Zusätzliche Bewegung vor jeder Trailing-Anpassung erforderlich. |
StopLossPips |
Optionaler fester Stop-Loss. 0 deaktiviert ihn. |
TakeProfitPips |
Optionaler fester Take-Profit. 0 deaktiviert ihn. |
CandleType |
Intraday-Kerzenserie für die Signalgenerierung. |
Verwendungshinweise
- Die Strategie abonniert automatisch sowohl Intraday- als auch Tageskerzen. Stellen Sie sicher, dass der Datenanbieter die angeforderten Zeitrahmen unterstützt.
- Da die Logik fertige Kerzen auswertet, werden Orders beim Schlusskurs der Signalbar gesendet.
- Die Pip-Konvertierung setzt Forex-Kursstellung voraus. Überprüfen Sie die Standardwerte bei Anwendung der Strategie auf Instrumente mit unkonventionellen Tick-Größen.
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>
/// Daily breakout strategy that reacts to the distance from the daily open.
/// Converted from the MetaTrader Daily BreakPoint expert advisor.
/// </summary>
public class DailyBreakPointStrategy : Strategy
{
private readonly StrategyParam<decimal> _orderVolume;
private readonly StrategyParam<bool> _closeBySignal;
private readonly StrategyParam<decimal> _breakPointPips;
private readonly StrategyParam<decimal> _lastBarSizeMinPips;
private readonly StrategyParam<decimal> _lastBarSizeMaxPips;
private readonly StrategyParam<decimal> _trailingStopPips;
private readonly StrategyParam<decimal> _trailingStepPips;
private readonly StrategyParam<decimal> _stopLossPips;
private readonly StrategyParam<decimal> _takeProfitPips;
private readonly StrategyParam<DataType> _candleType;
private decimal? _currentDayOpen;
private decimal? _longStopPrice;
private decimal? _longTakePrice;
private decimal? _shortStopPrice;
private decimal? _shortTakePrice;
private decimal? _longEntryPrice;
private decimal? _shortEntryPrice;
private decimal _pipSize;
/// <summary>
/// Order volume.
/// </summary>
public decimal OrderVolume
{
get => _orderVolume.Value;
set => _orderVolume.Value = value;
}
/// <summary>
/// Reverse the position when the opposite signal appears.
/// </summary>
public bool CloseBySignal
{
get => _closeBySignal.Value;
set => _closeBySignal.Value = value;
}
/// <summary>
/// Break distance from the daily open expressed in pips.
/// </summary>
public decimal BreakPointPips
{
get => _breakPointPips.Value;
set => _breakPointPips.Value = value;
}
/// <summary>
/// Minimum size of the previous bar body in pips.
/// </summary>
public decimal LastBarSizeMinPips
{
get => _lastBarSizeMinPips.Value;
set => _lastBarSizeMinPips.Value = value;
}
/// <summary>
/// Maximum size of the previous bar body in pips.
/// </summary>
public decimal LastBarSizeMaxPips
{
get => _lastBarSizeMaxPips.Value;
set => _lastBarSizeMaxPips.Value = value;
}
/// <summary>
/// Trailing stop distance in pips.
/// </summary>
public decimal TrailingStopPips
{
get => _trailingStopPips.Value;
set => _trailingStopPips.Value = value;
}
/// <summary>
/// Trailing stop step in pips.
/// </summary>
public decimal TrailingStepPips
{
get => _trailingStepPips.Value;
set => _trailingStepPips.Value = value;
}
/// <summary>
/// Fixed stop loss in pips.
/// </summary>
public decimal StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Fixed take profit in pips.
/// </summary>
public decimal TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Intraday candle type used for signal calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="DailyBreakPointStrategy"/> class.
/// </summary>
public DailyBreakPointStrategy()
{
_orderVolume = Param(nameof(OrderVolume), 1m)
.SetGreaterThanZero()
.SetDisplay("Volume", "Default order volume", "General");
_closeBySignal = Param(nameof(CloseBySignal), true)
.SetDisplay("Close By Signal", "Reverse existing position on opposite signal", "General");
_breakPointPips = Param(nameof(BreakPointPips), 5m)
.SetGreaterThanZero()
.SetDisplay("Break Point (pips)", "Distance from the daily open", "Signals");
_lastBarSizeMinPips = Param(nameof(LastBarSizeMinPips), 1m)
.SetGreaterThanZero()
.SetDisplay("Last Bar Min (pips)", "Minimum body size of the previous bar", "Signals");
_lastBarSizeMaxPips = Param(nameof(LastBarSizeMaxPips), 5000m)
.SetGreaterThanZero()
.SetDisplay("Last Bar Max (pips)", "Maximum body size of the previous bar", "Signals");
_trailingStopPips = Param(nameof(TrailingStopPips), 2m)
.SetDisplay("Trailing Stop (pips)", "Trailing stop distance", "Risk");
_trailingStepPips = Param(nameof(TrailingStepPips), 2m)
.SetDisplay("Trailing Step (pips)", "Minimum move before trailing", "Risk");
_stopLossPips = Param(nameof(StopLossPips), 0m)
.SetDisplay("Stop Loss (pips)", "Fixed stop loss distance", "Risk");
_takeProfitPips = Param(nameof(TakeProfitPips), 30m)
.SetDisplay("Take Profit (pips)", "Fixed take profit distance", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Intraday candle series", "Data");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType), (Security, TimeSpan.FromMinutes(5).TimeFrame())];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_currentDayOpen = null;
_longStopPrice = null;
_longTakePrice = null;
_shortStopPrice = null;
_shortTakePrice = null;
_longEntryPrice = null;
_shortEntryPrice = null;
_pipSize = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
Volume = OrderVolume;
_pipSize = CalculatePipSize();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent)
);
var intradaySubscription = SubscribeCandles(CandleType);
intradaySubscription.Bind(ProcessCandle).Start();
var dailySubscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
dailySubscription.Bind(ProcessDailyCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, intradaySubscription);
DrawOwnTrades(area);
}
}
private decimal CalculatePipSize()
{
var step = Security?.PriceStep ?? 0.0001m;
if (step <= 0m)
step = 0.0001m;
var decimals = Security?.Decimals;
if (decimals == 3 || decimals == 5)
return step * 10m;
return step;
}
private decimal NormalizePrice(decimal price)
{
var step = Security?.PriceStep;
if (step is null || step.Value <= 0m)
return price;
var value = price / step.Value;
var rounded = Math.Round(value, 0, MidpointRounding.AwayFromZero);
return rounded * step.Value;
}
private void ProcessDailyCandle(ICandleMessage candle)
{
if (candle.State == CandleStates.Finished || candle.State == CandleStates.Active)
_currentDayOpen = candle.OpenPrice;
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
Volume = OrderVolume;
if (_pipSize <= 0m)
_pipSize = CalculatePipSize();
var dayOpen = _currentDayOpen;
if (dayOpen is null)
return;
var breakOffset = BreakPointPips * _pipSize;
var minBody = LastBarSizeMinPips * _pipSize;
var maxBody = LastBarSizeMaxPips * _pipSize;
var trailingStop = TrailingStopPips * _pipSize;
var trailingStep = TrailingStepPips * _pipSize;
var stopLossOffset = StopLossPips > 0m ? StopLossPips * _pipSize : 0m;
var takeProfitOffset = TakeProfitPips > 0m ? TakeProfitPips * _pipSize : 0m;
UpdateTrailing(candle, trailingStop, trailingStep);
HandleRiskExits(candle);
var bodySize = Math.Abs(candle.ClosePrice - candle.OpenPrice);
var minPrice = Math.Min(candle.OpenPrice, candle.ClosePrice);
var maxPrice = Math.Max(candle.OpenPrice, candle.ClosePrice);
var breakBuy = dayOpen.Value + breakOffset;
var breakSell = dayOpen.Value - breakOffset;
var bullishBody = candle.ClosePrice > candle.OpenPrice;
var bearishBody = candle.ClosePrice < candle.OpenPrice;
var bullishSignal = bullishBody && breakOffset > 0m &&
candle.ClosePrice - dayOpen.Value >= breakOffset &&
bodySize >= minBody &&
(maxBody <= 0m || bodySize <= maxBody);
var bearishSignal = bearishBody && breakOffset > 0m &&
dayOpen.Value - candle.ClosePrice >= breakOffset &&
bodySize >= minBody &&
(maxBody <= 0m || bodySize <= maxBody);
if (bullishSignal)
{
ExecuteBullishSignal(candle.ClosePrice, stopLossOffset, takeProfitOffset);
}
else if (bearishSignal)
{
ExecuteBearishSignal(candle.ClosePrice, stopLossOffset, takeProfitOffset);
}
}
private void UpdateTrailing(ICandleMessage candle, decimal trailingStop, decimal trailingStep)
{
if (trailingStop <= 0m)
return;
if (Position > 0 && _longEntryPrice.HasValue)
{
var profit = candle.ClosePrice - _longEntryPrice.Value;
if (profit > trailingStop + trailingStep)
{
var threshold = candle.ClosePrice - (trailingStop + trailingStep);
if (!_longStopPrice.HasValue || _longStopPrice.Value < threshold)
_longStopPrice = NormalizePrice(candle.ClosePrice - trailingStop);
}
}
else if (Position < 0 && _shortEntryPrice.HasValue)
{
var profit = _shortEntryPrice.Value - candle.ClosePrice;
if (profit > trailingStop + trailingStep)
{
var threshold = candle.ClosePrice + (trailingStop + trailingStep);
if (!_shortStopPrice.HasValue || _shortStopPrice.Value > threshold || _shortStopPrice.Value == 0m)
_shortStopPrice = NormalizePrice(candle.ClosePrice + trailingStop);
}
}
}
private void HandleRiskExits(ICandleMessage candle)
{
if (Position > 0)
{
var volume = Math.Abs(Position);
if (volume > 0m && _longStopPrice.HasValue && candle.LowPrice <= _longStopPrice.Value)
{
SellMarket();
ResetLongState();
return;
}
if (volume > 0m && _longTakePrice.HasValue && candle.HighPrice >= _longTakePrice.Value)
{
SellMarket();
ResetLongState();
}
}
else if (Position < 0)
{
var volume = Math.Abs(Position);
if (volume > 0m && _shortStopPrice.HasValue && candle.HighPrice >= _shortStopPrice.Value)
{
BuyMarket();
ResetShortState();
return;
}
if (volume > 0m && _shortTakePrice.HasValue && candle.LowPrice <= _shortTakePrice.Value)
{
BuyMarket();
ResetShortState();
}
}
else
{
ResetLongState();
ResetShortState();
}
}
private void ExecuteBullishSignal(decimal entryPrice, decimal stopLossOffset, decimal takeProfitOffset)
{
if (CloseBySignal)
{
if (Position > 0)
{
var volume = Math.Abs(Position);
SellMarket();
}
ResetLongState();
SellMarket();
_shortEntryPrice = entryPrice;
_shortStopPrice = stopLossOffset > 0m ? NormalizePrice(entryPrice + stopLossOffset) : null;
_shortTakePrice = takeProfitOffset > 0m ? NormalizePrice(entryPrice - takeProfitOffset) : null;
}
else
{
BuyMarket();
_longEntryPrice = entryPrice;
_longStopPrice = stopLossOffset > 0m ? NormalizePrice(entryPrice - stopLossOffset) : null;
_longTakePrice = takeProfitOffset > 0m ? NormalizePrice(entryPrice + takeProfitOffset) : null;
ResetShortState();
}
}
private void ExecuteBearishSignal(decimal entryPrice, decimal stopLossOffset, decimal takeProfitOffset)
{
if (CloseBySignal)
{
if (Position < 0)
{
var volume = Math.Abs(Position);
BuyMarket();
}
ResetShortState();
BuyMarket();
_longEntryPrice = entryPrice;
_longStopPrice = stopLossOffset > 0m ? NormalizePrice(entryPrice - stopLossOffset) : null;
_longTakePrice = takeProfitOffset > 0m ? NormalizePrice(entryPrice + takeProfitOffset) : null;
}
else
{
SellMarket();
_shortEntryPrice = entryPrice;
_shortStopPrice = stopLossOffset > 0m ? NormalizePrice(entryPrice + stopLossOffset) : null;
_shortTakePrice = takeProfitOffset > 0m ? NormalizePrice(entryPrice - takeProfitOffset) : null;
ResetLongState();
}
}
private void ResetLongState()
{
_longEntryPrice = null;
_longStopPrice = null;
_longTakePrice = null;
}
private void ResetShortState()
{
_shortEntryPrice = null;
_shortStopPrice = null;
_shortTakePrice = null;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class daily_break_point_strategy(Strategy):
"""Daily BreakPoint: daily open breakout with body size filter and trailing stop."""
def __init__(self):
super(daily_break_point_strategy, self).__init__()
self._order_volume = self.Param("OrderVolume", 1.0) \
.SetGreaterThanZero() \
.SetDisplay("Volume", "Default order volume", "General")
self._close_by_signal = self.Param("CloseBySignal", True) \
.SetDisplay("Close By Signal", "Reverse existing position on opposite signal", "General")
self._break_point_pips = self.Param("BreakPointPips", 5.0) \
.SetGreaterThanZero() \
.SetDisplay("Break Point (pips)", "Distance from the daily open", "Signals")
self._last_bar_size_min_pips = self.Param("LastBarSizeMinPips", 1.0) \
.SetGreaterThanZero() \
.SetDisplay("Last Bar Min (pips)", "Minimum body size of the previous bar", "Signals")
self._last_bar_size_max_pips = self.Param("LastBarSizeMaxPips", 5000.0) \
.SetGreaterThanZero() \
.SetDisplay("Last Bar Max (pips)", "Maximum body size of the previous bar", "Signals")
self._trailing_stop_pips = self.Param("TrailingStopPips", 2.0) \
.SetDisplay("Trailing Stop (pips)", "Trailing stop distance", "Risk")
self._trailing_step_pips = self.Param("TrailingStepPips", 2.0) \
.SetDisplay("Trailing Step (pips)", "Minimum move before trailing", "Risk")
self._stop_loss_pips = self.Param("StopLossPips", 0.0) \
.SetDisplay("Stop Loss (pips)", "Fixed stop loss distance", "Risk")
self._take_profit_pips = self.Param("TakeProfitPips", 30.0) \
.SetDisplay("Take Profit (pips)", "Fixed take profit distance", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Intraday candle series", "Data")
self._current_day_open = None
self._long_stop_price = None
self._long_take_price = None
self._short_stop_price = None
self._short_take_price = None
self._long_entry_price = None
self._short_entry_price = None
self._pip_size = 0.0
@property
def OrderVolume(self):
return float(self._order_volume.Value)
@property
def CloseBySignal(self):
return self._close_by_signal.Value
@property
def BreakPointPips(self):
return float(self._break_point_pips.Value)
@property
def LastBarSizeMinPips(self):
return float(self._last_bar_size_min_pips.Value)
@property
def LastBarSizeMaxPips(self):
return float(self._last_bar_size_max_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 StopLossPips(self):
return float(self._stop_loss_pips.Value)
@property
def TakeProfitPips(self):
return float(self._take_profit_pips.Value)
@property
def CandleType(self):
return self._candle_type.Value
def _calc_pip_size(self):
sec = self.Security
if sec is None or sec.PriceStep is None:
return 0.0001
step = float(sec.PriceStep)
if step <= 0:
return 0.0001
decimals = None
if sec.Decimals is not None:
decimals = int(sec.Decimals)
if decimals == 3 or decimals == 5:
return step * 10.0
return step
def _normalize_price(self, price):
sec = self.Security
if sec is None or sec.PriceStep is None:
return price
step = float(sec.PriceStep)
if step <= 0:
return price
return round(price / step) * step
def OnStarted2(self, time):
super(daily_break_point_strategy, self).OnStarted2(time)
self._current_day_open = None
self._long_stop_price = None
self._long_take_price = None
self._short_stop_price = None
self._short_take_price = None
self._long_entry_price = None
self._short_entry_price = None
self._pip_size = self._calc_pip_size()
self.StartProtection(
takeProfit=Unit(2, UnitTypes.Percent),
stopLoss=Unit(1, UnitTypes.Percent)
)
intraday_subscription = self.SubscribeCandles(self.CandleType)
intraday_subscription.Bind(self.process_candle).Start()
daily_subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
daily_subscription.Bind(self.process_daily_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, intraday_subscription)
self.DrawOwnTrades(area)
def process_daily_candle(self, candle):
if candle.State == CandleStates.Finished or candle.State == CandleStates.Active:
self._current_day_open = float(candle.OpenPrice)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
if self._pip_size <= 0:
self._pip_size = self._calc_pip_size()
day_open = self._current_day_open
if day_open is None:
return
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
h = float(candle.HighPrice)
lo = float(candle.LowPrice)
break_offset = self.BreakPointPips * self._pip_size
min_body = self.LastBarSizeMinPips * self._pip_size
max_body = self.LastBarSizeMaxPips * self._pip_size
trailing_stop = self.TrailingStopPips * self._pip_size
trailing_step = self.TrailingStepPips * self._pip_size
stop_loss_offset = self.StopLossPips * self._pip_size if self.StopLossPips > 0 else 0.0
take_profit_offset = self.TakeProfitPips * self._pip_size if self.TakeProfitPips > 0 else 0.0
self._update_trailing(candle, trailing_stop, trailing_step)
if self._handle_risk_exits(candle):
return
body_size = abs(close - open_p)
bullish_body = close > open_p
bearish_body = close < open_p
bullish_signal = (bullish_body and break_offset > 0 and
close - day_open >= break_offset and
body_size >= min_body and
(max_body <= 0 or body_size <= max_body))
bearish_signal = (bearish_body and break_offset > 0 and
day_open - close >= break_offset and
body_size >= min_body and
(max_body <= 0 or body_size <= max_body))
if bullish_signal:
self._execute_bullish_signal(close, stop_loss_offset, take_profit_offset)
elif bearish_signal:
self._execute_bearish_signal(close, stop_loss_offset, take_profit_offset)
def _update_trailing(self, candle, trailing_stop, trailing_step):
if trailing_stop <= 0:
return
close = float(candle.ClosePrice)
if self.Position > 0 and self._long_entry_price is not None:
profit = close - self._long_entry_price
if profit > trailing_stop + trailing_step:
threshold = close - (trailing_stop + trailing_step)
if self._long_stop_price is None or self._long_stop_price < threshold:
self._long_stop_price = self._normalize_price(close - trailing_stop)
elif self.Position < 0 and self._short_entry_price is not None:
profit = self._short_entry_price - close
if profit > trailing_stop + trailing_step:
threshold = close + trailing_stop + trailing_step
if (self._short_stop_price is None or
self._short_stop_price > threshold or self._short_stop_price == 0):
self._short_stop_price = self._normalize_price(close + trailing_stop)
def _handle_risk_exits(self, candle):
h = float(candle.HighPrice)
lo = float(candle.LowPrice)
if self.Position > 0:
if self._long_stop_price is not None and lo <= self._long_stop_price:
self.SellMarket()
self._reset_long_state()
return True
if self._long_take_price is not None and h >= self._long_take_price:
self.SellMarket()
self._reset_long_state()
return True
elif self.Position < 0:
if self._short_stop_price is not None and h >= self._short_stop_price:
self.BuyMarket()
self._reset_short_state()
return True
if self._short_take_price is not None and lo <= self._short_take_price:
self.BuyMarket()
self._reset_short_state()
return True
else:
self._reset_long_state()
self._reset_short_state()
return False
def _execute_bullish_signal(self, entry_price, stop_loss_offset, take_profit_offset):
if self.CloseBySignal:
if self.Position > 0:
self.SellMarket()
self._reset_long_state()
self.SellMarket()
self._short_entry_price = entry_price
self._short_stop_price = self._normalize_price(entry_price + stop_loss_offset) if stop_loss_offset > 0 else None
self._short_take_price = self._normalize_price(entry_price - take_profit_offset) if take_profit_offset > 0 else None
else:
self.BuyMarket()
self._long_entry_price = entry_price
self._long_stop_price = self._normalize_price(entry_price - stop_loss_offset) if stop_loss_offset > 0 else None
self._long_take_price = self._normalize_price(entry_price + take_profit_offset) if take_profit_offset > 0 else None
self._reset_short_state()
def _execute_bearish_signal(self, entry_price, stop_loss_offset, take_profit_offset):
if self.CloseBySignal:
if self.Position < 0:
self.BuyMarket()
self._reset_short_state()
self.BuyMarket()
self._long_entry_price = entry_price
self._long_stop_price = self._normalize_price(entry_price - stop_loss_offset) if stop_loss_offset > 0 else None
self._long_take_price = self._normalize_price(entry_price + take_profit_offset) if take_profit_offset > 0 else None
else:
self.SellMarket()
self._short_entry_price = entry_price
self._short_stop_price = self._normalize_price(entry_price + stop_loss_offset) if stop_loss_offset > 0 else None
self._short_take_price = self._normalize_price(entry_price - take_profit_offset) if take_profit_offset > 0 else None
self._reset_long_state()
def _reset_long_state(self):
self._long_entry_price = None
self._long_stop_price = None
self._long_take_price = None
def _reset_short_state(self):
self._short_entry_price = None
self._short_stop_price = None
self._short_take_price = None
def OnReseted(self):
super(daily_break_point_strategy, self).OnReseted()
self._current_day_open = None
self._long_stop_price = None
self._long_take_price = None
self._short_stop_price = None
self._short_take_price = None
self._long_entry_price = None
self._short_entry_price = None
self._pip_size = 0.0
def CreateClone(self):
return daily_break_point_strategy()