Estratégia de Compra e Venda com Padrão Envolvente de Alta
Esta estratégia entra comprado quando uma vela de alta envolve completamente a barra de baixa anterior e condições de tendência opcionais são atendidas. O tamanho da posição é uma porcentagem do capital atual, enquanto o take profit e o stop loss fecham as operações automaticamente.
Detalhes
- Critérios de entrada: Padrão envolvente de alta com filtro de tendência SMA opcional.
- Comprado/Vendido: Somente comprado.
- Critérios de saída: Take profit ou stop loss.
- Stops: Sim, tanto take profit quanto stop loss.
- Valores padrão:
CandleType= 15 minuteTakeProfitPercent= 2StopLossPercent= 2OrderPercent= 30TrendMode= SMA50
- Filtros:
- Categoria: Padrão
- Direção: Somente comprado
- Indicadores: Candlestick, SMA
- Stops: Sim
- Complexidade: Básico
- Período: Intradiário
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Médio
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()