Morgenstern-Muster-Strategie
Der Morgenstern ist eine bullische Kerzenformation, die nach einem Rückgang einen potenziellen Boden signalisiert. Er besteht aus einer großen bärischen Kerze, einer kleinen unentschlossenen Kerze und einer starken bullischen Kerze, die über dem Mittelpunkt des ersten Balkens schließt.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 97%. Sie funktioniert am besten auf dem Kryptomarkt.
Diese Strategie verfolgt Sequenzen von drei Kerzen. Wenn das Muster erscheint, wird eine Long-Position mit einem Stop unterhalb der kleinen mittleren Kerze eröffnet. Ausstiege erfolgen, sobald der Preis über das Hoch des Bestätigungsbalkens steigt oder der Stop erreicht wird.
Da das Muster oft schnelle Erholungen aus überverkauften Bedingungen auslöst, sind Trades meist kurzlebig und erfassen den anfänglichen Aufwärtsschub.
Details
- Einstiegskriterien: Drei-Kerzen-Morgenstern-Muster.
- Long/Short: Nur Long.
- Ausstiegskriterien: Preis über dem Hoch des Bestätigungsbalkens oder Stop-Loss.
- Stops: Ja, unterhalb des Tiefs der mittleren Kerze.
- Standardwerte:
CandleType= 5 minuteStopLossPercent= 1
- Filter:
- Kategorie: Muster
- Richtung: Long
- 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.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Long-only three-candle Morning Star with middle-candle-low stop and confirmation-high target.
/// </summary>
public class MorningStarStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly List<ICandleMessage> _recent = new();
private decimal? _stopPrice;
private decimal? _targetPrice;
private Order _entryOrder;
private Order _exitOrder;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
public MorningStarStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Morning Star pattern timeframe", "General");
_stopLossPercent = Param(nameof(StopLossPercent), 1m).SetRange(0m, 99m)
.SetDisplay("Stop below middle low (%)", "Buffer below the middle candle's low; zero places the stop at that low", "Protection");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType), (Security, DataType.Level1)];
protected override void OnReseted()
{
base.OnReseted();
ClearState();
}
private void ClearState()
{
_recent.Clear();
_stopPrice = _targetPrice = null;
_entryOrder = _exitOrder = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ClearState();
var bids = new Subscription(DataType.Level1, Security);
bids.MarketData.BuildField = Level1Fields.BestBidPrice;
SubscribeLevel1(bids).Bind(ProcessBid).Start();
var candles = SubscribeCandles(CandleType);
candles.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, candles);
DrawOwnTrades(area);
}
}
private static bool IsPending(Order order)
=> order is not null && order.State is not (OrderStates.Done or OrderStates.Failed);
private void ProcessBid(Level1ChangeMessage message)
{
if (message.TryGetDecimal(Level1Fields.BestBidPrice) is decimal bid && bid > 0m)
CheckExit(bid, bid);
}
private bool CheckExit(decimal low, decimal high)
{
if (Position <= 0m || IsPending(_exitOrder))
return false;
// With only a completed bar's range, prefer the adverse stop when both levels touched.
if (_stopPrice is decimal stop && low <= stop ||
_targetPrice is decimal target && high > target)
{
_exitOrder = SellMarket(Position);
_recent.Clear();
_stopPrice = _targetPrice = null;
return true;
}
return false;
}
private void Append(ICandleMessage candle)
{
_recent.Add(candle);
if (_recent.Count > 2)
_recent.RemoveAt(0);
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (Position > 0m && CheckExit(candle.LowPrice, candle.HighPrice))
return;
if (IsPending(_entryOrder) || IsPending(_exitOrder))
{
Append(candle);
return;
}
if (Position == 0m && _recent.Count == 2 && IsFormedAndOnlineAndAllowTrading())
{
var first = _recent[0];
var middle = _recent[1];
var firstBody = first.OpenPrice - first.ClosePrice;
var middleBody = Math.Abs(middle.ClosePrice - middle.OpenPrice);
var thirdBody = candle.ClosePrice - candle.OpenPrice;
var firstMidpoint = (first.HighPrice + first.LowPrice) / 2m;
if (firstBody > 0m && middleBody < firstBody / 2m &&
thirdBody >= firstBody / 2m && candle.ClosePrice > firstMidpoint)
{
_stopPrice = middle.LowPrice * (1m - StopLossPercent / 100m);
_targetPrice = candle.HighPrice;
_entryOrder = BuyMarket(Volume);
}
}
Append(candle);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal, Math
from StockSharp.Messages import DataType, CandleStates, OrderStates, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Strategies import Strategy
class morning_star_strategy(Strategy):
"""Long-only Morning Star with a middle-candle-low stop and confirmation-high target."""
def __init__(self):
super(morning_star_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Morning Star pattern timeframe", "General")
self._stop_loss_percent = self.Param("StopLossPercent", 1.0).SetRange(0.0, 99.0).SetDisplay("Stop below middle low (%)", "Buffer below the middle candle's low; zero places the stop at that low", "Protection")
self._clear_state()
@property
def candle_type(self):
return self._candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.candle_type), (self.Security, DataType.Level1)]
def _clear_state(self):
self._recent = []
self._stop_price = None
self._target_price = None
self._entry_order = None
self._exit_order = None
def OnReseted(self):
super(morning_star_strategy, self).OnReseted()
self._clear_state()
def OnStarted2(self, time):
super(morning_star_strategy, self).OnStarted2(time)
self._clear_state()
bids = Subscription(DataType.Level1, self.Security)
bids.MarketData.BuildField = Level1Fields.BestBidPrice
self.SubscribeLevel1(bids).Bind(self._process_bid).Start()
candles = self.SubscribeCandles(self.candle_type)
candles.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, candles)
self.DrawOwnTrades(area)
@staticmethod
def _is_pending(order):
return order is not None and order.State not in (OrderStates.Done, OrderStates.Failed)
def _process_bid(self, message):
if message.Changes.ContainsKey(Level1Fields.BestBidPrice):
bid = message.Changes[Level1Fields.BestBidPrice]
if bid > 0:
self._check_exit(bid, bid)
def _check_exit(self, low, high):
if self.Position <= 0 or self._is_pending(self._exit_order):
return False
# With only a completed bar's range, prefer the adverse stop when both levels touched.
if ((self._stop_price is not None and low <= self._stop_price) or
(self._target_price is not None and high > self._target_price)):
self._exit_order = self.SellMarket(self.Position)
self._recent = []
self._stop_price = None
self._target_price = None
return True
return False
def _append(self, candle):
self._recent.append(candle)
if len(self._recent) > 2:
self._recent.pop(0)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
if self.Position > 0 and self._check_exit(candle.LowPrice, candle.HighPrice):
return
if self._is_pending(self._entry_order) or self._is_pending(self._exit_order):
self._append(candle)
return
if self.Position == 0 and len(self._recent) == 2 and self.IsFormedAndOnlineAndAllowTrading():
first, middle = self._recent
first_body = first.OpenPrice - first.ClosePrice
middle_body = Math.Abs(middle.ClosePrice - middle.OpenPrice)
third_body = candle.ClosePrice - candle.OpenPrice
first_midpoint = (first.HighPrice + first.LowPrice) / Decimal(2)
if (first_body > 0 and middle_body < first_body / Decimal(2) and
third_body >= first_body / Decimal(2) and candle.ClosePrice > first_midpoint):
self._stop_price = middle.LowPrice * (Decimal(1) - Decimal(self._stop_loss_percent.Value) / Decimal(100))
self._target_price = candle.HighPrice
self._entry_order = self.BuyMarket(self.Volume)
self._append(candle)
def CreateClone(self):
return morning_star_strategy()