買いと売りの強気包み足パターン戦略
この戦略は、強気の陽線が前の陰線を完全に包み込み、オプションのトレンド条件が満たされたときにロングポジションを取ります。ポジションサイズは現在の資産の割合であり、テイクプロフィットとストップロスが自動的にトレードを決済します。
詳細
- エントリー条件: オプションのSMAトレンドフィルターを持つ強気包み足パターン。
- ロング/ショート: ロングのみ。
- エグジット条件: テイクプロフィットまたはストップロス。
- ストップ: はい、テイクプロフィットとストップロスの両方。
- デフォルト値:
CandleType= 15 minuteTakeProfitPercent= 2StopLossPercent= 2OrderPercent= 30TrendMode= SMA50
- フィルター:
- カテゴリ: パターン
- 方向: ロングのみ
- インジケーター: Candlestick, SMA
- ストップ: はい
- 複雑さ: 低
- 時間軸: イントラデイ
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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;
public enum BullishEngulfingTrendMode
{
None,
SMA50,
}
/// <summary>
/// Buys bullish body engulfings, optionally following a below-SMA50 bearish bar.
/// Allocates a percentage of current equity and closes longs through local SL/TP.
/// </summary>
public class BuySellBullishEngulfingStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _orderPercent;
private readonly StrategyParam<BullishEngulfingTrendMode> _trendMode;
private (decimal Open, decimal Close, decimal Sma, bool SmaReady)? _previousBar;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public decimal TakeProfitPercent { get => _takeProfitPercent.Value; set => _takeProfitPercent.Value = value; }
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
public decimal OrderPercent { get => _orderPercent.Value; set => _orderPercent.Value = value; }
public BullishEngulfingTrendMode TrendMode { get => _trendMode.Value; set => _trendMode.Value = value; }
public BuySellBullishEngulfingStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame());
_takeProfitPercent = Param(nameof(TakeProfitPercent), 2m).SetRange(0m, 100m);
_stopLossPercent = Param(nameof(StopLossPercent), 2m).SetRange(0m, 100m);
_orderPercent = Param(nameof(OrderPercent), 30m).SetRange(0m, 100m).SetGreaterThanZero();
_trendMode = Param(nameof(TrendMode), BullishEngulfingTrendMode.SMA50);
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType), (Security, DataType.Level1)];
protected override void OnReseted()
{
base.OnReseted();
_previousBar = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
if (TrendMode is not (BullishEngulfingTrendMode.None or BullishEngulfingTrendMode.SMA50))
throw new ArgumentOutOfRangeException(nameof(TrendMode));
_previousBar = null;
StartProtection(new Unit(TakeProfitPercent, UnitTypes.Percent), new Unit(StopLossPercent, UnitTypes.Percent),
useMarketOrders: true, isLocalStop: true);
var sma = new SimpleMovingAverage { Length = TrendMode == BullishEngulfingTrendMode.SMA50 ? 50 : 1 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(sma, (candle, value) => ProcessCandle(candle, value, sma.IsFormed)).Start();
// Feed real bid updates to the native long-position protection between candle closes.
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = Level1Fields.BestBidPrice;
SubscribeLevel1(quotes).Bind(_ => { }).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
if (TrendMode == BullishEngulfingTrendMode.SMA50)
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue, bool smaReady)
{
if (candle.State != CandleStates.Finished)
return;
var previous = _previousBar;
_previousBar = (candle.OpenPrice, candle.ClosePrice, smaValue, smaReady);
if (previous is not { } bar || Position != 0m || !IsFormedAndOnlineAndAllowTrading())
return;
var engulfing = bar.Open > bar.Close && candle.ClosePrice > candle.OpenPrice
&& candle.OpenPrice <= bar.Close && candle.ClosePrice >= bar.Open;
var trend = TrendMode == BullishEngulfingTrendMode.None || bar.SmaReady && bar.Close < bar.Sma;
if (!engulfing || !trend || candle.ClosePrice <= 0m)
return;
var equity = Portfolio.CurrentValue ?? Portfolio.BeginValue ?? 0m;
var step = Security.VolumeStep ?? 1m;
if (equity <= 0m || step <= 0m)
return;
var volume = equity * OrderPercent / 100m / candle.ClosePrice;
volume = Math.Floor(Math.Min(volume, Security.MaxVolume ?? decimal.MaxValue) / step) * step;
if (volume > 0m && volume >= (Security.MinVolume ?? step))
BuyMarket(volume);
}
}
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, Decimal, Convert, Math
from StockSharp.Messages import DataType, CandleStates, Level1Fields, Unit, UnitTypes
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class buy_sell_bullish_engulfing_strategy(Strategy):
"""Long-only body engulfing, optional prior-bar SMA50 trend, equity sizing and local SL/TP."""
def __init__(self):
super(buy_sell_bullish_engulfing_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15)))
self._take_profit_percent = self.Param("TakeProfitPercent", 2.0).SetRange(0.0, 100.0)
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetRange(0.0, 100.0)
self._order_percent = self.Param("OrderPercent", 30.0).SetRange(0.0, 100.0).SetGreaterThanZero()
self._trend_mode = self.Param("TrendMode", "SMA50")
self._previous_bar = None
def GetWorkingSecurities(self):
return [(self.Security, self._candle_type.Value), (self.Security, DataType.Level1)]
def OnReseted(self):
super(buy_sell_bullish_engulfing_strategy, self).OnReseted()
self._previous_bar = None
def OnStarted2(self, time):
super(buy_sell_bullish_engulfing_strategy, self).OnStarted2(time)
if self._trend_mode.Value not in ("None", "SMA50"):
raise ValueError("TrendMode must be None or SMA50.")
self._previous_bar = None
self.StartProtection(Unit(float(self._take_profit_percent.Value), UnitTypes.Percent),
Unit(float(self._stop_loss_percent.Value), UnitTypes.Percent),
useMarketOrders=True, isLocalStop=True)
sma = SimpleMovingAverage()
sma.Length = 50 if self._trend_mode.Value == "SMA50" else 1
def process(candle, value):
self._process_candle(candle, value, sma.IsFormed)
subscription = self.SubscribeCandles(self._candle_type.Value)
subscription.Bind(sma, process).Start()
# Bid updates drive native long-position protection between finished candles.
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = Level1Fields.BestBidPrice
self.SubscribeLevel1(quotes).Bind(lambda message: None).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
if self._trend_mode.Value == "SMA50":
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, sma_value, sma_ready):
if candle.State != CandleStates.Finished:
return
previous = self._previous_bar
self._previous_bar = (candle.OpenPrice, candle.ClosePrice, sma_value, sma_ready)
if previous is None or self.Position != 0 or not self.IsFormedAndOnlineAndAllowTrading():
return
engulfing = (previous[0] > previous[1] and candle.ClosePrice > candle.OpenPrice and
candle.OpenPrice <= previous[1] and candle.ClosePrice >= previous[0])
trend = (self._trend_mode.Value == "None" or
previous[3] and previous[1] < previous[2])
if not engulfing or not trend or candle.ClosePrice <= 0:
return
equity = self.Portfolio.CurrentValue
if equity is None:
equity = self.Portfolio.BeginValue
step = self.Security.VolumeStep
if step is None:
step = Decimal.One
if equity is None or equity <= 0 or step <= 0:
return
volume = equity * Convert.ToDecimal(self._order_percent.Value) / Decimal(100) / candle.ClosePrice
maximum = self.Security.MaxVolume
if maximum is not None:
volume = Math.Min(volume, maximum)
volume = Math.Floor(volume / step) * step
minimum = self.Security.MinVolume
if minimum is None:
minimum = step
if volume > 0 and volume >= minimum:
self.BuyMarket(volume)
def CreateClone(self):
return buy_sell_bullish_engulfing_strategy()