Estrategia de Fuerza de Bias y Sentimiento
Esta estrategia agrega múltiples indicadores de momentum y volumen (MACD, RSI, Stochastic, Awesome Oscillator, promedios Alligator y bias de volumen) en un único valor de bias. Se abre una posición larga cuando el bias combinado está por encima de cero y una posición corta cuando está por debajo de cero.
Detalles
- Criterios de entrada:
- Largo: Bias combinado > 0.
- Corto: Bias combinado < 0.
- Largo/Corto: Ambos.
- Criterios de salida: Señal inversa.
- Stops: Porcentaje de stop-loss mediante
StopLossPercent. - Valores predeterminados:
- MACD rápido 12, lento 26, señal 9.
- Período RSI 14.
- Períodos Stochastic 21/14/14.
- Períodos Awesome Oscillator 5/34.
- Longitud de bias de volumen 30.
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: Múltiples
- Stops: Sí
- Complejidad: Complejo
- Marco temporal: Medio plazo
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>
/// Bias and Sentiment Strength (BASS) strategy.
/// Combines several momentum and volume indicators.
/// Enters long when the aggregated bias is positive and short when negative.
/// </summary>
public class BiasSentimentStrengthStrategy : Strategy
{
private readonly StrategyParam<int> _macdFast;
private readonly StrategyParam<int> _macdSlow;
private readonly StrategyParam<int> _macdSignal;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _stochK;
private readonly StrategyParam<int> _stochD;
private readonly StrategyParam<int> _aoShort;
private readonly StrategyParam<int> _aoLong;
private readonly StrategyParam<int> _volumeLength;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _bassThreshold;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevBass;
public int MacdFast { get => _macdFast.Value; set => _macdFast.Value = value; }
public int MacdSlow { get => _macdSlow.Value; set => _macdSlow.Value = value; }
public int MacdSignal { get => _macdSignal.Value; set => _macdSignal.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int StochK { get => _stochK.Value; set => _stochK.Value = value; }
public int StochD { get => _stochD.Value; set => _stochD.Value = value; }
public int AoShort { get => _aoShort.Value; set => _aoShort.Value = value; }
public int AoLong { get => _aoLong.Value; set => _aoLong.Value = value; }
public int VolumeLength { get => _volumeLength.Value; set => _volumeLength.Value = value; }
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
public decimal BassThreshold { get => _bassThreshold.Value; set => _bassThreshold.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public BiasSentimentStrengthStrategy()
{
_macdFast = Param(nameof(MacdFast), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "Fast EMA period for MACD", "Indicators");
_macdSlow = Param(nameof(MacdSlow), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "Slow EMA period for MACD", "Indicators");
_macdSignal = Param(nameof(MacdSignal), 9)
.SetGreaterThanZero()
.SetDisplay("MACD Signal", "Signal period for MACD", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation length", "Indicators");
_stochK = Param(nameof(StochK), 21)
.SetGreaterThanZero()
.SetDisplay("Stochastic K", "%K period for Stochastic", "Indicators");
_stochD = Param(nameof(StochD), 14)
.SetGreaterThanZero()
.SetDisplay("Stochastic D", "%D period for Stochastic", "Indicators");
_aoShort = Param(nameof(AoShort), 5)
.SetGreaterThanZero()
.SetDisplay("AO Short", "Short period for Awesome Oscillator", "Indicators");
_aoLong = Param(nameof(AoLong), 34)
.SetGreaterThanZero()
.SetDisplay("AO Long", "Long period for Awesome Oscillator", "Indicators");
_volumeLength = Param(nameof(VolumeLength), 30)
.SetGreaterThanZero()
.SetDisplay("Volume Bias Length", "Length for VWMA/SMA", "Indicators");
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk Management");
_bassThreshold = Param(nameof(BassThreshold), 70m)
.SetGreaterThanZero()
.SetDisplay("BASS Threshold", "Minimum BASS value for signal", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Time frame for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevBass = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFast },
LongMa = { Length = MacdSlow },
},
SignalMa = { Length = MacdSignal }
};
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var stoch = new StochasticOscillator
{
K = { Length = StochK },
D = { Length = StochD },
};
var ao = new AwesomeOscillator
{
ShortMa = { Length = AoShort },
LongMa = { Length = AoLong }
};
var vwma = new VolumeWeightedMovingAverage { Length = VolumeLength };
var sma = new SimpleMovingAverage { Length = VolumeLength };
var jaw = new SmoothedMovingAverage { Length = 13 };
var teeth = new SmoothedMovingAverage { Length = 8 };
var lips = new SmoothedMovingAverage { Length = 5 };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx([macd, rsi, stoch, ao, vwma, sma, jaw, teeth, lips], ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue[] values)
{
if (candle.State != CandleStates.Finished)
return;
if (values.Length < 9)
return;
for (var i = 0; i < values.Length; i++)
{
if (values[i] is null || !values[i].IsFinal)
return;
}
decimal macdHist, rsiHist, stochHist, aoVal, volumeHist, gatorHist;
try
{
if (values[0] is not IMovingAverageConvergenceDivergenceSignalValue macdTyped)
return;
var macdLine = macdTyped.Macd ?? 0m;
var signalLine = macdTyped.Signal ?? 0m;
macdHist = (macdLine - signalLine) * 2m;
var rsi = values[1].ToDecimal();
rsiHist = (rsi - 50m) / 5m;
if (values[2] is not IStochasticOscillatorValue stochTyped)
return;
if (stochTyped.K is not decimal stochKVal || stochTyped.D is not decimal stochDVal)
return;
stochHist = ((stochKVal - stochDVal) / 10m) * 1.5m;
aoVal = values[3].ToDecimal() * 0.6m;
var vwmaVal = values[4].ToDecimal();
var smaVal = values[5].ToDecimal();
volumeHist = vwmaVal - smaVal;
var jawVal = values[6].ToDecimal();
var teethVal = values[7].ToDecimal();
var lipsVal = values[8].ToDecimal();
gatorHist = (lipsVal - teethVal) + (teethVal - jawVal);
}
catch (Exception)
{
return;
}
var bass = macdHist + rsiHist + stochHist + aoVal + gatorHist + volumeHist;
// Trade on zero crossover
if (bass > 0m && _prevBass <= 0m && Position <= 0)
{
BuyMarket();
}
else if (bass < 0m && _prevBass >= 0m && Position >= 0)
{
SellMarket();
}
_prevBass = bass;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Array
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import (MovingAverageConvergenceDivergenceSignal,
RelativeStrengthIndex, StochasticOscillator, AwesomeOscillator,
VolumeWeightedMovingAverage, SimpleMovingAverage, SmoothedMovingAverage, IIndicator)
from StockSharp.Algo.Strategies import Strategy
class bias_sentiment_strength_strategy(Strategy):
def __init__(self):
super(bias_sentiment_strength_strategy, self).__init__()
self._macd_fast = self.Param("MacdFast", 12) \
.SetDisplay("MACD Fast", "Fast EMA period for MACD", "Indicators")
self._macd_slow = self.Param("MacdSlow", 26) \
.SetDisplay("MACD Slow", "Slow EMA period for MACD", "Indicators")
self._macd_signal = self.Param("MacdSignal", 9) \
.SetDisplay("MACD Signal", "Signal period for MACD", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI calculation length", "Indicators")
self._stoch_k = self.Param("StochK", 21) \
.SetDisplay("Stochastic K", "%K period for Stochastic", "Indicators")
self._stoch_d = self.Param("StochD", 14) \
.SetDisplay("Stochastic D", "%D period for Stochastic", "Indicators")
self._ao_short = self.Param("AoShort", 5) \
.SetDisplay("AO Short", "Short period for Awesome Oscillator", "Indicators")
self._ao_long = self.Param("AoLong", 34) \
.SetDisplay("AO Long", "Long period for Awesome Oscillator", "Indicators")
self._volume_length = self.Param("VolumeLength", 30) \
.SetDisplay("Volume Bias Length", "Length for VWMA/SMA", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Time frame for strategy", "General")
self._prev_bass = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bias_sentiment_strength_strategy, self).OnReseted()
self._prev_bass = 0.0
def OnStarted2(self, time):
super(bias_sentiment_strength_strategy, self).OnStarted2(time)
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self._macd_fast.Value
macd.Macd.LongMa.Length = self._macd_slow.Value
macd.SignalMa.Length = self._macd_signal.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
stoch = StochasticOscillator()
stoch.K.Length = self._stoch_k.Value
stoch.D.Length = self._stoch_d.Value
ao = AwesomeOscillator()
ao.ShortMa.Length = self._ao_short.Value
ao.LongMa.Length = self._ao_long.Value
vwma = VolumeWeightedMovingAverage()
vwma.Length = self._volume_length.Value
sma = SimpleMovingAverage()
sma.Length = self._volume_length.Value
jaw = SmoothedMovingAverage()
jaw.Length = 13
teeth = SmoothedMovingAverage()
teeth.Length = 8
lips = SmoothedMovingAverage()
lips.Length = 5
subscription = self.SubscribeCandles(self.candle_type)
indicators = Array[IIndicator]([macd, rsi, stoch, ao, vwma, sma, jaw, teeth, lips])
subscription.BindEx(indicators, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def OnProcess(self, candle, values):
if candle.State != CandleStates.Finished:
return
if values.Length < 9:
return
for i in range(values.Length):
if values[i] is None or not values[i].IsFinal:
return
try:
macd_val = values[0]
macd_line = float(macd_val.Macd) if macd_val.Macd is not None else 0.0
signal_line = float(macd_val.Signal) if macd_val.Signal is not None else 0.0
macd_hist = (macd_line - signal_line) * 2.0
rsi = float(values[1])
rsi_hist = (rsi - 50.0) / 5.0
stoch_val = values[2]
stoch_k_val = stoch_val.K
stoch_d_val = stoch_val.D
if stoch_k_val is None or stoch_d_val is None:
return
stoch_hist = ((float(stoch_k_val) - float(stoch_d_val)) / 10.0) * 1.5
ao_val = float(values[3]) * 0.6
vwma_val = float(values[4])
sma_val = float(values[5])
volume_hist = vwma_val - sma_val
jaw_val = float(values[6])
teeth_val = float(values[7])
lips_val = float(values[8])
gator_hist = (lips_val - teeth_val) + (teeth_val - jaw_val)
except Exception:
return
bass = macd_hist + rsi_hist + stoch_hist + ao_val + gator_hist + volume_hist
if bass > 0 and self._prev_bass <= 0 and self.Position <= 0:
self.BuyMarket()
elif bass < 0 and self._prev_bass >= 0 and self.Position >= 0:
self.SellMarket()
self._prev_bass = bass
def CreateClone(self):
return bias_sentiment_strength_strategy()