流れ星パターン (Shooting Star Pattern)
流れ星(Shooting Star)の足は上昇後によく現れ、リバーサルを警告します。この戦略は実体に対して長い上ヒゲと、ほとんど下ヒゲのないパターンを探します。
テストでは年平均リターンが約67%となっています。株式市場での運用に最も適しています。
確認が必要な場合、次の足が安値で引けてからショートエントリーします。そうでなければ即座に取引できます。ストップはパターンの高値の上に置かれます。
詳細
- エントリー条件: 流れ星が検出され、有効な場合は確認も取れている。
- ロング/ショート: ショートのみ。
- エグジット条件: ストップロスまたは裁量的なエグジット。
- ストップ: はい。
- デフォルト値:
ShadowToBodyRatio= 2.0mCandleType= TimeSpan.FromMinutes(15)StopLossPercent= 1.0mConfirmationRequired= true
- フィルター:
- カテゴリ: パターン
- 方向: ショートのみ
- インジケーター: Candlestick
- ストップ: はい
- 複雑さ: 中級
- 時間軸: イントラデイ
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// Shooting Star strategy.
/// Enters short on shooting star pattern (long upper shadow, small lower shadow).
/// Enters long on inverted shooting star (long lower shadow, small upper shadow).
/// Exits via SMA crossover.
/// </summary>
public class ShootingStarStrategy : Strategy
{
private readonly StrategyParam<decimal> _shadowToBodyRatio;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private int _cooldown;
/// <summary>
/// Shadow to body ratio.
/// </summary>
public decimal ShadowToBodyRatio
{
get => _shadowToBodyRatio.Value;
set => _shadowToBodyRatio.Value = value;
}
/// <summary>
/// MA Period for exit.
/// </summary>
public int MAPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Type of candles to use.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public ShootingStarStrategy()
{
_shadowToBodyRatio = Param(nameof(ShadowToBodyRatio), 2.0m)
.SetRange(1.5m, 5.0m)
.SetDisplay("Shadow/Body Ratio", "Min ratio of shadow to body", "Pattern");
_maPeriod = Param(nameof(MAPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Period for SMA", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_cooldown = 0;
var sma = new SimpleMovingAverage { Length = MAPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldown > 0)
{
_cooldown--;
return;
}
var bodySize = Math.Abs(candle.OpenPrice - candle.ClosePrice);
var upperShadow = candle.HighPrice - Math.Max(candle.OpenPrice, candle.ClosePrice);
var lowerShadow = Math.Min(candle.OpenPrice, candle.ClosePrice) - candle.LowPrice;
// Shooting star: long upper shadow, small lower shadow (bearish)
var isShootingStar = bodySize > 0 && upperShadow > bodySize * ShadowToBodyRatio && lowerShadow < bodySize * 0.5m;
// Hammer: long lower shadow, small upper shadow (bullish)
var isHammer = bodySize > 0 && lowerShadow > bodySize * ShadowToBodyRatio && upperShadow < bodySize * 0.5m;
if (Position == 0 && isShootingStar && candle.ClosePrice > smaValue)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && isHammer && candle.ClosePrice < smaValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && candle.ClosePrice < smaValue)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && candle.ClosePrice > smaValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class shooting_star_strategy(Strategy):
"""
Shooting Star strategy.
Enters short on shooting star pattern (long upper shadow, small lower shadow).
Enters long on hammer pattern (long lower shadow, small upper shadow).
Exits via SMA crossover.
"""
def __init__(self):
super(shooting_star_strategy, self).__init__()
self._shadow_to_body_ratio = self.Param("ShadowToBodyRatio", 2.0).SetDisplay("Shadow/Body Ratio", "Min ratio of shadow to body", "Pattern")
self._ma_period = self.Param("MAPeriod", 20).SetDisplay("MA Period", "Period for SMA", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(shooting_star_strategy, self).OnReseted()
self._cooldown = 0
def OnStarted2(self, time):
super(shooting_star_strategy, self).OnStarted2(time)
self._cooldown = 0
sma = SimpleMovingAverage()
sma.Length = self._ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, sma_val):
if candle.State != CandleStates.Finished:
return
if self._cooldown > 0:
self._cooldown -= 1
return
body_size = abs(float(candle.OpenPrice) - float(candle.ClosePrice))
upper_shadow = float(candle.HighPrice) - max(float(candle.OpenPrice), float(candle.ClosePrice))
lower_shadow = min(float(candle.OpenPrice), float(candle.ClosePrice)) - float(candle.LowPrice)
ratio = float(self._shadow_to_body_ratio.Value)
# Shooting star: long upper shadow, small lower shadow (bearish)
is_shooting_star = body_size > 0 and upper_shadow > body_size * ratio and lower_shadow < body_size * 0.5
# Hammer: long lower shadow, small upper shadow (bullish)
is_hammer = body_size > 0 and lower_shadow > body_size * ratio and upper_shadow < body_size * 0.5
close = float(candle.ClosePrice)
sv = float(sma_val)
cd = self._cooldown_bars.Value
if self.Position == 0 and is_shooting_star and close > sv:
self.SellMarket()
self._cooldown = cd
elif self.Position == 0 and is_hammer and close < sv:
self.BuyMarket()
self._cooldown = cd
elif self.Position > 0 and close < sv:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and close > sv:
self.BuyMarket()
self._cooldown = cd
def CreateClone(self):
return shooting_star_strategy()