Стратегия Eugene Inside Breakout представляет собой прямую конвертацию оригинального советника MetaTrader от barabashkakvn. Осн
ова лежит исключительно на ценовом действии: серия внутренних свечей с последующим пробоем диапазона. Уровни подтверждения, рас
считанные по телу предыдущей свечи, позволяют дождаться развития импульса до входа в позицию.
Обзор
Алгоритм отслеживает формирование нового максимума или минимума относительно предыдущей свечи. Для лонгов требуется, чтобы мини
мум предыдущей свечи находился ниже максимума свечи два бара назад — это подчеркивает сжатие перед пробоем. Для шортов стратегия
отказывается торговать, если предыдущая свеча является внутренней, полностью повторяя защиту из исходного MQL-кода. Заявки всег
да исполняются по рынку фиксированным объемом.
Рыночная логика
Делает акцент на пробоях последних экстремумов, чтобы как можно раньше войти в зарождающееся движение.
Использует тело предыдущей свечи для расчёта двух уровней отката на одну треть (zigLevelBuy и zigLevelSell). Цена должна к
оснуться соответствующего уровня либо торговая сессия должна перейти за настроенный час активации, чтобы вход был разрешён.
Блокирует новые позиции, если пробой совпадает с внутренней свечой против направления сделки.
Закрывает открытые позиции, когда подтверждается противоположный пробой, поэтому стратегия всегда остаётся вне рынка или в пос
леднем сигнале.
Правила входа
Лонг
Текущий максимум выше максимума предыдущей свечи.
Подтверждение получено, когда текущий минимум пробивает уровень отката одной третьей тела предыдущей свечи либо текущий час п
ревышает параметр активации.
Текущий минимум должен оставаться выше предыдущего минимума, при этом минимум предыдущей свечи располагается ниже максимума с
вечи два бара назад.
Открытых позиций нет.
Шорт
Текущий минимум ниже минимума предыдущей свечи.
Подтверждение получено, когда текущий максимум тестирует верхний уровень отката одной третьей тела предыдущей свечи либо теку
щий час превышает параметр активации.
Предыдущая свеча не является внутренней (её максимум не ниже и минимум не выше свечи два бара назад).
Текущий максимум ниже максимума предыдущей свечи.
Открытых позиций нет.
Правила выхода
Закрывать лонг, когда формируется подтверждённый шорт-пробой (условия 1–3 логики входа в шорт).
Закрывать шорт, когда формируется подтверждённый лонг-пробой (условия 1–3 логики входа в лонг).
Параметры
Имя
Описание
Значение по умолчанию
CandleType
Таймфрейм свечей, обрабатываемых стратегией.
1-часовые свечи
Volume
Объём заявки для каждого рыночного ордера.
0.1
ActivationHour
Час, после которого подтверждения принимаются автоматически. Повторяет фильтр TimeCurrent() из MQL-кода.
8
Примечания
Проверки "white bird" и "black bird" из оригинального скрипта из-за условий всегда ложны; они сохранены для совместимости и н
е влияют на торговые решения.
Дополнительные индикаторы и трейлинг-стопы не используются — стратегия полностью основана на цене и переворачивается при каждо
м противоположном пробое.
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>
/// Breakout strategy derived from the Eugene expert advisor.
/// </summary>
public class EugeneInsideBreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _activationHour;
private decimal _prevOpen1;
private decimal _prevClose1;
private decimal _prevHigh1;
private decimal _prevLow1;
private decimal _prevOpen2;
private decimal _prevClose2;
private decimal _prevHigh2;
private decimal _prevLow2;
private bool _hasPrev1;
private bool _hasPrev2;
/// <summary>
/// Candle type to process.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Hour of day after which confirmations are automatically valid.
/// </summary>
public int ActivationHour
{
get => _activationHour.Value;
set => _activationHour.Value = value;
}
/// <summary>
/// Initializes <see cref="EugeneInsideBreakoutStrategy"/>.
/// </summary>
public EugeneInsideBreakoutStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to process", "General");
_activationHour = Param(nameof(ActivationHour), 8)
.SetRange(0, 23)
.SetDisplay("Activation Hour", "Hour when confirmations become unconditional", "Filters");
ResetHistory();
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetHistory();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev2)
{
UpdateHistory(candle);
return;
}
var open1 = _prevOpen1;
var close1 = _prevClose1;
var open2 = _prevOpen2;
var close2 = _prevClose2;
var high0 = candle.HighPrice;
var high1 = _prevHigh1;
var high2 = _prevHigh2;
var low0 = candle.LowPrice;
var low1 = _prevLow1;
var low2 = _prevLow2;
// Replicate the original expert advisor checks for inside bars.
var blackInsider = high1 <= high2 && low1 >= low2 && close1 <= open1;
var whiteInsider = high1 <= high2 && low1 >= low2 && close1 > open1;
var whiteBird = whiteInsider && close2 > open2;
var blackBird = blackInsider && close2 < open2;
// ZigZag style confirmation levels based on the previous candle body.
var zigLevelBuy = close1 < open1
? open1 - (close1 - open1) / 3m
: open1 - (open1 - low1) / 3m;
var zigLevelSell = close1 > open1
? open1 + (close1 - open1) / 3m
: open1 + (high1 - open1) / 3m;
var confirmBuy = (low0 <= zigLevelBuy || candle.CloseTime.Hour >= ActivationHour) && !blackBird && !whiteInsider;
var confirmSell = (high0 >= zigLevelSell || candle.CloseTime.Hour >= ActivationHour) && !whiteBird && !blackInsider;
var buySignal = high0 > high1;
var sellSignal = low0 < low1;
if (Position == 0)
{
if (buySignal && confirmBuy && low0 > low1 && low1 < high2)
{
BuyMarket();
}
else if (sellSignal && confirmSell && high0 < high1)
{
SellMarket();
}
}
else if (Position > 0)
{
if (sellSignal && confirmSell && high0 < high1)
SellMarket();
}
else if (Position < 0)
{
if (buySignal && confirmBuy && low0 > low1 && low1 < high2)
BuyMarket();
}
UpdateHistory(candle);
}
private void UpdateHistory(ICandleMessage candle)
{
// Keep the two most recent completed candles for decision making.
_prevOpen2 = _prevOpen1;
_prevClose2 = _prevClose1;
_prevHigh2 = _prevHigh1;
_prevLow2 = _prevLow1;
_hasPrev2 = _hasPrev1;
_prevOpen1 = candle.OpenPrice;
_prevClose1 = candle.ClosePrice;
_prevHigh1 = candle.HighPrice;
_prevLow1 = candle.LowPrice;
_hasPrev1 = true;
}
private void ResetHistory()
{
_prevOpen1 = default;
_prevClose1 = default;
_prevHigh1 = default;
_prevLow1 = default;
_prevOpen2 = default;
_prevClose2 = default;
_prevHigh2 = default;
_prevLow2 = default;
_hasPrev1 = false;
_hasPrev2 = false;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class eugene_inside_breakout_strategy(Strategy):
"""
Breakout strategy derived from the Eugene expert advisor.
Detects inside bars and trades breakouts with zigzag confirmation.
"""
def __init__(self):
super(eugene_inside_breakout_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._activation_hour = self.Param("ActivationHour", 8) \
.SetDisplay("Activation Hour", "Hour when confirmations become unconditional", "Filters")
self._prev_open1 = 0.0
self._prev_close1 = 0.0
self._prev_high1 = 0.0
self._prev_low1 = 0.0
self._prev_open2 = 0.0
self._prev_close2 = 0.0
self._prev_high2 = 0.0
self._prev_low2 = 0.0
self._has_prev1 = False
self._has_prev2 = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(eugene_inside_breakout_strategy, self).OnReseted()
self._reset_history()
def OnStarted2(self, time):
super(eugene_inside_breakout_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
if not self._has_prev2:
self._update_history(candle)
return
high0 = float(candle.HighPrice)
low0 = float(candle.LowPrice)
close0 = float(candle.ClosePrice)
open1 = self._prev_open1
close1 = self._prev_close1
high1 = self._prev_high1
low1 = self._prev_low1
open2 = self._prev_open2
close2 = self._prev_close2
high2 = self._prev_high2
low2 = self._prev_low2
black_insider = high1 <= high2 and low1 >= low2 and close1 <= open1
white_insider = high1 <= high2 and low1 >= low2 and close1 > open1
white_bird = white_insider and close2 > open2
black_bird = black_insider and close2 < open2
if close1 < open1:
zig_level_buy = open1 - (close1 - open1) / 3.0
else:
zig_level_buy = open1 - (open1 - low1) / 3.0
if close1 > open1:
zig_level_sell = open1 + (close1 - open1) / 3.0
else:
zig_level_sell = open1 + (high1 - open1) / 3.0
hour = candle.CloseTime.Hour
confirm_buy = (low0 <= zig_level_buy or hour >= self._activation_hour.Value) and not black_bird and not white_insider
confirm_sell = (high0 >= zig_level_sell or hour >= self._activation_hour.Value) and not white_bird and not black_insider
buy_signal = high0 > high1
sell_signal = low0 < low1
if self.Position == 0:
if buy_signal and confirm_buy and low0 > low1 and low1 < high2:
self.BuyMarket()
elif sell_signal and confirm_sell and high0 < high1:
self.SellMarket()
elif self.Position > 0:
if sell_signal and confirm_sell and high0 < high1:
self.SellMarket()
elif self.Position < 0:
if buy_signal and confirm_buy and low0 > low1 and low1 < high2:
self.BuyMarket()
self._update_history(candle)
def _update_history(self, candle):
self._prev_open2 = self._prev_open1
self._prev_close2 = self._prev_close1
self._prev_high2 = self._prev_high1
self._prev_low2 = self._prev_low1
self._has_prev2 = self._has_prev1
self._prev_open1 = float(candle.OpenPrice)
self._prev_close1 = float(candle.ClosePrice)
self._prev_high1 = float(candle.HighPrice)
self._prev_low1 = float(candle.LowPrice)
self._has_prev1 = True
def _reset_history(self):
self._prev_open1 = 0.0
self._prev_close1 = 0.0
self._prev_high1 = 0.0
self._prev_low1 = 0.0
self._prev_open2 = 0.0
self._prev_close2 = 0.0
self._prev_high2 = 0.0
self._prev_low2 = 0.0
self._has_prev1 = False
self._has_prev2 = False
def CreateClone(self):
return eugene_inside_breakout_strategy()