Estrategia de Scalping Nocturno
Esta estrategia opera durante la sesión vespertina usando Bandas de Bollinger. Abre posiciones solo después de una hora de inicio especificada cuando el ancho de banda es estrecho y el precio rompe fuera de las bandas.
Detalles
- Criterios de entrada:
- Largo: después de
Start Hour, el precio cierra por debajo de la Banda de Bollinger inferior y el ancho de banda es menor queRange Threshold. - Corto: después de
Start Hour, el precio cierra por encima de la Banda de Bollinger superior y el ancho de banda es menor queRange Threshold.
- Largo: después de
- Largo/Corto: Ambos.
- Criterios de salida:
- La posición se cierra si el tiempo cae antes de
Start Hourdel día siguiente. - Stop-loss y take-profit protectores gestionados por
StartProtection.
- La posición se cierra si el tiempo cae antes de
- Stops: Usa
StartProtectioncon offsets fijos de stop-loss y take-profit. - Valores predeterminados:
BB Period= 40BB Deviation= 1Range Threshold= 450Stop Loss= 370Take Profit= 20Start Hour= 19Candle Type= 1h
- Filtros:
- Categoría: Reversión a la media
- Dirección: Ambos
- Indicadores: Bollinger Bands
- Stops: Sí
- Complejidad: Bajo
- Marco temporal: Corto plazo
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Night scalping strategy using Bollinger Bands.
/// </summary>
public class NightScalperStrategy : Strategy
{
private const int BufferSize = 128;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<decimal> _rangeThreshold;
private readonly StrategyParam<DataType> _candleType;
private readonly decimal[] _closes = new decimal[BufferSize];
private int _closeIndex;
private int _closeCount;
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
public decimal RangeThreshold
{
get => _rangeThreshold.Value;
set => _rangeThreshold.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public NightScalperStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetDisplay("BB Period", "Bollinger period", "Indicators");
_bollingerDeviation = Param(nameof(BollingerDeviation), 2.0m)
.SetDisplay("BB Deviation", "Bollinger deviation", "Indicators");
_rangeThreshold = Param(nameof(RangeThreshold), 3000m)
.SetDisplay("Range Threshold", "Maximum band width", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
Array.Clear(_closes);
_closeIndex = 0;
_closeCount = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
Array.Clear(_closes);
_closeIndex = 0;
_closeCount = 0;
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
PushClose(candle.ClosePrice);
if (_closeCount < BollingerPeriod)
return;
var mean = GetAverage(BollingerPeriod);
var deviation = GetStandardDeviation(BollingerPeriod, mean);
var upper = mean + (deviation * BollingerDeviation);
var lower = mean - (deviation * BollingerDeviation);
var width = upper - lower;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position == 0 && width <= RangeThreshold)
{
if (candle.LowPrice <= lower)
BuyMarket();
else if (candle.HighPrice >= upper)
SellMarket();
}
else if (Position > 0 && candle.ClosePrice >= mean)
{
SellMarket();
}
else if (Position < 0 && candle.ClosePrice <= mean)
{
BuyMarket();
}
}
private void PushClose(decimal close)
{
_closes[_closeIndex] = close;
_closeIndex = (_closeIndex + 1) % BufferSize;
if (_closeCount < BufferSize)
_closeCount++;
}
private decimal GetAverage(int period)
{
var count = Math.Min(period, _closeCount);
var sum = 0m;
for (var i = 0; i < count; i++)
{
var idx = (_closeIndex - 1 - i + BufferSize) % BufferSize;
sum += _closes[idx];
}
return sum / count;
}
private decimal GetStandardDeviation(int period, decimal mean)
{
var count = Math.Min(period, _closeCount);
var sum = 0m;
for (var i = 0; i < count; i++)
{
var idx = (_closeIndex - 1 - i + BufferSize) % BufferSize;
var diff = _closes[idx] - mean;
sum += diff * diff;
}
return (decimal)Math.Sqrt((double)(sum / count));
}
}
import clr
import math
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class night_scalper_strategy(Strategy):
BUFFER_SIZE = 128
def __init__(self):
super(night_scalper_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("BB Period", "Bollinger period", "Indicators")
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0) \
.SetDisplay("BB Deviation", "Bollinger deviation", "Indicators")
self._range_threshold = self.Param("RangeThreshold", 3000.0) \
.SetDisplay("Range Threshold", "Maximum band width", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._closes = [0.0] * self.BUFFER_SIZE
self._close_index = 0
self._close_count = 0
@property
def bollinger_period(self):
return self._bollinger_period.Value
@property
def bollinger_deviation(self):
return self._bollinger_deviation.Value
@property
def range_threshold(self):
return self._range_threshold.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(night_scalper_strategy, self).OnReseted()
self._closes = [0.0] * self.BUFFER_SIZE
self._close_index = 0
self._close_count = 0
def OnStarted2(self, time):
super(night_scalper_strategy, self).OnStarted2(time)
self._closes = [0.0] * self.BUFFER_SIZE
self._close_index = 0
self._close_count = 0
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _push_close(self, close):
self._closes[self._close_index] = close
self._close_index = (self._close_index + 1) % self.BUFFER_SIZE
if self._close_count < self.BUFFER_SIZE:
self._close_count += 1
def _get_average(self, period):
count = min(period, self._close_count)
s = 0.0
for i in range(count):
idx = (self._close_index - 1 - i + self.BUFFER_SIZE) % self.BUFFER_SIZE
s += self._closes[idx]
return s / count if count > 0 else 0.0
def _get_standard_deviation(self, period, mean):
count = min(period, self._close_count)
s = 0.0
for i in range(count):
idx = (self._close_index - 1 - i + self.BUFFER_SIZE) % self.BUFFER_SIZE
diff = self._closes[idx] - mean
s += diff * diff
return math.sqrt(s / count) if count > 0 else 0.0
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
self._push_close(close)
bp = int(self.bollinger_period)
if self._close_count < bp:
return
mean = self._get_average(bp)
deviation = self._get_standard_deviation(bp, mean)
bd = float(self.bollinger_deviation)
upper = mean + deviation * bd
lower = mean - deviation * bd
width = upper - lower
rt = float(self.range_threshold)
low_price = float(candle.LowPrice)
high_price = float(candle.HighPrice)
if self.Position == 0 and width <= rt:
if low_price <= lower:
self.BuyMarket()
elif high_price >= upper:
self.SellMarket()
elif self.Position > 0 and close >= mean:
self.SellMarket()
elif self.Position < 0 and close <= mean:
self.BuyMarket()
def CreateClone(self):
return night_scalper_strategy()