Bias Sentiment Strength
取引ルール
確定した 15 分足で MACD(12,26,9)、Wilder RSI(14)、ストキャスティクス(21,14,14)、Awesome Oscillator(5,34)、Alligator、出来高による偏りを合成します。生の K は 21 本の高安、Ks はその 14 値 SMA、D はさらに 14 値 SMA です。Alligator は中央値の SMMA で、jaw は 13 期間・8 本シフト、teeth は 8・5、lips は 5・3 です。
BASS = 2 * (MACD - Signal) + (RSI - 50) / 5 + 0.15 * (Ks - D) + 0.6 * AO + (Lips - Teeth) + (Teeth - Jaw) + VWMA(30) - SMA(30)。全成分の形成を待ち、既定では最低 47 本の確定足が必要です。不正な設定は明示的に失敗します。
BassThreshold より大きければ買い Volume、-BassThreshold より小さければ売り Volume が目標です。既定の閾値はゼロ。水準を評価するため、損切り後の再エントリーに新たなゼロ交差は不要です。反転数量は Volume + abs(Position) とし、未完了注文は次の注文を抑止します。原生ローカル成行ストップは実約定建玉を StopLossPercent%(既定 1)で全決済します。利確は設定しません。
ネイティブのローカル保護は銘柄の足と購読した価格更新を使用し、距離は実際の新規約定を基準にします。決済は成行で、約定価格は市場の状況と呼値に依存します。
パラメーター
| パラメーター | 既定値 |
|---|---|
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()