Эта модель зеркально отражает бычий вариант и сигнализирует о возможной вершине. После разрыва вверх формируется доджи, а затем происходит разрыв вниз, изолируя среднюю свечу над предыдущим диапазоном.
Тестирование показывает среднегодичную доходность около 79%. Стратегию лучше запускать на фондовом рынке.
Стратегия открывает короткую позицию, когда третья свеча открывается ниже доджи, стремясь воспользоваться резкой сменой настроений.
Риск ограничивается стопом сразу над максимумом доджи на случай восстановления цены.
Детали
Условия входа: совпадение с паттерном
Длинная/короткая: обе
Условия выхода: стоп-лосс или противоположный сигнал
Стопы: да, процентные
Значения по умолчанию:
CandleType = 15 minute
DojiBodyPercent = 10
StopLossPercent = 2
Рынок торгуется круглосуточно, поэтому диапазоны свечей почти никогда не разрываются (в месяце примеров не больше одного такого медвежьего паттерна); гэпы измеряются между телами свечей. Тело доджи — не больше DojiBodyPercent его диапазона. Стратегия только продаёт, по закрытию третьей свечи; стоп ставится на StopLossPercent выше максимума доджи, и позиция закрывается, когда свеча закрывается выше него.
Фильтры:
Категория: Паттерн
Направление: обе
Индикаторы: свечные
Стопы: да
Сложность: средняя
Таймфрейм: внутридневной
Сезонность: нет
Нейронные сети: нет
Дивергенция: нет
Уровень риска: средний
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>
/// Bearish Abandoned Baby strategy.
/// While flat it sells after a bullish candle, a doji whose body gaps above the first body, and a bearish candle whose body gaps below the doji.
/// The stop lies StopLossPercent above the doji's high, and a close beyond it closes the position.
/// </summary>
public class BearishAbandonedBabyStrategy : Strategy
{
private readonly StrategyParam<decimal> _dojiBodyPercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private readonly List<ICandleMessage> _candles = [];
private decimal _stopPrice;
/// <summary>
/// Largest body of the doji, in percent of its range.
/// </summary>
public decimal DojiBodyPercent
{
get => _dojiBodyPercent.Value;
set => _dojiBodyPercent.Value = value;
}
/// <summary>
/// Distance of the stop beyond the pattern, in percent.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public BearishAbandonedBabyStrategy()
{
_dojiBodyPercent = Param(nameof(DojiBodyPercent), 10m)
.SetNotNegative()
.SetDisplay("Doji Body %", "Largest body of the doji, in percent of its range", "Pattern");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Distance of the stop beyond the pattern, in percent", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candles.Clear();
_stopPrice = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candles.Clear();
_stopPrice = default;
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;
_candles.Add(candle);
if (_candles.Count > 3)
_candles.RemoveAt(0);
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position < 0)
{
if (candle.ClosePrice >= _stopPrice)
BuyMarket(-Position);
return;
}
if (Position != 0 || _candles.Count < 3)
return;
var c0 = _candles[0];
var c1 = _candles[1];
var c2 = _candles[2];
if (!(c0.ClosePrice > c0.OpenPrice && Math.Abs(c1.ClosePrice - c1.OpenPrice) <= (c1.HighPrice - c1.LowPrice) * DojiBodyPercent / 100m && Math.Min(c1.OpenPrice, c1.ClosePrice) > Math.Max(c0.OpenPrice, c0.ClosePrice) && c2.ClosePrice < c2.OpenPrice && Math.Max(c2.OpenPrice, c2.ClosePrice) < Math.Min(c1.OpenPrice, c1.ClosePrice)))
return;
SellMarket(Volume);
_stopPrice = c1.HighPrice * (1 + StopLossPercent / 100m);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class bearish_abandoned_baby_strategy(Strategy):
"""
Bearish Abandoned Baby strategy.
While flat it sells after a bullish candle, a doji whose body gaps above the first body, and a bearish candle whose body gaps below the doji.
The stop lies StopLossPercent above the doji's high, and a close beyond it closes the position.
"""
def __init__(self):
super(bearish_abandoned_baby_strategy, self).__init__()
self._doji_body_percent = self.Param("DojiBodyPercent", 10.0).SetNotNegative().SetDisplay("Doji Body %", "Largest body of the doji, in percent of its range", "Pattern")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Distance of the stop beyond the pattern, in percent", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._candles = []
self._stop_price = Decimal(0)
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bearish_abandoned_baby_strategy, self).OnReseted()
self._candles = []
self._stop_price = Decimal(0)
def OnStarted2(self, time):
super(bearish_abandoned_baby_strategy, self).OnStarted2(time)
self._candles = []
self._stop_price = Decimal(0)
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
self._candles.append(candle)
if len(self._candles) > 3:
self._candles.pop(0)
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position < 0:
if candle.ClosePrice >= self._stop_price:
self.BuyMarket(-self.Position)
return
if self.Position != 0 or len(self._candles) < 3:
return
c0, c1, c2 = self._candles
if not (c0.ClosePrice > c0.OpenPrice and Math.Abs(c1.ClosePrice - c1.OpenPrice) <= (c1.HighPrice - c1.LowPrice) * Decimal(self._doji_body_percent.Value) / Decimal(100) and Math.Min(c1.OpenPrice, c1.ClosePrice) > Math.Max(c0.OpenPrice, c0.ClosePrice) and c2.ClosePrice < c2.OpenPrice and Math.Max(c2.OpenPrice, c2.ClosePrice) < Math.Min(c1.OpenPrice, c1.ClosePrice)):
return
self.SellMarket(self.Volume)
self._stop_price = c1.HighPrice * (Decimal(1) + Decimal(self._stop_loss_percent.Value) / Decimal(100))
def CreateClone(self):
return bearish_abandoned_baby_strategy()