Стратегия Exp Candles XSmoothed
Стратегия отслеживает максимумы и минимумы свечей, сглаженные взвешенным скользящим средним (WMA). Когда цена закрытия пробивает сглаженный максимум плюс настраиваемый буфер, открывается длинная позиция и закрывается существующий шорт. Если цена опускается ниже сглаженного минимума минус буфер, открывается короткая позиция и закрывается существующий лонг.
Параметры
- MA Length – количество периодов для WMA по максимумам и минимумам.
- Level – размер буфера в пунктах, добавляемый к сглаженному максимуму и вычитаемый из сглаженного минимума.
- Candle Type – таймфрейм свечей для анализа.
- Buy Open / Sell Open – разрешения на открытие длинных или коротких позиций.
- Buy Close / Sell Close – разрешения на закрытие позиций при противоположном пробое.
Стратегия отображает линии сглаженных максимумов и минимумов на графике и при запуске активирует встроенную защиту позиций.
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 based on smoothed candle highs and lows.
/// Applies a weighted moving average to high and low prices and
/// enters on breakouts beyond these smoothed levels plus a buffer.
/// </summary>
public class ExpCandlesXSmoothedStrategy : Strategy
{
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<decimal> _level;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<bool> _buyPosOpen;
private readonly StrategyParam<bool> _sellPosOpen;
private readonly StrategyParam<bool> _buyPosClose;
private readonly StrategyParam<bool> _sellPosClose;
private WeightedMovingAverage _highMa;
private WeightedMovingAverage _lowMa;
/// <summary>
/// Moving average period length.
/// </summary>
public int MaLength
{
get => _maLength.Value;
set => _maLength.Value = value;
}
/// <summary>
/// Breakout level in points.
/// </summary>
public decimal Level
{
get => _level.Value;
set => _level.Value = value;
}
/// <summary>
/// Candle type for analysis.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Permission to open long positions.
/// </summary>
public bool BuyPosOpen
{
get => _buyPosOpen.Value;
set => _buyPosOpen.Value = value;
}
/// <summary>
/// Permission to open short positions.
/// </summary>
public bool SellPosOpen
{
get => _sellPosOpen.Value;
set => _sellPosOpen.Value = value;
}
/// <summary>
/// Permission to close long positions.
/// </summary>
public bool BuyPosClose
{
get => _buyPosClose.Value;
set => _buyPosClose.Value = value;
}
/// <summary>
/// Permission to close short positions.
/// </summary>
public bool SellPosClose
{
get => _sellPosClose.Value;
set => _sellPosClose.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="ExpCandlesXSmoothedStrategy"/>.
/// </summary>
public ExpCandlesXSmoothedStrategy()
{
_maLength = Param(nameof(MaLength), 30)
.SetGreaterThanZero()
.SetDisplay("MA Length", "Smoothing period", "Indicators");
_level = Param(nameof(Level), 30m)
.SetGreaterThanZero()
.SetDisplay("Level", "Breakout level in points", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles timeframe", "General");
_buyPosOpen = Param(nameof(BuyPosOpen), true)
.SetDisplay("Buy Open", "Allow opening long positions", "Trading");
_sellPosOpen = Param(nameof(SellPosOpen), true)
.SetDisplay("Sell Open", "Allow opening short positions", "Trading");
_buyPosClose = Param(nameof(BuyPosClose), true)
.SetDisplay("Buy Close", "Allow closing long positions", "Trading");
_sellPosClose = Param(nameof(SellPosClose), true)
.SetDisplay("Sell Close", "Allow closing short positions", "Trading");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highMa = new WeightedMovingAverage { Length = MaLength };
_lowMa = new WeightedMovingAverage { Length = MaLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _highMa);
DrawIndicator(area, _lowMa);
DrawOwnTrades(area);
}
StartProtection(null, null);
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var highVal = _highMa.Process(candle.HighPrice, candle.OpenTime, true);
var lowVal = _lowMa.Process(candle.LowPrice, candle.OpenTime, true);
if (!highVal.IsFormed || !lowVal.IsFormed)
return;
var level = Level * (Security.PriceStep ?? 1m);
var smoothedHigh = highVal.ToDecimal();
var smoothedLow = lowVal.ToDecimal();
var breakUp = candle.ClosePrice > smoothedHigh + level;
var breakDown = candle.ClosePrice < smoothedLow - level;
if (breakUp)
{
if (SellPosClose && Position < 0)
BuyMarket();
if (BuyPosOpen && Position <= 0)
BuyMarket();
}
else if (breakDown)
{
if (BuyPosClose && Position > 0)
SellMarket();
if (SellPosOpen && Position >= 0)
SellMarket();
}
}
}
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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class exp_candles_x_smoothed_strategy(Strategy):
def __init__(self):
super(exp_candles_x_smoothed_strategy, self).__init__()
self._ma_length = self.Param("MaLength", 30) \
.SetGreaterThanZero() \
.SetDisplay("MA Length", "Smoothing period", "Indicators")
self._level = self.Param("Level", 30.0) \
.SetGreaterThanZero() \
.SetDisplay("Level", "Breakout level in points", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles timeframe", "General")
self._buy_pos_open = self.Param("BuyPosOpen", True) \
.SetDisplay("Buy Open", "Allow opening long positions", "Trading")
self._sell_pos_open = self.Param("SellPosOpen", True) \
.SetDisplay("Sell Open", "Allow opening short positions", "Trading")
self._buy_pos_close = self.Param("BuyPosClose", True) \
.SetDisplay("Buy Close", "Allow closing long positions", "Trading")
self._sell_pos_close = self.Param("SellPosClose", True) \
.SetDisplay("Sell Close", "Allow closing short positions", "Trading")
self._high_ma = None
self._low_ma = None
@property
def ma_length(self):
return self._ma_length.Value
@property
def level(self):
return self._level.Value
@property
def candle_type(self):
return self._candle_type.Value
@property
def buy_pos_open(self):
return self._buy_pos_open.Value
@property
def sell_pos_open(self):
return self._sell_pos_open.Value
@property
def buy_pos_close(self):
return self._buy_pos_close.Value
@property
def sell_pos_close(self):
return self._sell_pos_close.Value
def OnStarted2(self, time):
super(exp_candles_x_smoothed_strategy, self).OnStarted2(time)
self._high_ma = WeightedMovingAverage()
self._high_ma.Length = self.ma_length
self._low_ma = WeightedMovingAverage()
self._low_ma.Length = self.ma_length
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.DrawIndicator(area, self._high_ma)
self.DrawIndicator(area, self._low_ma)
self.DrawOwnTrades(area)
self.StartProtection(None, None)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
high_val = process_float(self._high_ma, candle.HighPrice, candle.OpenTime, True)
low_val = process_float(self._low_ma, candle.LowPrice, candle.OpenTime, True)
if not high_val.IsFormed or not low_val.IsFormed:
return
step = self.Security.PriceStep if self.Security.PriceStep is not None else 1.0
lvl = float(self.level) * float(step)
smoothed_high = float(high_val)
smoothed_low = float(low_val)
close = float(candle.ClosePrice)
break_up = close > smoothed_high + lvl
break_down = close < smoothed_low - lvl
if break_up:
if self.sell_pos_close and self.Position < 0:
self.BuyMarket()
if self.buy_pos_open and self.Position <= 0:
self.BuyMarket()
elif break_down:
if self.buy_pos_close and self.Position > 0:
self.SellMarket()
if self.sell_pos_open and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return exp_candles_x_smoothed_strategy()