Стратегия VR ZVER
Общее описание
VR ZVER — это трендовая стратегия, в которой задействованы три уровня фильтрации: связка экспоненциальных средних (быстрая, медленная и очень медленная), осциллятор Stochastic и индикатор RSI. Сделка открывается только тогда, когда все активированные фильтры подтверждают одно и то же направление. Такой подход позволяет избегать сделок в период рыночного шума и противоречивых сигналов. При переносе на StockSharp сохранены исходные правила перевода позиции в безубыток и защитного выхода.
Определение рыночного режима
- Структура EMA — по умолчанию используются EMA с периодами 3, 5 и 7. Для лонга требуется, чтобы быстрая EMA находилась выше медленной, а медленная выше самой медленной. Для шорта условия зеркальные.
- Стохастик — анализируются и относительное положение линий %K/%D, и их нахождение относительно уровней. Для покупок %K должна быть ниже нижнего порога и выше %D, что указывает на выход из перепроданности. Для продаж %K должна находиться выше верхнего порога и ниже %D.
- RSI — индикатор должен быть ниже нижнего уровня для покупок или выше верхнего уровня для продаж.
Только при согласованности всех фильтров стратегия отправляет рыночный ордер с заданным объёмом.
Управление рисками
- Стоп-лосс — рассчитывается на основе параметра
StopLossPipsи размера пункта инструмента. Лонг закрывается, если минимум свечи пробивает стоп, шорт — если максимум свечи пересекает стоповый уровень. - Тейк-профит — выставляется симметрично. При достижении целевой цены в пределах текущей свечи позиция фиксируется.
- Перевод в безубыток — после прохождения расстояния
BreakevenPipsстратегия включает режим защиты: возврат цены к точке входа закрывает сделку в ноль. - Очистка заявок — перед открытием нового входа отменяются все активные ордера.
Параметры
| Параметр | Описание |
|---|---|
CandleType |
Тип свечей, используемых в расчётах. |
UseMovingAverage |
Включение/выключение фильтра на основе EMA. |
FastMaPeriod, SlowMaPeriod, VerySlowMaPeriod |
Периоды для быстрой, медленной и очень медленной EMA. |
UseStochastic |
Включение фильтра на основе стохастика. |
StochasticKPeriod, StochasticDPeriod, StochasticSlowing |
Настройки периодов стохастика. |
StochasticUpperLevel, StochasticLowerLevel |
Границы перекупленности/перепроданности для %K. |
UseRsi |
Включение фильтра RSI. |
RsiPeriod |
Период сглаживания RSI. |
RsiUpperLevel, RsiLowerLevel |
Уровни перекупленности и перепроданности для RSI. |
StopLossPips, TakeProfitPips |
Расстояние до стоп-лосса и тейк-профита в пунктах. |
BreakevenPips |
Дистанция до активации режима безубытка. |
Volume |
Объём сделки при отправке рыночного ордера. |
Особенности реализации
- Размер пункта автоматически рассчитывается исходя из шага цены и количества знаков после запятой. Для инструментов с 3 или 5 знаками применяется стандартный коэффициент ×10, как и в оригинальном MQL-советнике.
- Индикаторы подключаются через
BindEx, поэтому логика срабатывает только на полностью сформированных свечах. - Стратегия всегда выравнивает текущую позицию перед сменой направления, что исключает наложение противоположных сделок.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Multi-indicator strategy that combines EMA, Stochastic, and RSI confirmations.
/// </summary>
public class VrZverStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<bool> _useMovingAverage;
private readonly StrategyParam<int> _fastMaPeriod;
private readonly StrategyParam<int> _slowMaPeriod;
private readonly StrategyParam<int> _verySlowMaPeriod;
private readonly StrategyParam<bool> _useStochastic;
private readonly StrategyParam<int> _stochasticKPeriod;
private readonly StrategyParam<int> _stochasticDPeriod;
private readonly StrategyParam<int> _stochasticSlowing;
private readonly StrategyParam<int> _stochasticUpperLevel;
private readonly StrategyParam<int> _stochasticLowerLevel;
private readonly StrategyParam<bool> _useRsi;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _rsiUpperLevel;
private readonly StrategyParam<int> _rsiLowerLevel;
private readonly StrategyParam<int> _stopLossPips;
private readonly StrategyParam<int> _takeProfitPips;
private readonly StrategyParam<int> _breakevenPips;
private ExponentialMovingAverage _fastMa = null!;
private ExponentialMovingAverage _slowMa = null!;
private ExponentialMovingAverage _verySlowMa = null!;
private StochasticOscillator _stochastic = null!;
private RelativeStrengthIndex _rsi = null!;
private decimal _pipSize;
private decimal? _longEntryPrice;
private decimal? _shortEntryPrice;
private decimal? _longStopPrice;
private decimal? _shortStopPrice;
private decimal? _longTakePrice;
private decimal? _shortTakePrice;
private decimal? _longBreakevenTrigger;
private decimal? _shortBreakevenTrigger;
private bool _longBreakevenArmed;
private bool _shortBreakevenArmed;
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Enable moving average confirmation.
/// </summary>
public bool UseMovingAverage
{
get => _useMovingAverage.Value;
set => _useMovingAverage.Value = value;
}
/// <summary>
/// Fast EMA period.
/// </summary>
public int FastMaPeriod
{
get => _fastMaPeriod.Value;
set => _fastMaPeriod.Value = value;
}
/// <summary>
/// Slow EMA period.
/// </summary>
public int SlowMaPeriod
{
get => _slowMaPeriod.Value;
set => _slowMaPeriod.Value = value;
}
/// <summary>
/// Very slow EMA period.
/// </summary>
public int VerySlowMaPeriod
{
get => _verySlowMaPeriod.Value;
set => _verySlowMaPeriod.Value = value;
}
/// <summary>
/// Enable Stochastic confirmation.
/// </summary>
public bool UseStochastic
{
get => _useStochastic.Value;
set => _useStochastic.Value = value;
}
/// <summary>
/// Stochastic oscillator %K period.
/// </summary>
public int StochasticKPeriod
{
get => _stochasticKPeriod.Value;
set => _stochasticKPeriod.Value = value;
}
/// <summary>
/// Stochastic %D smoothing period.
/// </summary>
public int StochasticDPeriod
{
get => _stochasticDPeriod.Value;
set => _stochasticDPeriod.Value = value;
}
/// <summary>
/// Stochastic %K smoothing period.
/// </summary>
public int StochasticSlowing
{
get => _stochasticSlowing.Value;
set => _stochasticSlowing.Value = value;
}
/// <summary>
/// Upper threshold for Stochastic %K.
/// </summary>
public int StochasticUpperLevel
{
get => _stochasticUpperLevel.Value;
set => _stochasticUpperLevel.Value = value;
}
/// <summary>
/// Lower threshold for Stochastic %K.
/// </summary>
public int StochasticLowerLevel
{
get => _stochasticLowerLevel.Value;
set => _stochasticLowerLevel.Value = value;
}
/// <summary>
/// Enable RSI confirmation.
/// </summary>
public bool UseRsi
{
get => _useRsi.Value;
set => _useRsi.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI upper threshold.
/// </summary>
public int RsiUpperLevel
{
get => _rsiUpperLevel.Value;
set => _rsiUpperLevel.Value = value;
}
/// <summary>
/// RSI lower threshold.
/// </summary>
public int RsiLowerLevel
{
get => _rsiLowerLevel.Value;
set => _rsiLowerLevel.Value = value;
}
/// <summary>
/// Stop loss distance in pips.
/// </summary>
public int StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Take profit distance in pips.
/// </summary>
public int TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Breakeven activation distance in pips.
/// </summary>
public int BreakevenPips
{
get => _breakevenPips.Value;
set => _breakevenPips.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="VrZverStrategy"/>.
/// </summary>
public VrZverStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_useMovingAverage = Param(nameof(UseMovingAverage), true)
.SetDisplay("Use EMA", "Enable EMA trend filter", "Signals");
_fastMaPeriod = Param(nameof(FastMaPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "Signals");
_slowMaPeriod = Param(nameof(SlowMaPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period", "Signals");
_verySlowMaPeriod = Param(nameof(VerySlowMaPeriod), 7)
.SetGreaterThanZero()
.SetDisplay("Very Slow EMA", "Very slow EMA period", "Signals");
_useStochastic = Param(nameof(UseStochastic), true)
.SetDisplay("Use Stochastic", "Enable stochastic confirmation", "Signals");
_stochasticKPeriod = Param(nameof(StochasticKPeriod), 42)
.SetGreaterThanZero()
.SetDisplay("Stoch %K", "Stochastic %K period", "Signals");
_stochasticDPeriod = Param(nameof(StochasticDPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Stoch %D", "Stochastic %D period", "Signals");
_stochasticSlowing = Param(nameof(StochasticSlowing), 7)
.SetGreaterThanZero()
.SetDisplay("Stoch Smoothing", "Stochastic %K smoothing", "Signals");
_stochasticUpperLevel = Param(nameof(StochasticUpperLevel), 55)
.SetDisplay("Stoch Upper", "Upper stochastic threshold", "Signals");
_stochasticLowerLevel = Param(nameof(StochasticLowerLevel), 50)
.SetDisplay("Stoch Lower", "Lower stochastic threshold", "Signals");
_useRsi = Param(nameof(UseRsi), true)
.SetDisplay("Use RSI", "Enable RSI confirmation", "Signals");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI averaging period", "Signals");
_rsiUpperLevel = Param(nameof(RsiUpperLevel), 55)
.SetDisplay("RSI Upper", "Upper RSI threshold", "Signals");
_rsiLowerLevel = Param(nameof(RsiLowerLevel), 50)
.SetDisplay("RSI Lower", "Lower RSI threshold", "Signals");
_stopLossPips = Param(nameof(StopLossPips), 50)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop loss distance in pips", "Risk");
_takeProfitPips = Param(nameof(TakeProfitPips), 70)
.SetNotNegative()
.SetDisplay("Take Profit", "Take profit distance in pips", "Risk");
_breakevenPips = Param(nameof(BreakevenPips), 20)
.SetNotNegative()
.SetDisplay("Breakeven", "Breakeven activation distance", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_pipSize = 0m;
ResetPositionState();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastMa = new ExponentialMovingAverage { Length = FastMaPeriod };
_slowMa = new ExponentialMovingAverage { Length = SlowMaPeriod };
_verySlowMa = new ExponentialMovingAverage { Length = VerySlowMaPeriod };
_stochastic = new StochasticOscillator
{
K = { Length = StochasticKPeriod },
D = { Length = StochasticDPeriod },
};
_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
_pipSize = CalculatePipSize();
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_fastMa, _slowMa, _verySlowMa, _stochastic, _rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastMa);
DrawIndicator(area, _slowMa);
DrawIndicator(area, _verySlowMa);
DrawIndicator(area, _stochastic);
DrawIndicator(area, _rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(
ICandleMessage candle,
IIndicatorValue fastValue,
IIndicatorValue slowValue,
IIndicatorValue verySlowValue,
IIndicatorValue stochasticValue,
IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!fastValue.IsFinal || !slowValue.IsFinal || !verySlowValue.IsFinal || !stochasticValue.IsFinal || !rsiValue.IsFinal)
return;
// Extract indicator outputs for the completed candle.
var fast = fastValue.GetValue<decimal>();
var slow = slowValue.GetValue<decimal>();
var verySlow = verySlowValue.GetValue<decimal>();
var stochastic = (StochasticOscillatorValue)stochasticValue;
if (stochastic.K is not decimal stochK || stochastic.D is not decimal stochD)
return;
var rsi = rsiValue.GetValue<decimal>();
var longClosed = HandleLongPosition(candle);
if (!longClosed && Position > 0)
return;
var shortClosed = HandleShortPosition(candle);
if (!shortClosed && Position < 0)
return;
if (Position == 0)
ResetPositionState();
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position != 0)
return;
if (!UseMovingAverage && !UseStochastic && !UseRsi)
return;
// All enabled filters must align to confirm the long scenario.
var longSignal = (!UseMovingAverage || fast > slow && slow > verySlow)
&& (!UseStochastic || stochD < stochK && stochK < StochasticLowerLevel)
&& (!UseRsi || rsi < RsiLowerLevel);
var shortSignal = (!UseMovingAverage || verySlow > slow && slow > fast)
&& (!UseStochastic || stochD > stochK && stochK > StochasticUpperLevel)
&& (!UseRsi || rsi > RsiUpperLevel);
if (longSignal && Volume > 0)
{
EnterLong(candle.ClosePrice);
}
else if (shortSignal && Volume > 0)
{
EnterShort(candle.ClosePrice);
}
}
private void EnterLong(decimal price)
{
BuyMarket();
_longEntryPrice = price;
_longStopPrice = StopLossPips > 0 ? price - StopLossPips * _pipSize : null;
_longTakePrice = TakeProfitPips > 0 ? price + TakeProfitPips * _pipSize : null;
_longBreakevenTrigger = BreakevenPips > 0 ? price + BreakevenPips * _pipSize : null;
_longBreakevenArmed = false;
}
private void EnterShort(decimal price)
{
SellMarket();
_shortEntryPrice = price;
_shortStopPrice = StopLossPips > 0 ? price + StopLossPips * _pipSize : null;
_shortTakePrice = TakeProfitPips > 0 ? price - TakeProfitPips * _pipSize : null;
_shortBreakevenTrigger = BreakevenPips > 0 ? price - BreakevenPips * _pipSize : null;
_shortBreakevenArmed = false;
}
private bool HandleLongPosition(ICandleMessage candle)
{
if (Position <= 0 || _longEntryPrice is null)
return false;
// Exit the long trade if the protective stop is touched within the candle range.
if (_longStopPrice is decimal stop && candle.LowPrice <= stop)
{
SellMarket();
ResetPositionState();
return true;
}
// Take profit when the upper target is reached.
if (_longTakePrice is decimal take && candle.HighPrice >= take)
{
SellMarket();
ResetPositionState();
return true;
}
if (!_longBreakevenArmed && _longBreakevenTrigger is decimal trigger && candle.HighPrice >= trigger)
_longBreakevenArmed = true;
// Once breakeven is armed, protect the entry price if momentum fades.
if (_longBreakevenArmed && candle.LowPrice <= _longEntryPrice.Value)
{
SellMarket();
ResetPositionState();
return true;
}
return false;
}
private bool HandleShortPosition(ICandleMessage candle)
{
if (Position >= 0 || _shortEntryPrice is null)
return false;
// Cover the short trade if the stop level is breached.
if (_shortStopPrice is decimal stop && candle.HighPrice >= stop)
{
BuyMarket();
ResetPositionState();
return true;
}
// Lock in profits if the target is met on the downside move.
if (_shortTakePrice is decimal take && candle.LowPrice <= take)
{
BuyMarket();
ResetPositionState();
return true;
}
if (!_shortBreakevenArmed && _shortBreakevenTrigger is decimal trigger && candle.LowPrice <= trigger)
_shortBreakevenArmed = true;
// Breakeven logic mirrors the long side to guard against reversals.
if (_shortBreakevenArmed && candle.HighPrice >= _shortEntryPrice.Value)
{
BuyMarket();
ResetPositionState();
return true;
}
return false;
}
private void ResetPositionState()
{
_longEntryPrice = null;
_shortEntryPrice = null;
_longStopPrice = null;
_shortStopPrice = null;
_longTakePrice = null;
_shortTakePrice = null;
_longBreakevenTrigger = null;
_shortBreakevenTrigger = null;
_longBreakevenArmed = false;
_shortBreakevenArmed = false;
}
private decimal CalculatePipSize()
{
var step = Security?.PriceStep ?? 0.0001m;
if (step <= 0)
step = 0.0001m;
var decimals = Security?.Decimals ?? 0;
return decimals is 3 or 5 ? step * 10m : step;
}
}
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.Indicators import (
ExponentialMovingAverage, StochasticOscillator, RelativeStrengthIndex
)
from StockSharp.Algo.Strategies import Strategy
class vr_zver_strategy(Strategy):
def __init__(self):
super(vr_zver_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._use_moving_average = self.Param("UseMovingAverage", True)
self._fast_ma_period = self.Param("FastMaPeriod", 3)
self._slow_ma_period = self.Param("SlowMaPeriod", 5)
self._very_slow_ma_period = self.Param("VerySlowMaPeriod", 7)
self._use_stochastic = self.Param("UseStochastic", True)
self._stochastic_k_period = self.Param("StochasticKPeriod", 42)
self._stochastic_d_period = self.Param("StochasticDPeriod", 5)
self._stochastic_slowing = self.Param("StochasticSlowing", 7)
self._stochastic_upper_level = self.Param("StochasticUpperLevel", 55)
self._stochastic_lower_level = self.Param("StochasticLowerLevel", 50)
self._use_rsi = self.Param("UseRsi", True)
self._rsi_period = self.Param("RsiPeriod", 14)
self._rsi_upper_level = self.Param("RsiUpperLevel", 55)
self._rsi_lower_level = self.Param("RsiLowerLevel", 50)
self._stop_loss_pips = self.Param("StopLossPips", 50)
self._take_profit_pips = self.Param("TakeProfitPips", 70)
self._breakeven_pips = self.Param("BreakevenPips", 20)
self._fast_ma = None
self._slow_ma = None
self._very_slow_ma = None
self._stochastic = None
self._rsi = None
self._pip_size = 0.0
self._long_entry_price = None
self._short_entry_price = None
self._long_stop_price = None
self._short_stop_price = None
self._long_take_price = None
self._short_take_price = None
self._long_breakeven_trigger = None
self._short_breakeven_trigger = None
self._long_breakeven_armed = False
self._short_breakeven_armed = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def UseMovingAverage(self):
return self._use_moving_average.Value
@property
def FastMaPeriod(self):
return self._fast_ma_period.Value
@property
def SlowMaPeriod(self):
return self._slow_ma_period.Value
@property
def VerySlowMaPeriod(self):
return self._very_slow_ma_period.Value
@property
def UseStochastic(self):
return self._use_stochastic.Value
@property
def StochasticKPeriod(self):
return self._stochastic_k_period.Value
@property
def StochasticDPeriod(self):
return self._stochastic_d_period.Value
@property
def StochasticUpperLevel(self):
return self._stochastic_upper_level.Value
@property
def StochasticLowerLevel(self):
return self._stochastic_lower_level.Value
@property
def UseRsi(self):
return self._use_rsi.Value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def RsiUpperLevel(self):
return self._rsi_upper_level.Value
@property
def RsiLowerLevel(self):
return self._rsi_lower_level.Value
@property
def StopLossPips(self):
return self._stop_loss_pips.Value
@property
def TakeProfitPips(self):
return self._take_profit_pips.Value
@property
def BreakevenPips(self):
return self._breakeven_pips.Value
def OnStarted2(self, time):
super(vr_zver_strategy, self).OnStarted2(time)
self._fast_ma = ExponentialMovingAverage()
self._fast_ma.Length = self.FastMaPeriod
self._slow_ma = ExponentialMovingAverage()
self._slow_ma.Length = self.SlowMaPeriod
self._very_slow_ma = ExponentialMovingAverage()
self._very_slow_ma.Length = self.VerySlowMaPeriod
self._stochastic = StochasticOscillator()
self._stochastic.K.Length = self.StochasticKPeriod
self._stochastic.D.Length = self.StochasticDPeriod
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiPeriod
self._pip_size = self._calculate_pip_size()
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(self._fast_ma, self._slow_ma, self._very_slow_ma, self._stochastic, self._rsi, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._fast_ma)
self.DrawIndicator(area, self._slow_ma)
self.DrawIndicator(area, self._very_slow_ma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_v, slow_v, vs_v, stoch_v, rsi_v):
if candle.State != CandleStates.Finished:
return
if not fast_v.IsFinal or not slow_v.IsFinal or not vs_v.IsFinal or not stoch_v.IsFinal or not rsi_v.IsFinal:
return
fast = float(fast_v.Value)
slow = float(slow_v.Value)
very_slow = float(vs_v.Value)
stoch_k = stoch_v.K
stoch_d = stoch_v.D
if stoch_k is None or stoch_d is None:
return
stoch_k = float(stoch_k)
stoch_d = float(stoch_d)
rsi = float(rsi_v.Value)
long_closed = self._handle_long(candle)
if not long_closed and self.Position > 0:
return
short_closed = self._handle_short(candle)
if not short_closed and self.Position < 0:
return
if self.Position == 0:
self._reset_state()
if self.Position != 0:
return
if not self.UseMovingAverage and not self.UseStochastic and not self.UseRsi:
return
long_signal = (
(not self.UseMovingAverage or (fast > slow and slow > very_slow))
and (not self.UseStochastic or (stoch_d < stoch_k and stoch_k < self.StochasticLowerLevel))
and (not self.UseRsi or rsi < self.RsiLowerLevel)
)
short_signal = (
(not self.UseMovingAverage or (very_slow > slow and slow > fast))
and (not self.UseStochastic or (stoch_d > stoch_k and stoch_k > self.StochasticUpperLevel))
and (not self.UseRsi or rsi > self.RsiUpperLevel)
)
if long_signal and self.Volume > 0:
self._enter_long(float(candle.ClosePrice))
elif short_signal and self.Volume > 0:
self._enter_short(float(candle.ClosePrice))
def _enter_long(self, price):
self.BuyMarket()
self._long_entry_price = price
self._long_stop_price = price - self.StopLossPips * self._pip_size if self.StopLossPips > 0 else None
self._long_take_price = price + self.TakeProfitPips * self._pip_size if self.TakeProfitPips > 0 else None
self._long_breakeven_trigger = price + self.BreakevenPips * self._pip_size if self.BreakevenPips > 0 else None
self._long_breakeven_armed = False
def _enter_short(self, price):
self.SellMarket()
self._short_entry_price = price
self._short_stop_price = price + self.StopLossPips * self._pip_size if self.StopLossPips > 0 else None
self._short_take_price = price - self.TakeProfitPips * self._pip_size if self.TakeProfitPips > 0 else None
self._short_breakeven_trigger = price - self.BreakevenPips * self._pip_size if self.BreakevenPips > 0 else None
self._short_breakeven_armed = False
def _handle_long(self, candle):
if self.Position <= 0 or self._long_entry_price is None:
return False
if self._long_stop_price is not None and float(candle.LowPrice) <= self._long_stop_price:
self.SellMarket(); self._reset_state(); return True
if self._long_take_price is not None and float(candle.HighPrice) >= self._long_take_price:
self.SellMarket(); self._reset_state(); return True
if not self._long_breakeven_armed and self._long_breakeven_trigger is not None and float(candle.HighPrice) >= self._long_breakeven_trigger:
self._long_breakeven_armed = True
if self._long_breakeven_armed and float(candle.LowPrice) <= self._long_entry_price:
self.SellMarket(); self._reset_state(); return True
return False
def _handle_short(self, candle):
if self.Position >= 0 or self._short_entry_price is None:
return False
if self._short_stop_price is not None and float(candle.HighPrice) >= self._short_stop_price:
self.BuyMarket(); self._reset_state(); return True
if self._short_take_price is not None and float(candle.LowPrice) <= self._short_take_price:
self.BuyMarket(); self._reset_state(); return True
if not self._short_breakeven_armed and self._short_breakeven_trigger is not None and float(candle.LowPrice) <= self._short_breakeven_trigger:
self._short_breakeven_armed = True
if self._short_breakeven_armed and float(candle.HighPrice) >= self._short_entry_price:
self.BuyMarket(); self._reset_state(); return True
return False
def _reset_state(self):
self._long_entry_price = None
self._short_entry_price = None
self._long_stop_price = None
self._short_stop_price = None
self._long_take_price = None
self._short_take_price = None
self._long_breakeven_trigger = None
self._short_breakeven_trigger = None
self._long_breakeven_armed = False
self._short_breakeven_armed = False
def _calculate_pip_size(self):
sec = self.Security
step = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None else 0.0001
if step <= 0:
step = 0.0001
decimals = sec.Decimals if sec is not None and sec.Decimals is not None else 0
return step * 10.0 if (decimals == 3 or decimals == 5) else step
def OnReseted(self):
super(vr_zver_strategy, self).OnReseted()
self._pip_size = 0.0
self._reset_state()
def CreateClone(self):
return vr_zver_strategy()