Стратегия Puncher
Обзор
- Конвертация советника MetaTrader 5 «The Puncher».
- Комбинирует стохастик с длинным периодом и RSI для поиска зон истощения.
- Работает только по закрытию свечи, следуя высокоуровневому API StockSharp.
- Управляет рисками с помощью стоп-лосса, тейк-профита, перевода в безубыток и трейлинг-стопа.
Индикаторы
- Стохастик: основной период
StochasticPeriod, сглаживание %K —StochasticSignalPeriod, сглаживание %D —StochasticSmoothingPeriod. - RSI: период
RsiPeriod.
Параметры
| Параметр | Значение по умолчанию | Описание |
|---|---|---|
StochasticPeriod |
100 | Базовый период стохастика. |
StochasticSignalPeriod |
3 | Сглаживание линии %K. |
StochasticSmoothingPeriod |
3 | Сглаживание линии %D. |
RsiPeriod |
14 | Длина расчёта RSI. |
OversoldLevel |
30 | Общий уровень перепроданности для стохастика и RSI. |
OverboughtLevel |
70 | Общий уровень перекупленности для стохастика и RSI. |
StopLossPips |
20 | Размер стоп-лосса в пунктах (0 — отключено). |
TakeProfitPips |
50 | Размер тейк-профита в пунктах (0 — отключено). |
TrailingStopPips |
10 | Дистанция трейлинг-стопа в пунктах (0 — отключено). |
TrailingStepPips |
5 | Минимальное улучшение цены для очередного подтягивания трейлинг-стопа. |
BreakEvenPips |
21 | Прибыль в пунктах для перевода стопа в безубыток (0 — отключено). |
CandleType |
Таймфрейм 5 минут | Тип свечей для расчётов. |
Volume |
Свойство стратегии | Объём заявок (настраивается через Volume). |
Пункты пересчитываются в абсолютные цены через
Security.PriceStep. Убедитесь, что шаг цены инструмента задан корректно.
Правила торговли
Вход
- Покупка: стохастик (сигнальная линия) и RSI ниже
OversoldLevel, открытых лонгов нет. - Продажа: стохастик и RSI выше
OverboughtLevel, открытых шортов нет. - При противоположном сигнале открытая позиция закрывается, после чего до следующей свечи новые входы не рассматриваются.
Выход и риск-менеджмент
- Стоп-лосс: фиксированное расстояние
StopLossPips. - Тейк-профит: фиксированная цель
TakeProfitPips. - Безубыток: при достижении прибыли
BreakEvenPipsстоп переносится на цену входа. - Трейлинг-стоп: активируется после движения на
TrailingStopPipsи подтягивается каждыеTrailingStepPips. - Противосигнал: закрывает позицию даже без достижения стопа или цели.
Примечания
- Подходит для любых инструментов StockSharp; параметры по умолчанию ориентированы на валютные пары.
- Работает только с закрытыми свечами, повторяя поведение
TradeAtCloseBar=trueоригинального робота. - Перед запуском укажите портфель, инструмент и объём сделок.
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>
/// Stochastic and RSI based strategy converted from "The Puncher".
/// Buys when both oscillators confirm oversold conditions and sells when they confirm overbought conditions.
/// Includes configurable stop-loss, take-profit, break-even and trailing stop logic.
/// </summary>
public class PuncherStrategy : Strategy
{
private readonly StrategyParam<int> _stochasticPeriod;
private readonly StrategyParam<int> _stochasticSignalPeriod;
private readonly StrategyParam<int> _stochasticSmoothingPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _oversoldLevel;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<int> _stopLossPips;
private readonly StrategyParam<int> _takeProfitPips;
private readonly StrategyParam<int> _trailingStopPips;
private readonly StrategyParam<int> _trailingStepPips;
private readonly StrategyParam<int> _breakEvenPips;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private decimal? _stopPrice;
private decimal? _takeProfitPrice;
private bool _breakEvenActivated;
private decimal? _lastTrailingPrice;
/// <summary>
/// Period of the Stochastic oscillator base calculation.
/// </summary>
public int StochasticPeriod
{
get => _stochasticPeriod.Value;
set => _stochasticPeriod.Value = value;
}
/// <summary>
/// Period used to smooth the %K line (signal).
/// </summary>
public int StochasticSignalPeriod
{
get => _stochasticSignalPeriod.Value;
set => _stochasticSignalPeriod.Value = value;
}
/// <summary>
/// Period used to smooth the %D line.
/// </summary>
public int StochasticSmoothingPeriod
{
get => _stochasticSmoothingPeriod.Value;
set => _stochasticSmoothingPeriod.Value = value;
}
/// <summary>
/// RSI calculation period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// Oversold threshold shared by Stochastic and RSI.
/// </summary>
public decimal OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
/// <summary>
/// Overbought threshold shared by Stochastic and RSI.
/// </summary>
public decimal OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
/// <summary>
/// Stop-loss distance expressed in pips (0 disables the stop-loss).
/// </summary>
public int StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Take-profit distance expressed in pips (0 disables the take-profit).
/// </summary>
public int TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Trailing stop distance in pips (0 disables the trailing stop).
/// </summary>
public int TrailingStopPips
{
get => _trailingStopPips.Value;
set => _trailingStopPips.Value = value;
}
/// <summary>
/// Minimum price improvement in pips before moving the trailing stop again.
/// </summary>
public int TrailingStepPips
{
get => _trailingStepPips.Value;
set => _trailingStepPips.Value = value;
}
/// <summary>
/// Profit in pips required to move the stop to break-even (0 disables the feature).
/// </summary>
public int BreakEvenPips
{
get => _breakEvenPips.Value;
set => _breakEvenPips.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public PuncherStrategy()
{
_stochasticPeriod = Param(nameof(StochasticPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("Stochastic Period", "Base period for the Stochastic oscillator", "Indicators")
.SetOptimize(50, 150, 10);
_stochasticSignalPeriod = Param(nameof(StochasticSignalPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("Stochastic Signal", "Smoothing period for the %K line", "Indicators")
.SetOptimize(1, 10, 1);
_stochasticSmoothingPeriod = Param(nameof(StochasticSmoothingPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("Stochastic Smoothing", "Smoothing period for the %D line", "Indicators")
.SetOptimize(1, 10, 1);
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation length", "Indicators")
.SetOptimize(7, 28, 1);
_oversoldLevel = Param(nameof(OversoldLevel), 20m)
.SetDisplay("Oversold Level", "Threshold for oversold detection", "Signals")
.SetOptimize(10m, 40m, 5m);
_overboughtLevel = Param(nameof(OverboughtLevel), 80m)
.SetDisplay("Overbought Level", "Threshold for overbought detection", "Signals")
.SetOptimize(60m, 90m, 5m);
_stopLossPips = Param(nameof(StopLossPips), 20)
.SetNotNegative()
.SetDisplay("Stop Loss (pips)", "Distance of the protective stop-loss", "Risk")
.SetOptimize(0, 60, 5);
_takeProfitPips = Param(nameof(TakeProfitPips), 50)
.SetNotNegative()
.SetDisplay("Take Profit (pips)", "Distance of the profit target", "Risk")
.SetOptimize(0, 120, 10);
_trailingStopPips = Param(nameof(TrailingStopPips), 10)
.SetNotNegative()
.SetDisplay("Trailing Stop (pips)", "Trailing stop distance", "Risk")
.SetOptimize(0, 40, 5);
_trailingStepPips = Param(nameof(TrailingStepPips), 5)
.SetNotNegative()
.SetDisplay("Trailing Step (pips)", "Minimum improvement before trailing stop updates", "Risk")
.SetOptimize(0, 20, 2);
_breakEvenPips = Param(nameof(BreakEvenPips), 21)
.SetNotNegative()
.SetDisplay("Break-Even (pips)", "Profit needed to move the stop to entry", "Risk")
.SetOptimize(0, 40, 2);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for processing", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0m;
_stopPrice = null;
_takeProfitPrice = null;
_breakEvenActivated = false;
_lastTrailingPrice = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsi)
{
if (candle.State != CandleStates.Finished)
return;
if (ManagePosition(candle))
return;
var isBuySignal = rsi < OversoldLevel;
var isSellSignal = rsi > OverboughtLevel;
if (Position > 0 && isSellSignal)
{
CloseLong();
return;
}
if (Position < 0 && isBuySignal)
{
CloseShort();
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (isBuySignal && Position <= 0)
{
EnterLong(candle);
return;
}
if (isSellSignal && Position >= 0)
{
EnterShort(candle);
}
}
private bool ManagePosition(ICandleMessage candle)
{
if (Position > 0)
{
return HandleLongPosition(candle);
}
if (Position < 0)
{
return HandleShortPosition(candle);
}
if (_stopPrice.HasValue || _takeProfitPrice.HasValue || _entryPrice != 0m)
{
ResetProtectionState();
}
return false;
}
private bool HandleLongPosition(ICandleMessage candle)
{
if (_entryPrice == 0m)
_entryPrice = candle.ClosePrice;
var priceStep = GetPriceStep();
if (BreakEvenPips > 0 && !_breakEvenActivated)
{
var breakEvenPrice = _entryPrice + GetPipValue(BreakEvenPips, priceStep);
if (candle.HighPrice >= breakEvenPrice)
{
if (_stopPrice is null || _stopPrice < _entryPrice)
{
_stopPrice = _entryPrice;
_breakEvenActivated = true;
}
}
}
if (TrailingStopPips > 0)
{
var trailingDistance = GetPipValue(TrailingStopPips, priceStep);
var trailingStep = TrailingStepPips > 0 ? GetPipValue(TrailingStepPips, priceStep) : 0m;
_lastTrailingPrice ??= _entryPrice;
if (candle.HighPrice >= _entryPrice + trailingDistance)
{
var referencePrice = _lastTrailingPrice.Value;
var shouldUpdate = referencePrice == _entryPrice || trailingStep == 0m || candle.HighPrice - referencePrice >= trailingStep;
if (shouldUpdate)
{
var newStop = candle.HighPrice - trailingDistance;
if (_stopPrice is null || newStop > _stopPrice)
_stopPrice = newStop;
_lastTrailingPrice = candle.HighPrice;
}
}
}
if (_takeProfitPrice is decimal tp && candle.HighPrice >= tp)
{
CloseLong();
return true;
}
if (_stopPrice is decimal sl && candle.LowPrice <= sl)
{
CloseLong();
return true;
}
return false;
}
private bool HandleShortPosition(ICandleMessage candle)
{
if (_entryPrice == 0m)
_entryPrice = candle.ClosePrice;
var priceStep = GetPriceStep();
if (BreakEvenPips > 0 && !_breakEvenActivated)
{
var breakEvenPrice = _entryPrice - GetPipValue(BreakEvenPips, priceStep);
if (candle.LowPrice <= breakEvenPrice)
{
if (_stopPrice is null || _stopPrice > _entryPrice)
{
_stopPrice = _entryPrice;
_breakEvenActivated = true;
}
}
}
if (TrailingStopPips > 0)
{
var trailingDistance = GetPipValue(TrailingStopPips, priceStep);
var trailingStep = TrailingStepPips > 0 ? GetPipValue(TrailingStepPips, priceStep) : 0m;
_lastTrailingPrice ??= _entryPrice;
if (candle.LowPrice <= _entryPrice - trailingDistance)
{
var referencePrice = _lastTrailingPrice.Value;
var shouldUpdate = referencePrice == _entryPrice || trailingStep == 0m || referencePrice - candle.LowPrice >= trailingStep;
if (shouldUpdate)
{
var newStop = candle.LowPrice + trailingDistance;
if (_stopPrice is null || newStop < _stopPrice)
_stopPrice = newStop;
_lastTrailingPrice = candle.LowPrice;
}
}
}
if (_takeProfitPrice is decimal tp && candle.LowPrice <= tp)
{
CloseShort();
return true;
}
if (_stopPrice is decimal sl && candle.HighPrice >= sl)
{
CloseShort();
return true;
}
return false;
}
private void EnterLong(ICandleMessage candle)
{
var volume = Volume + (Position < 0 ? -Position : 0m);
if (volume <= 0m)
return;
BuyMarket(volume);
_entryPrice = candle.ClosePrice;
InitializeProtection(isLong: true);
}
private void EnterShort(ICandleMessage candle)
{
var volume = Volume + (Position > 0 ? Position : 0m);
if (volume <= 0m)
return;
SellMarket(volume);
_entryPrice = candle.ClosePrice;
InitializeProtection(isLong: false);
}
private void CloseLong()
{
if (Position > 0)
SellMarket(Position);
ResetProtectionState();
}
private void CloseShort()
{
if (Position < 0)
BuyMarket(-Position);
ResetProtectionState();
}
private void InitializeProtection(bool isLong)
{
var priceStep = GetPriceStep();
var stopOffset = StopLossPips > 0 ? GetPipValue(StopLossPips, priceStep) : (decimal?)null;
var takeOffset = TakeProfitPips > 0 ? GetPipValue(TakeProfitPips, priceStep) : (decimal?)null;
_stopPrice = isLong
? (stopOffset.HasValue ? _entryPrice - stopOffset.Value : null)
: (stopOffset.HasValue ? _entryPrice + stopOffset.Value : null);
_takeProfitPrice = isLong
? (takeOffset.HasValue ? _entryPrice + takeOffset.Value : null)
: (takeOffset.HasValue ? _entryPrice - takeOffset.Value : null);
_breakEvenActivated = false;
_lastTrailingPrice = _entryPrice;
}
private void ResetProtectionState()
{
_entryPrice = 0m;
_stopPrice = null;
_takeProfitPrice = null;
_breakEvenActivated = false;
_lastTrailingPrice = null;
}
private static decimal GetPipValue(int pips, decimal priceStep)
{
return priceStep * pips;
}
private decimal GetPriceStep()
{
return Security?.PriceStep ?? 1m;
}
}
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
from StockSharp.Algo.Indicators import RelativeStrengthIndex
class puncher_strategy(Strategy):
def __init__(self):
super(puncher_strategy, self).__init__()
self._stochastic_period = self.Param("StochasticPeriod", 100) \
.SetGreaterThanZero() \
.SetDisplay("Stochastic Period", "Base period for the Stochastic oscillator", "Indicators")
self._stochastic_signal_period = self.Param("StochasticSignalPeriod", 3) \
.SetGreaterThanZero() \
.SetDisplay("Stochastic Signal", "Smoothing period for the K line", "Indicators")
self._stochastic_smoothing_period = self.Param("StochasticSmoothingPeriod", 3) \
.SetGreaterThanZero() \
.SetDisplay("Stochastic Smoothing", "Smoothing period for the D line", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("RSI Period", "RSI calculation length", "Indicators")
self._oversold_level = self.Param("OversoldLevel", 20.0) \
.SetDisplay("Oversold Level", "Threshold for oversold detection", "Signals")
self._overbought_level = self.Param("OverboughtLevel", 80.0) \
.SetDisplay("Overbought Level", "Threshold for overbought detection", "Signals")
self._stop_loss_pips = self.Param("StopLossPips", 20) \
.SetNotNegative() \
.SetDisplay("Stop Loss (pips)", "Distance of the protective stop-loss", "Risk")
self._take_profit_pips = self.Param("TakeProfitPips", 50) \
.SetNotNegative() \
.SetDisplay("Take Profit (pips)", "Distance of the profit target", "Risk")
self._trailing_stop_pips = self.Param("TrailingStopPips", 10) \
.SetNotNegative() \
.SetDisplay("Trailing Stop (pips)", "Trailing stop distance", "Risk")
self._trailing_step_pips = self.Param("TrailingStepPips", 5) \
.SetNotNegative() \
.SetDisplay("Trailing Step (pips)", "Minimum improvement before trailing stop updates", "Risk")
self._break_even_pips = self.Param("BreakEvenPips", 21) \
.SetNotNegative() \
.SetDisplay("Break-Even (pips)", "Profit needed to move the stop to entry", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles for processing", "General")
self._entry_price = 0.0
self._stop_price = None
self._take_profit_price = None
self._break_even_activated = False
self._last_trailing_price = None
@property
def StochasticPeriod(self):
return self._stochastic_period.Value
@property
def StochasticSignalPeriod(self):
return self._stochastic_signal_period.Value
@property
def StochasticSmoothingPeriod(self):
return self._stochastic_smoothing_period.Value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def OversoldLevel(self):
return self._oversold_level.Value
@property
def OverboughtLevel(self):
return self._overbought_level.Value
@property
def StopLossPips(self):
return self._stop_loss_pips.Value
@property
def TakeProfitPips(self):
return self._take_profit_pips.Value
@property
def TrailingStopPips(self):
return self._trailing_stop_pips.Value
@property
def TrailingStepPips(self):
return self._trailing_step_pips.Value
@property
def BreakEvenPips(self):
return self._break_even_pips.Value
@property
def CandleType(self):
return self._candle_type.Value
def _get_price_step(self):
sec = self.Security
if sec is not None and sec.PriceStep is not None and float(sec.PriceStep) > 0:
return float(sec.PriceStep)
return 1.0
def _get_pip_value(self, pips, price_step):
return price_step * pips
def OnStarted2(self, time):
super(puncher_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(rsi, self.process_candle) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def process_candle(self, candle, rsi_val):
if candle.State != CandleStates.Finished:
return
rsi = float(rsi_val)
if self._manage_position(candle):
return
is_buy = rsi < float(self.OversoldLevel)
is_sell = rsi > float(self.OverboughtLevel)
if self.Position > 0 and is_sell:
self._close_long()
return
if self.Position < 0 and is_buy:
self._close_short()
return
if is_buy and self.Position <= 0:
self._enter_long(candle)
return
if is_sell and self.Position >= 0:
self._enter_short(candle)
def _manage_position(self, candle):
if self.Position > 0:
return self._handle_long(candle)
if self.Position < 0:
return self._handle_short(candle)
if self._stop_price is not None or self._take_profit_price is not None or self._entry_price != 0.0:
self._reset_protection()
return False
def _handle_long(self, candle):
if self._entry_price == 0.0:
self._entry_price = float(candle.ClosePrice)
ps = self._get_price_step()
if self.BreakEvenPips > 0 and not self._break_even_activated:
be = self._entry_price + self._get_pip_value(self.BreakEvenPips, ps)
if float(candle.HighPrice) >= be:
if self._stop_price is None or self._stop_price < self._entry_price:
self._stop_price = self._entry_price
self._break_even_activated = True
if self.TrailingStopPips > 0:
td = self._get_pip_value(self.TrailingStopPips, ps)
ts = self._get_pip_value(self.TrailingStepPips, ps) if self.TrailingStepPips > 0 else 0.0
if self._last_trailing_price is None:
self._last_trailing_price = self._entry_price
high = float(candle.HighPrice)
if high >= self._entry_price + td:
ref = self._last_trailing_price
do_update = (ref == self._entry_price) or (ts == 0.0) or (high - ref >= ts)
if do_update:
ns = high - td
if self._stop_price is None or ns > self._stop_price:
self._stop_price = ns
self._last_trailing_price = high
if self._take_profit_price is not None and float(candle.HighPrice) >= self._take_profit_price:
self._close_long()
return True
if self._stop_price is not None and float(candle.LowPrice) <= self._stop_price:
self._close_long()
return True
return False
def _handle_short(self, candle):
if self._entry_price == 0.0:
self._entry_price = float(candle.ClosePrice)
ps = self._get_price_step()
if self.BreakEvenPips > 0 and not self._break_even_activated:
be = self._entry_price - self._get_pip_value(self.BreakEvenPips, ps)
if float(candle.LowPrice) <= be:
if self._stop_price is None or self._stop_price > self._entry_price:
self._stop_price = self._entry_price
self._break_even_activated = True
if self.TrailingStopPips > 0:
td = self._get_pip_value(self.TrailingStopPips, ps)
ts = self._get_pip_value(self.TrailingStepPips, ps) if self.TrailingStepPips > 0 else 0.0
if self._last_trailing_price is None:
self._last_trailing_price = self._entry_price
low = float(candle.LowPrice)
if low <= self._entry_price - td:
ref = self._last_trailing_price
do_update = (ref == self._entry_price) or (ts == 0.0) or (ref - low >= ts)
if do_update:
ns = low + td
if self._stop_price is None or ns < self._stop_price:
self._stop_price = ns
self._last_trailing_price = low
if self._take_profit_price is not None and float(candle.LowPrice) <= self._take_profit_price:
self._close_short()
return True
if self._stop_price is not None and float(candle.HighPrice) >= self._stop_price:
self._close_short()
return True
return False
def _enter_long(self, candle):
vol = self.Volume + (abs(self.Position) if self.Position < 0 else 0)
if vol <= 0:
return
self.BuyMarket(vol)
self._entry_price = float(candle.ClosePrice)
self._init_protection(True)
def _enter_short(self, candle):
vol = self.Volume + (self.Position if self.Position > 0 else 0)
if vol <= 0:
return
self.SellMarket(vol)
self._entry_price = float(candle.ClosePrice)
self._init_protection(False)
def _close_long(self):
if self.Position > 0:
self.SellMarket(self.Position)
self._reset_protection()
def _close_short(self):
if self.Position < 0:
self.BuyMarket(abs(self.Position))
self._reset_protection()
def _init_protection(self, is_long):
ps = self._get_price_step()
so = self._get_pip_value(self.StopLossPips, ps) if self.StopLossPips > 0 else None
to = self._get_pip_value(self.TakeProfitPips, ps) if self.TakeProfitPips > 0 else None
if is_long:
self._stop_price = (self._entry_price - so) if so is not None else None
self._take_profit_price = (self._entry_price + to) if to is not None else None
else:
self._stop_price = (self._entry_price + so) if so is not None else None
self._take_profit_price = (self._entry_price - to) if to is not None else None
self._break_even_activated = False
self._last_trailing_price = self._entry_price
def _reset_protection(self):
self._entry_price = 0.0
self._stop_price = None
self._take_profit_price = None
self._break_even_activated = False
self._last_trailing_price = None
def OnReseted(self):
super(puncher_strategy, self).OnReseted()
self._reset_protection()
def CreateClone(self):
return puncher_strategy()