Bias Sentiment Strength
Regras de negociação
Em velas concluídas de 15 minutos, combinam-se MACD(12,26,9), RSI Wilder(14), estocástico(21,14,14), Awesome Oscillator(5,34), Alligator e viés por volume. K bruto usa extremos de 21 barras; Ks é sua SMA de 14 valores e D outra SMA de 14. Alligator usa SMMAs do preço mediano: mandíbula 13 deslocada 8, dentes 8 deslocados 5 e lábios 5 deslocados 3.
BASS = 2 * (MACD - Signal) + (RSI - 50) / 5 + 0.15 * (Ks - D) + 0.6 * AO + (Lips - Teeth) + (Teeth - Jaw) + VWMA(30) - SMA(30). Todos os componentes devem estar formados; por padrão são necessárias pelo menos 47 barras completas. Configuração inválida falha explicitamente.
Acima de BassThreshold, o alvo é comprado Volume; abaixo de -BassThreshold, vendido Volume. O limiar padrão é zero. Usam-se níveis, permitindo nova entrada após stop sem novo cruzamento do zero. A reversão usa Volume + abs(Position); ordem pendente bloqueia outra. O stop nativo local a mercado fecha toda a exposição executada a StopLossPercent por cento, padrão 1. Não há take-profit.
A proteção local nativa recebe velas e atualizações de preço assinadas do instrumento. As distâncias partem das execuções reais de entrada. As saídas são a mercado; o preço depende do mercado disponível e do passo de preço.
Parâmetros
| Parâmetro | Padrão |
|---|---|
MacdFast |
12 |
MacdSlow |
26 |
MacdSignal |
9 |
RsiPeriod |
14 |
StochK |
21 |
StochSmooth |
14 |
StochD |
14 |
AoShort |
5 |
AoLong |
34 |
VolumeLength |
30 |
BassThreshold |
0 |
StopLossPercent |
1 |
CandleType |
15m |
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using System.Linq;
using Ecng.Common;
using StockSharp.Algo;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>Complete MACD, RSI, smoothed stochastic, AO, Alligator and volume bias with native protection.</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> _stochSmooth;
private readonly StrategyParam<int> _stochD;
private readonly StrategyParam<int> _aoShort;
private readonly StrategyParam<int> _aoLong;
private readonly StrategyParam<int> _volumeLength;
private readonly StrategyParam<decimal> _bassThreshold;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private SimpleMovingAverage _smoothK, _smoothD;
private Order _pending;
/// <summary>Fast MACD EMA length.</summary>
public int MacdFast
{
get => _macdFast.Value;
set => _macdFast.Value = value;
}
/// <summary>Slow MACD EMA length.</summary>
public int MacdSlow
{
get => _macdSlow.Value;
set => _macdSlow.Value = value;
}
/// <summary>MACD signal EMA length.</summary>
public int MacdSignal
{
get => _macdSignal.Value;
set => _macdSignal.Value = value;
}
/// <summary>Wilder RSI length.</summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>Raw stochastic high-low window.</summary>
public int StochK
{
get => _stochK.Value;
set => _stochK.Value = value;
}
/// <summary>Stochastic K smoothing length.</summary>
public int StochSmooth
{
get => _stochSmooth.Value;
set => _stochSmooth.Value = value;
}
/// <summary>Smoothed stochastic D length.</summary>
public int StochD
{
get => _stochD.Value;
set => _stochD.Value = value;
}
/// <summary>Short median-price SMA length.</summary>
public int AoShort
{
get => _aoShort.Value;
set => _aoShort.Value = value;
}
/// <summary>Long median-price SMA length.</summary>
public int AoLong
{
get => _aoLong.Value;
set => _aoLong.Value = value;
}
/// <summary>Close VWMA and SMA length.</summary>
public int VolumeLength
{
get => _volumeLength.Value;
set => _volumeLength.Value = value;
}
/// <summary>Minimum absolute aggregate bias.</summary>
public decimal BassThreshold
{
get => _bassThreshold.Value;
set => _bassThreshold.Value = value;
}
/// <summary>Native filled-entry percentage stop.</summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>Finished signal candle interval.</summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>Latest fully formed aggregate bias.</summary>
public decimal? LastBass { get; private set; }
/// <summary>Initializes the published indicator lengths, zero bias threshold and percent stop.</summary>
public BiasSentimentStrengthStrategy()
{
_macdFast = Param(nameof(MacdFast), 12).SetGreaterThanZero()
.SetDisplay("MacdFast", "Fast MACD EMA length", "Parameters");
_macdSlow = Param(nameof(MacdSlow), 26).SetGreaterThanZero()
.SetDisplay("MacdSlow", "Slow MACD EMA length", "Parameters");
_macdSignal = Param(nameof(MacdSignal), 9).SetGreaterThanZero()
.SetDisplay("MacdSignal", "MACD signal EMA length", "Parameters");
_rsiPeriod = Param(nameof(RsiPeriod), 14).SetGreaterThanZero()
.SetDisplay("RsiPeriod", "Wilder RSI length", "Parameters");
_stochK = Param(nameof(StochK), 21).SetGreaterThanZero()
.SetDisplay("StochK", "Raw stochastic high-low window", "Parameters");
_stochSmooth = Param(nameof(StochSmooth), 14).SetGreaterThanZero()
.SetDisplay("StochSmooth", "Stochastic K smoothing length", "Parameters");
_stochD = Param(nameof(StochD), 14).SetGreaterThanZero()
.SetDisplay("StochD", "Smoothed stochastic D length", "Parameters");
_aoShort = Param(nameof(AoShort), 5).SetGreaterThanZero()
.SetDisplay("AoShort", "Short median-price SMA length", "Parameters");
_aoLong = Param(nameof(AoLong), 34).SetGreaterThanZero()
.SetDisplay("AoLong", "Long median-price SMA length", "Parameters");
_volumeLength = Param(nameof(VolumeLength), 30).SetGreaterThanZero()
.SetDisplay("VolumeLength", "Close VWMA and SMA length", "Parameters");
_bassThreshold = Param(nameof(BassThreshold), 0m).SetRange(0m, decimal.MaxValue)
.SetDisplay("BassThreshold", "Minimum absolute aggregate bias", "Parameters");
_stopLossPercent = Param(nameof(StopLossPercent), 1m).SetGreaterThanZero()
.SetDisplay("StopLossPercent", "Native filled-entry percentage stop", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("CandleType", "Finished signal candle interval", "Parameters");
OrderRegistering += order => _pending = order;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType), (Security, DataType.Level1)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_smoothK = _smoothD = null;
_pending = null;
LastBass = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
if (MacdFast >= MacdSlow || AoShort >= AoLong)
throw new InvalidOperationException("Fast MACD and AO lengths must be shorter than their slow lengths.");
base.OnStarted2(time);
_smoothK = new SimpleMovingAverage { Length = StochSmooth };
_smoothD = new SimpleMovingAverage { Length = StochD };
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd = { ShortMa = { Length = MacdFast }, LongMa = { Length = MacdSlow } },
SignalMa = { Length = MacdSignal },
};
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var stochastic = new StochasticK { Length = StochK };
var ao = new AwesomeOscillator { ShortMa = { Length = AoShort }, LongMa = { Length = AoLong } };
var vwma = new VolumeWeightedMovingAverage { Length = VolumeLength };
var sma = new SimpleMovingAverage { Length = VolumeLength };
var alligator = new Alligator();
StartProtection(new Unit(), StopLossPercent.Percents(), useMarketOrders: true, isLocalStop: true);
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quote = new Subscription(DataType.Level1, Security);
quote.MarketData.BuildField = field;
SubscribeLevel1(quote).Start();
}
var candles = SubscribeCandles(CandleType);
candles.BindEx([macd, rsi, stochastic, ao, vwma, sma, alligator], ProcessCandle).Start();
var area = CreateChartArea();
if (area is not null)
{
DrawCandles(area, candles);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue[] values)
{
if (candle.State != CandleStates.Finished || !values[2].IsFormed || values[2].IsEmpty)
return;
var smoothed = _smoothK.Process(new DecimalIndicatorValue(_smoothK, values[2].GetValue<decimal>(), candle.OpenTime) { IsFinal = true });
if (!_smoothK.IsFormed) return;
var averageD = _smoothD.Process(new DecimalIndicatorValue(_smoothD, smoothed.GetValue<decimal>(), candle.OpenTime) { IsFinal = true });
if (!_smoothD.IsFormed || !values.All(v => v.IsFormed && !v.IsEmpty)
|| values[0] is not IMovingAverageConvergenceDivergenceSignalValue macd
|| macd.Macd is not decimal line || macd.Signal is not decimal signal
|| values[6] is not IAlligatorValue gator || gator.Jaw is not decimal jaw
|| gator.Teeth is not decimal teeth || gator.Lips is not decimal lips)
return;
var bass = (line - signal) * 2m + (values[1].GetValue<decimal>() - 50m) / 5m
+ (smoothed.GetValue<decimal>() - averageD.GetValue<decimal>()) * 0.15m
+ values[3].GetValue<decimal>() * 0.6m + (lips - teeth) + (teeth - jaw)
+ values[4].GetValue<decimal>() - values[5].GetValue<decimal>();
LastBass = bass;
if (!IsFormedAndOnlineAndAllowTrading() || _pending is not null && _pending.State is not (OrderStates.Done or OrderStates.Failed))
return;
if (bass > BassThreshold && Position <= 0m)
BuyMarket(Volume + Math.Abs(Position));
else if (bass < -BassThreshold && Position >= 0m)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
import math
from collections import deque
from System import TimeSpan, DateTime, DateTimeKind, Decimal, Nullable
from StockSharp.Messages import DataType, CandleStates, Sides, OrderStates, Unit, UnitTypes
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Strategies import Strategy
from System import Array
from StockSharp.Messages import Level1Fields
from StockSharp.Algo.Indicators import (MovingAverageConvergenceDivergenceSignal, RelativeStrengthIndex,
StochasticK, AwesomeOscillator, VolumeWeightedMovingAverage, SimpleMovingAverage, Alligator,
IIndicator, DecimalIndicatorValue)
class bias_sentiment_strength_strategy(Strategy):
def __init__(self):
super(bias_sentiment_strength_strategy, self).__init__()
self._macd_fast = self.Param("MacdFast", 12).SetGreaterThanZero().SetDisplay(
"MacdFast", "Fast MACD EMA length", "Parameters")
self._macd_slow = self.Param("MacdSlow", 26).SetGreaterThanZero().SetDisplay(
"MacdSlow", "Slow MACD EMA length", "Parameters")
self._macd_signal = self.Param("MacdSignal", 9).SetGreaterThanZero().SetDisplay(
"MacdSignal", "MACD signal EMA length", "Parameters")
self._rsi_period = self.Param("RsiPeriod", 14).SetGreaterThanZero().SetDisplay(
"RsiPeriod", "Wilder RSI length", "Parameters")
self._stoch_k = self.Param("StochK", 21).SetGreaterThanZero().SetDisplay(
"StochK", "Raw stochastic high-low window", "Parameters")
self._stoch_smooth = self.Param("StochSmooth", 14).SetGreaterThanZero().SetDisplay(
"StochSmooth", "Stochastic K smoothing length", "Parameters")
self._stoch_d = self.Param("StochD", 14).SetGreaterThanZero().SetDisplay(
"StochD", "Smoothed stochastic D length", "Parameters")
self._ao_short = self.Param("AoShort", 5).SetGreaterThanZero().SetDisplay(
"AoShort", "Short median-price SMA length", "Parameters")
self._ao_long = self.Param("AoLong", 34).SetGreaterThanZero().SetDisplay(
"AoLong", "Long median-price SMA length", "Parameters")
self._volume_length = self.Param("VolumeLength", 30).SetGreaterThanZero().SetDisplay(
"VolumeLength", "Close VWMA and SMA length", "Parameters")
self._bass_threshold = self.Param("BassThreshold", 0.0).SetRange(0.0, float(Decimal.MaxValue)).SetDisplay(
"BassThreshold", "Minimum absolute aggregate bias", "Parameters")
self._stop_loss_percent = self.Param("StopLossPercent", 1.0).SetGreaterThanZero().SetDisplay(
"StopLossPercent", "Native filled-entry percentage stop", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay(
"CandleType", "Finished signal candle interval", "Parameters")
self._pending = None
self._smooth_k = self._smooth_d = None
self._last_bass = None
self.OrderRegistering += self._remember_order
@property
def MacdFast(self):
return self._macd_fast.Value
@MacdFast.setter
def MacdFast(self, value):
self._macd_fast.Value = value
@property
def MacdSlow(self):
return self._macd_slow.Value
@MacdSlow.setter
def MacdSlow(self, value):
self._macd_slow.Value = value
@property
def MacdSignal(self):
return self._macd_signal.Value
@MacdSignal.setter
def MacdSignal(self, value):
self._macd_signal.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def StochK(self):
return self._stoch_k.Value
@StochK.setter
def StochK(self, value):
self._stoch_k.Value = value
@property
def StochSmooth(self):
return self._stoch_smooth.Value
@StochSmooth.setter
def StochSmooth(self, value):
self._stoch_smooth.Value = value
@property
def StochD(self):
return self._stoch_d.Value
@StochD.setter
def StochD(self, value):
self._stoch_d.Value = value
@property
def AoShort(self):
return self._ao_short.Value
@AoShort.setter
def AoShort(self, value):
self._ao_short.Value = value
@property
def AoLong(self):
return self._ao_long.Value
@AoLong.setter
def AoLong(self, value):
self._ao_long.Value = value
@property
def VolumeLength(self):
return self._volume_length.Value
@VolumeLength.setter
def VolumeLength(self, value):
self._volume_length.Value = value
@property
def BassThreshold(self):
return self._bass_threshold.Value
@BassThreshold.setter
def BassThreshold(self, value):
self._bass_threshold.Value = value
@property
def StopLossPercent(self):
return self._stop_loss_percent.Value
@StopLossPercent.setter
def StopLossPercent(self, value):
self._stop_loss_percent.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def LastBass(self):
return self._last_bass
def _remember_order(self, order):
self._pending = order
def OnReseted(self):
super(bias_sentiment_strength_strategy, self).OnReseted()
self._pending = None
self._smooth_k = self._smooth_d = None
self._last_bass = None
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType), (self.Security, DataType.Level1)]
def OnStarted2(self, time):
if self.MacdFast >= self.MacdSlow or self.AoShort >= self.AoLong:
raise ValueError("Fast MACD and AO lengths must be shorter than their slow lengths.")
super(bias_sentiment_strength_strategy, self).OnStarted2(time)
self._smooth_k, self._smooth_d = SimpleMovingAverage(), SimpleMovingAverage()
self._smooth_k.Length, self._smooth_d.Length = self.StochSmooth, self.StochD
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length, macd.Macd.LongMa.Length, macd.SignalMa.Length = self.MacdFast, self.MacdSlow, self.MacdSignal
rsi, stochastic, ao = RelativeStrengthIndex(), StochasticK(), AwesomeOscillator()
rsi.Length, stochastic.Length = self.RsiPeriod, self.StochK
ao.ShortMa.Length, ao.LongMa.Length = self.AoShort, self.AoLong
vwma, sma, gator = VolumeWeightedMovingAverage(), SimpleMovingAverage(), Alligator()
vwma.Length = sma.Length = self.VolumeLength
self.StartProtection(Unit(), Unit(float(self.StopLossPercent), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quote = Subscription(DataType.Level1, self.Security)
quote.MarketData.BuildField = field
self.SubscribeLevel1(quote).Start()
candles = self.SubscribeCandles(self.CandleType)
candles.BindEx(Array[IIndicator]([macd, rsi, stochastic, ao, vwma, sma, gator]), self._process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, candles)
self.DrawOwnTrades(area)
def _process(self, candle, values):
if candle.State != CandleStates.Finished or not values[2].IsFormed or values[2].IsEmpty:
return
raw = DecimalIndicatorValue(self._smooth_k, values[2].GetValue[Decimal](None), candle.OpenTime)
raw.IsFinal = True
smooth = self._smooth_k.Process(raw)
if not self._smooth_k.IsFormed:
return
smooth_input = DecimalIndicatorValue(self._smooth_d, smooth.GetValue[Decimal](None), candle.OpenTime)
smooth_input.IsFinal = True
average = self._smooth_d.Process(smooth_input)
if not self._smooth_d.IsFormed or not all(v.IsFormed and not v.IsEmpty for v in values):
return
macd, gator = values[0], values[6]
if macd.Macd is None or macd.Signal is None or gator.Jaw is None or gator.Teeth is None or gator.Lips is None:
return
bass = (macd.Macd - macd.Signal) * Decimal(2) + (values[1].GetValue[Decimal](None) - Decimal(50)) / Decimal(5)
bass += (smooth.GetValue[Decimal](None) - average.GetValue[Decimal](None)) * Decimal(0.15)
bass += values[3].GetValue[Decimal](None) * Decimal(0.6)
bass += (gator.Lips - gator.Teeth) + (gator.Teeth - gator.Jaw)
bass += values[4].GetValue[Decimal](None) - values[5].GetValue[Decimal](None)
self._last_bass = bass
if not self.IsFormedAndOnlineAndAllowTrading() or (self._pending is not None and self._pending.State not in (OrderStates.Done, OrderStates.Failed)):
return
threshold = Decimal(float(self.BassThreshold))
if bass > threshold and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif bass < -threshold and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return bias_sentiment_strength_strategy()