Стратегия 3-Bar Low
Стратегия 3-Bar Low открывает длинную позицию, когда цена закрытия опускается ниже минимума предыдущих трёх баров, и выходит из позиции, когда цена закрытия поднимается выше максимума предыдущих семи баров. Дополнительный фильтр EMA может требовать, чтобы цена находилась выше долгосрочного среднего перед входом в сделку.
Подробности
- Условия входа:
- Цена закрытия ниже предыдущего минимума за три бара.
- Опционально: цена закрытия выше EMA при включенном фильтре.
- Направление: Только лонг.
- Условия выхода:
- Цена закрытия выше предыдущего максимума за семь баров.
- Стопы: Нет.
- Параметры по умолчанию:
MaPeriod= 200LowestLength= 3HighestLength= 7UseEmaFilter= false
- Фильтры:
- Категория: Пробой
- Направление: Лонг
- Индикаторы: EMA, Highest/Lowest
- Стопы: Нет
- Сложность: Низкая
- Таймфрейм: Любой
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Низкий
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Three Bar Low Strategy.
/// A long opens when the close falls below the lowest close of the previous LowestLength candles and, with UseEmaFilter,
/// the close is above the MaPeriod EMA. The long closes when the close rises above the highest close of the previous
/// HighestLength candles.
/// </summary>
public class ThreeBarLowStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<int> _lowestLength;
private readonly StrategyParam<int> _highestLength;
private readonly StrategyParam<bool> _useEmaFilter;
private readonly StrategyParam<DataType> _candleType;
private Lowest _lowestClose;
private Highest _highestClose;
private decimal? _prevLowest;
private decimal? _prevHighest;
/// <summary>
/// EMA period of the filter.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Previous candles of the lowest close.
/// </summary>
public int LowestLength
{
get => _lowestLength.Value;
set => _lowestLength.Value = value;
}
/// <summary>
/// Previous candles of the highest close.
/// </summary>
public int HighestLength
{
get => _highestLength.Value;
set => _highestLength.Value = value;
}
/// <summary>
/// Require the close above the EMA for entries.
/// </summary>
public bool UseEmaFilter
{
get => _useEmaFilter.Value;
set => _useEmaFilter.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public ThreeBarLowStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 200)
.SetGreaterThanZero()
.SetDisplay("MA Period", "EMA period of the filter", "Indicators");
_lowestLength = Param(nameof(LowestLength), 3)
.SetGreaterThanZero()
.SetDisplay("Lowest Length", "Previous candles of the lowest close", "Indicators");
_highestLength = Param(nameof(HighestLength), 7)
.SetGreaterThanZero()
.SetDisplay("Highest Length", "Previous candles of the highest close", "Indicators");
_useEmaFilter = Param(nameof(UseEmaFilter), false)
.SetDisplay("Use EMA Filter", "Require the close above the EMA for entries", "Filters");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevLowest = null;
_prevHighest = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevLowest = null;
_prevHighest = null;
var ema = new ExponentialMovingAverage { Length = MaPeriod };
_lowestClose = new Lowest { Length = LowestLength };
_highestClose = new Highest { Length = HighestLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue emaValue)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
// Both levels are measured on the candles before this one.
var lowest = _prevLowest;
var highest = _prevHighest;
var currentLowest = _lowestClose.Process(close, candle.OpenTime, true).ToDecimal();
var currentHighest = _highestClose.Process(close, candle.OpenTime, true).ToDecimal();
if (_lowestClose.IsFormed)
_prevLowest = currentLowest;
if (_highestClose.IsFormed)
_prevHighest = currentHighest;
if (lowest is not decimal lowLevel || highest is not decimal highLevel)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position > 0)
{
if (close > highLevel)
SellMarket(Position);
return;
}
var emaOk = !UseEmaFilter || (emaValue.IsFormed && close > emaValue.GetValue<decimal>());
if (Position == 0 && close < lowLevel && emaOk)
BuyMarket(Volume);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class three_bar_low_strategy(Strategy):
"""
Three Bar Low Strategy.
A long opens when the close falls below the lowest close of the previous LowestLength candles and, with UseEmaFilter,
the close is above the MaPeriod EMA. The long closes when the close rises above the highest close of the previous
HighestLength candles.
"""
def __init__(self):
super(three_bar_low_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 200).SetGreaterThanZero().SetDisplay("MA Period", "EMA period of the filter", "Indicators")
self._lowest_length = self.Param("LowestLength", 3).SetGreaterThanZero().SetDisplay("Lowest Length", "Previous candles of the lowest close", "Indicators")
self._highest_length = self.Param("HighestLength", 7).SetGreaterThanZero().SetDisplay("Highest Length", "Previous candles of the highest close", "Indicators")
self._use_ema_filter = self.Param("UseEmaFilter", False).SetDisplay("Use EMA Filter", "Require the close above the EMA for entries", "Filters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._lowest_close = None
self._highest_close = None
self._prev_lowest = None
self._prev_highest = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(three_bar_low_strategy, self).OnReseted()
self._prev_lowest = None
self._prev_highest = None
def OnStarted2(self, time):
super(three_bar_low_strategy, self).OnStarted2(time)
self._prev_lowest = None
self._prev_highest = None
ema = ExponentialMovingAverage()
ema.Length = self._ma_period.Value
self._lowest_close = Lowest()
self._lowest_close.Length = self._lowest_length.Value
self._highest_close = Highest()
self._highest_close.Length = self._highest_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(ema, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
# Both levels are measured on the candles before this one.
lowest = self._prev_lowest
highest = self._prev_highest
current_lowest = float(process_float(self._lowest_close, candle.ClosePrice, candle.OpenTime, True).GetValue[Decimal](None))
current_highest = float(process_float(self._highest_close, candle.ClosePrice, candle.OpenTime, True).GetValue[Decimal](None))
if self._lowest_close.IsFormed:
self._prev_lowest = current_lowest
if self._highest_close.IsFormed:
self._prev_highest = current_highest
if lowest is None or highest is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position > 0:
if close > highest:
self.SellMarket(self.Position)
return
ema_ok = not self._use_ema_filter.Value or (ema_value.IsFormed and close > float(ema_value.GetValue[Decimal](None)))
if self.Position == 0 and close < lowest and ema_ok:
self.BuyMarket(self.Volume)
def CreateClone(self):
return three_bar_low_strategy()