Стратегия Berlin Candles
Стратегия использует собственные свечи Berlin, построенные на сглаженных значениях Heikin Ashi. Длинная позиция открывается, когда бычья свеча Berlin закрывается выше линии Дончиана. Короткая позиция открывается, когда медвежья свеча закрывается ниже этой линии.
Детали
- Условия входа:
- Лонг: закрытие Berlin > открытие Berlin и закрытие Berlin > baseline.
- Шорт: закрытие Berlin < открытие Berlin и закрытие Berlin < baseline.
- Направление: обе стороны
- Стопы: по умолчанию отсутствуют
- Значения по умолчанию:
Smoothing= 1BaselinePeriod= 26CandleType= TimeSpan.FromMinutes(5).TimeFrame()
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>
/// Strategy based on Berlin candles with Donchian baseline.
/// </summary>
public class BerlinCandlesStrategy : Strategy
{
private readonly StrategyParam<int> _smoothing;
private readonly StrategyParam<int> _baselinePeriod;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _ema;
private DonchianChannels _donchian;
private decimal _prevEma;
private bool _isInitialized;
private int _cooldown;
public int Smoothing
{
get => _smoothing.Value;
set => _smoothing.Value = value;
}
public int BaselinePeriod
{
get => _baselinePeriod.Value;
set => _baselinePeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public BerlinCandlesStrategy()
{
_smoothing = Param(nameof(Smoothing), 1)
.SetDisplay("Smoothing", "EMA smoothing for Berlin open", "Berlin")
.SetOptimize(1, 10, 1);
_baselinePeriod = Param(nameof(BaselinePeriod), 26)
.SetDisplay("Baseline Period", "Donchian baseline period", "Berlin")
.SetOptimize(10, 50, 5);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_prevEma = default;
_isInitialized = false;
_cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ema = new ExponentialMovingAverage { Length = Smoothing + 1 };
_donchian = new DonchianChannels { Length = BaselinePeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _donchian);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
// Manually process Donchian
var donchianResult = _donchian.Process(candle);
if (donchianResult is not DonchianChannelsValue dv || dv.Middle is not decimal middleBand)
return;
if (!_isInitialized)
{
_prevEma = emaValue;
_isInitialized = true;
return;
}
var openExpr = _prevEma;
var closeExpr = candle.ClosePrice;
decimal openValue;
decimal closeValue;
if (openExpr > closeExpr)
{
openValue = Math.Min(openExpr, candle.HighPrice);
closeValue = Math.Max(closeExpr, candle.LowPrice);
}
else
{
openValue = Math.Max(openExpr, candle.LowPrice);
closeValue = Math.Min(closeExpr, candle.HighPrice);
}
var baseline = middleBand;
if (_cooldown > 0)
{
_cooldown--;
_prevEma = emaValue;
return;
}
if (closeValue > openValue && closeValue > baseline && Position <= 0)
{
BuyMarket();
_cooldown = 100;
}
else if (closeValue < openValue && closeValue < baseline && Position >= 0)
{
SellMarket();
_cooldown = 100;
}
_prevEma = emaValue;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.BusinessEntities")
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, DonchianChannels, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class berlin_candles_strategy(Strategy):
def __init__(self):
super(berlin_candles_strategy, self).__init__()
self._smoothing = self.Param("Smoothing", 1) \
.SetDisplay("Smoothing", "EMA smoothing for Berlin open", "Berlin")
self._baseline_period = self.Param("BaselinePeriod", 26) \
.SetDisplay("Baseline Period", "Donchian baseline period", "Berlin")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_ema = 0.0
self._is_initialized = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(berlin_candles_strategy, self).OnReseted()
self._prev_ema = 0.0
self._is_initialized = False
self._cooldown = 0
def OnStarted2(self, time):
super(berlin_candles_strategy, self).OnStarted2(time)
self._ema = ExponentialMovingAverage()
self._ema.Length = self._smoothing.Value + 1
self._donchian = DonchianChannels()
self._donchian.Length = self._baseline_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._ema, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._donchian)
self.DrawOwnTrades(area)
def OnProcess(self, candle, ema_val):
if candle.State != CandleStates.Finished:
return
ema_v = float(ema_val)
donchian_result = self._donchian.Process(CandleIndicatorValue(self._donchian, candle))
middle = donchian_result.Middle
if middle is None:
return
middle_v = float(middle)
if not self._is_initialized:
self._prev_ema = ema_v
self._is_initialized = True
return
open_expr = self._prev_ema
close_expr = float(candle.ClosePrice)
high_v = float(candle.HighPrice)
low_v = float(candle.LowPrice)
if open_expr > close_expr:
open_value = min(open_expr, high_v)
close_value = max(close_expr, low_v)
else:
open_value = max(open_expr, low_v)
close_value = min(close_expr, high_v)
if self._cooldown > 0:
self._cooldown -= 1
self._prev_ema = ema_v
return
if close_value > open_value and close_value > middle_v and self.Position <= 0:
self.BuyMarket()
self._cooldown = 100
elif close_value < open_value and close_value < middle_v and self.Position >= 0:
self.SellMarket()
self._cooldown = 100
self._prev_ema = ema_v
def CreateClone(self):
return berlin_candles_strategy()