Estratégia de Scalping do Ouro BOS & CHoCH
Esta estratégia opera padrões de quebra de estrutura (BOS) e mudança de caráter (CHoCH) no ouro. Deriva níveis de suporte e resistência de curto prazo e entra quando um BOS é seguido imediatamente por um CHoCH, utilizando alvos dinâmicos de stop loss e take profit.
Detalhes
- Critérios de entrada:
- Comprado:
High > LastSwingHigheClosecruza acima deLastSwingLow - Vendido:
Low < LastSwingLoweClosecruza abaixo deLastSwingHigh
- Comprado:
- Comprado/Vendido: Ambos os lados
- Critérios de saída: Stop loss ou take profit
- Stops: Dinâmicos
- Valores padrão:
RecentLength= 10SwingLength= 5TakeProfitFactor= 2
- Filtros:
- Categoria: Scalping
- Direção: Ambos
- Indicadores: Highest, Lowest
- Stops: Sim
- Complexidade: Médio
- Período: Curto prazo
- 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;
/// <summary>
/// Gold scalping BOS and CHoCH strategy.
/// The last swing high and low are the highest high and lowest low of the SwingLength candles before the current one. A high above the
/// last swing high (break of structure) together with a close crossing above the last swing low (change of character) goes long; a low
/// below the last swing low with a close crossing below the last swing high goes short. The stop sits at the RecentLength low (high) and
/// the target TakeProfitFactor times that risk away.
/// </summary>
public class GoldScalpingBosChochStrategy : Strategy
{
private readonly StrategyParam<int> _recentLength;
private readonly StrategyParam<int> _swingLength;
private readonly StrategyParam<decimal> _takeProfitFactor;
private readonly StrategyParam<DataType> _candleType;
private decimal? _swingHigh;
private decimal? _swingLow;
private decimal? _prevSwingHigh;
private decimal? _prevSwingLow;
private decimal? _prevClose;
private decimal _stopPrice;
private decimal _takePrice;
/// <summary>
/// Candles used for the stop level.
/// </summary>
public int RecentLength
{
get => _recentLength.Value;
set => _recentLength.Value = value;
}
/// <summary>
/// Candles used for the swing levels.
/// </summary>
public int SwingLength
{
get => _swingLength.Value;
set => _swingLength.Value = value;
}
/// <summary>
/// Target distance as a multiple of the stop distance.
/// </summary>
public decimal TakeProfitFactor
{
get => _takeProfitFactor.Value;
set => _takeProfitFactor.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public GoldScalpingBosChochStrategy()
{
_recentLength = Param(nameof(RecentLength), 10)
.SetGreaterThanZero()
.SetDisplay("Recent Length", "Candles used for the stop level", "Structure");
_swingLength = Param(nameof(SwingLength), 5)
.SetGreaterThanZero()
.SetDisplay("Swing Length", "Candles used for the swing levels", "Structure");
_takeProfitFactor = Param(nameof(TakeProfitFactor), 2m)
.SetGreaterThanZero()
.SetDisplay("Take Profit Factor", "Target distance as a multiple of the stop distance", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).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();
ResetState();
}
private void ResetState()
{
_swingHigh = null;
_swingLow = null;
_prevSwingHigh = null;
_prevSwingLow = null;
_prevClose = null;
_stopPrice = 0m;
_takePrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var swingHighest = new Highest { Length = SwingLength };
var swingLowest = new Lowest { Length = SwingLength };
var recentHighest = new Highest { Length = RecentLength };
var recentLowest = new Lowest { Length = RecentLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(swingHighest, swingLowest, recentHighest, recentLowest, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal swingHighest, decimal swingLowest, decimal recentHighest, decimal recentLowest)
{
if (candle.State != CandleStates.Finished)
return;
// Swing levels of the candles before this one, and the levels one candle earlier for the cross.
var lastSwingHigh = _swingHigh;
var lastSwingLow = _swingLow;
var prevSwingHigh = _prevSwingHigh;
var prevSwingLow = _prevSwingLow;
var prevClose = _prevClose;
_prevSwingHigh = _swingHigh;
_prevSwingLow = _swingLow;
_swingHigh = swingHighest;
_swingLow = swingLowest;
_prevClose = candle.ClosePrice;
if (ManagePosition(candle))
return;
if (lastSwingHigh is not decimal sh || lastSwingLow is not decimal sl || prevSwingHigh is not decimal psh || prevSwingLow is not decimal psl || prevClose is not decimal pc)
return;
if (!IsFormedAndOnlineAndAllowTrading() || Position != 0)
return;
var close = candle.ClosePrice;
if (candle.HighPrice > sh && pc <= psl && close > sl && recentLowest < close)
{
BuyMarket(Volume);
_stopPrice = recentLowest;
_takePrice = close + (close - recentLowest) * TakeProfitFactor;
}
else if (candle.LowPrice < sl && pc >= psh && close < sh && recentHighest > close)
{
SellMarket(Volume);
_stopPrice = recentHighest;
_takePrice = close - (recentHighest - close) * TakeProfitFactor;
}
}
// Returns true when the position was closed on this candle.
private bool ManagePosition(ICandleMessage candle)
{
if (Position > 0 && _stopPrice > 0)
{
if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _takePrice)
{
SellMarket(Position);
return true;
}
}
else if (Position < 0 && _stopPrice > 0)
{
if (candle.HighPrice >= _stopPrice || candle.LowPrice <= _takePrice)
{
BuyMarket(Math.Abs(Position));
return true;
}
}
return false;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class gold_scalping_bos_choch_strategy(Strategy):
"""
Gold scalping BOS and CHoCH strategy.
The last swing high and low are the highest high and lowest low of the SwingLength candles before the current one. A high above the
last swing high (break of structure) together with a close crossing above the last swing low (change of character) goes long; a low
below the last swing low with a close crossing below the last swing high goes short. The stop sits at the RecentLength low (high) and
the target TakeProfitFactor times that risk away.
"""
def __init__(self):
super(gold_scalping_bos_choch_strategy, self).__init__()
self._recent_length = self.Param("RecentLength", 10).SetGreaterThanZero().SetDisplay("Recent Length", "Candles used for the stop level", "Structure")
self._swing_length = self.Param("SwingLength", 5).SetGreaterThanZero().SetDisplay("Swing Length", "Candles used for the swing levels", "Structure")
self._take_profit_factor = self.Param("TakeProfitFactor", 2.0).SetGreaterThanZero().SetDisplay("Take Profit Factor", "Target distance as a multiple of the stop distance", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._swing_high = None
self._swing_low = None
self._prev_swing_high = None
self._prev_swing_low = None
self._prev_close = None
self._stop_price = Decimal(0)
self._take_price = Decimal(0)
def OnReseted(self):
super(gold_scalping_bos_choch_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(gold_scalping_bos_choch_strategy, self).OnStarted2(time)
self._reset_state()
swing_highest = Highest()
swing_highest.Length = self._swing_length.Value
swing_lowest = Lowest()
swing_lowest.Length = self._swing_length.Value
recent_highest = Highest()
recent_highest.Length = self._recent_length.Value
recent_lowest = Lowest()
recent_lowest.Length = self._recent_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(swing_highest, swing_lowest, recent_highest, recent_lowest, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle, swing_highest, swing_lowest, recent_highest, recent_lowest):
if candle.State != CandleStates.Finished:
return
# Swing levels of the candles before this one, and the levels one candle earlier for the cross.
last_swing_high = self._swing_high
last_swing_low = self._swing_low
prev_swing_high = self._prev_swing_high
prev_swing_low = self._prev_swing_low
prev_close = self._prev_close
self._prev_swing_high = self._swing_high
self._prev_swing_low = self._swing_low
self._swing_high = swing_highest
self._swing_low = swing_lowest
self._prev_close = candle.ClosePrice
if self._manage_position(candle):
return
if last_swing_high is None or last_swing_low is None or prev_swing_high is None or prev_swing_low is None or prev_close is None:
return
if not self.IsFormedAndOnlineAndAllowTrading() or self.Position != 0:
return
close = candle.ClosePrice
factor = Decimal(self._take_profit_factor.Value)
if candle.HighPrice > last_swing_high and prev_close <= prev_swing_low and close > last_swing_low and recent_lowest < close:
self.BuyMarket(self.Volume)
self._stop_price = recent_lowest
self._take_price = close + (close - recent_lowest) * factor
elif candle.LowPrice < last_swing_low and prev_close >= prev_swing_high and close < last_swing_high and recent_highest > close:
self.SellMarket(self.Volume)
self._stop_price = recent_highest
self._take_price = close - (recent_highest - close) * factor
def _manage_position(self, candle):
if self.Position > 0 and self._stop_price > 0:
if candle.LowPrice <= self._stop_price or candle.HighPrice >= self._take_price:
self.SellMarket(self.Position)
return True
elif self.Position < 0 and self._stop_price > 0:
if candle.HighPrice >= self._stop_price or candle.LowPrice <= self._take_price:
self.BuyMarket(abs(self.Position))
return True
return False
def CreateClone(self):
return gold_scalping_bos_choch_strategy()