Auf GitHub ansehen

Strategie Bullishes Verlassenes Baby

Das Bullishe Verlassene Baby ist ein seltenes Drei-Kerzen-Muster mit einem Gap-Down-Doji gefolgt von einem Gap-Up. Diese Formation lässt die mittlere Kerze "verlassen" zurück und geht oft einer starken Aufwärtsumkehr voraus.

Tests zeigen eine durchschnittliche jährliche Rendite von etwa 76%. Es funktioniert am besten auf dem Forex-Markt.

Die Strategie kauft bei der Eröffnung der dritten Kerze, sobald diese mit einem Gap über den Doji steigt, und erwartet starke Anschlusskäufe, wenn Shorts eindecken.

Stops liegen knapp unterhalb des Doji-Tiefs, um Verluste gering zu halten, falls die Umkehr nicht standhält.

Details

  • Einstiegskriterien: Mustererkennung
  • Long/Short: Beide
  • Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
  • Stops: Ja, prozentbasiert
  • Standardwerte:
    • CandleType = 15 minute
    • DojiBodyPercent = 10
    • StopLossPercent = 2 Der Markt handelt rund um die Uhr, daher haben Kerzenspannen fast nie Lücken (im Beispielmonat gibt es kein solches bullisches Muster); die Lücken werden zwischen den Kerzenkörpern gemessen. Der Körper des Doji beträgt höchstens DojiBodyPercent seiner Spanne. Die Strategie kauft nur, zum Schluss der dritten Kerze; der Stop liegt StopLossPercent unter dem Doji-Tief, und die Position schließt, wenn eine Kerze darunter schließt.
  • Filter:
    • Kategorie: Muster
    • Richtung: Beide
    • Indikatoren: Candlestick
    • Stops: Ja
    • Komplexität: Mittel
    • Zeitrahmen: Intraday
    • Saisonalität: Nein
    • Neuronale Netze: Nein
    • Divergenz: Nein
    • Risikolevel: Mittel
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>
/// Bullish Abandoned Baby strategy.
/// While flat it buys after a bearish candle, a doji whose body gaps below the first body, and a bullish candle whose body gaps above the doji.
/// The stop lies StopLossPercent below the doji's low, and a close beyond it closes the position.
/// </summary>
public class BullishAbandonedBabyStrategy : 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 BullishAbandonedBabyStrategy()
	{
		_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)
				SellMarket(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.Max(c1.OpenPrice, c1.ClosePrice) < Math.Min(c0.OpenPrice, c0.ClosePrice) && c2.ClosePrice > c2.OpenPrice && Math.Min(c2.OpenPrice, c2.ClosePrice) > Math.Max(c1.OpenPrice, c1.ClosePrice)))
			return;

		BuyMarket(Volume);
		_stopPrice = c1.LowPrice * (1 - StopLossPercent / 100m);
	}
}