mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-24 05:28:05 +00:00
Bollinger Bands® with validation tests
This commit is contained in:
@@ -158,7 +158,7 @@ public abstract class Single_TBars_Indicator : TSeries
|
|||||||
for (int i = 0; i < data.Count; i++) { base.Add(TValue: data[i], update: false); }
|
for (int i = 0; i < data.Count; i++) { base.Add(TValue: data[i], update: false); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public new void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar)
|
public void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar)
|
||||||
=> this.Add(TBar: TBar, update: false);
|
=> this.Add(TBar: TBar, update: false);
|
||||||
public void Add(bool update)
|
public void Add(bool update)
|
||||||
=> this.Add(TBar: this._bars[this._bars.Count - 1], update: update);
|
=> this.Add(TBar: this._bars[this._bars.Count - 1], update: update);
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
namespace QuanTAlib;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
/* <summary>
|
||||||
|
BBANDS: Bollinger Bands®
|
||||||
|
Price channels created by John Bollinger, depict volatility as standard deviation boundary
|
||||||
|
line range from a moving average of price. The bands automatically widen when volatility
|
||||||
|
increases and contract when volatility decreases. Their dynamic nature allows them to be
|
||||||
|
used on different securities with the standard settings.
|
||||||
|
|
||||||
|
Mid Band = simple moving average (SMA)
|
||||||
|
Upper Band = SMA + (standard deviation of price x multiplier)
|
||||||
|
Lower Band = SMA - (standard deviation of price x multiplier)
|
||||||
|
Bandwidth = Width of the channel: (Upper-Lower)/SMA
|
||||||
|
%B = The location of the data point within the channel: (Price-Lower)/(Upper/Lower)
|
||||||
|
Z-Score = number of standard deviations of the data point from SMA
|
||||||
|
|
||||||
|
Sources:
|
||||||
|
https://www.investopedia.com/terms/b/bollingerbands.asp
|
||||||
|
https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Bollinger Bands® is a registered trademark of John A. Bollinger.
|
||||||
|
|
||||||
|
</summary> */
|
||||||
|
|
||||||
|
public class BBANDS_Series : Single_TSeries_Indicator
|
||||||
|
{
|
||||||
|
public SMA_Series Mid { get; }
|
||||||
|
public ADD_Series Upper { get; }
|
||||||
|
public SUB_Series Lower { get; }
|
||||||
|
public DIV_Series PercentB { get; }
|
||||||
|
public DIV_Series Bandwidth { get; }
|
||||||
|
public DIV_Series Zscore { get; }
|
||||||
|
|
||||||
|
private readonly SDEV_Series _sdev;
|
||||||
|
private readonly MUL_Series _mulsdev;
|
||||||
|
private readonly SUB_Series _pbdnd;
|
||||||
|
private readonly SUB_Series _pbdvr;
|
||||||
|
private readonly SUB_Series _zdnd;
|
||||||
|
|
||||||
|
public BBANDS_Series(TSeries source, int period = 26, double multiplier = 2.0, bool useNaN = false)
|
||||||
|
: base(source, period: 0, useNaN)
|
||||||
|
{
|
||||||
|
this.Mid = new(source: source, period: period, useNaN: useNaN);
|
||||||
|
|
||||||
|
_sdev = new(source, period, useNaN: useNaN);
|
||||||
|
_mulsdev = new(_sdev, multiplier);
|
||||||
|
this.Upper = new(Mid, _mulsdev);
|
||||||
|
this.Lower = new(Mid, _mulsdev);
|
||||||
|
|
||||||
|
_pbdnd = new(source, Lower);
|
||||||
|
_pbdvr = new(Upper, Lower);
|
||||||
|
|
||||||
|
this.PercentB = new(_pbdnd, _pbdvr);
|
||||||
|
this.Bandwidth = new(_pbdvr, Mid);
|
||||||
|
|
||||||
|
_zdnd = new(source, Mid);
|
||||||
|
this.Zscore = new(_zdnd, _sdev);
|
||||||
|
|
||||||
|
if (source.Count > 0)
|
||||||
|
{ base.Add(this.Bandwidth); }
|
||||||
|
}
|
||||||
|
public override void Add((System.DateTime t, double v) TValue, bool update)
|
||||||
|
{
|
||||||
|
double _bbandwidth;
|
||||||
|
if (update)
|
||||||
|
{ _sdev.Add(TValue, true); }
|
||||||
|
_bbandwidth = this.Bandwidth[(this.Count < this.Bandwidth.Count) ? this.Count : this.Bandwidth.Count - 1].v;
|
||||||
|
var result = (TValue.t, _bbandwidth);
|
||||||
|
base.Add(result, update);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>0.1.15</Version>
|
<Version>0.1.16</Version>
|
||||||
<releaseNotes>
|
<releaseNotes>
|
||||||
</releaseNotes>
|
</releaseNotes>
|
||||||
<Title>QuanTAlib</Title>
|
<Title>QuanTAlib</Title>
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using Xunit;
|
||||||
|
using System;
|
||||||
|
using QuanTAlib;
|
||||||
|
|
||||||
|
namespace MovingAvg;
|
||||||
|
public class BBANDS_Test
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Add_Test()
|
||||||
|
{
|
||||||
|
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
|
||||||
|
BBANDS_Series c = new(a, 4,2.5);
|
||||||
|
Assert.Equal(6, c.Count);
|
||||||
|
a.Add(5);
|
||||||
|
Assert.Equal(a.Count, c.Count);
|
||||||
|
Assert.Equal(a.Count, c.Mid.Count);
|
||||||
|
Assert.Equal(a.Count, c.Upper.Count);
|
||||||
|
Assert.Equal(a.Count, c.Lower.Count);
|
||||||
|
Assert.Equal(a.Count, c.PercentB.Count);
|
||||||
|
Assert.Equal(a.Count, c.Zscore.Count);
|
||||||
|
Assert.Equal(a.Count, c.Bandwidth.Count);
|
||||||
|
|
||||||
|
a.Add(0, update: true);
|
||||||
|
Assert.Equal(a.Count, c.Count);
|
||||||
|
Assert.Equal(a.Count, c.Mid.Count);
|
||||||
|
Assert.Equal(a.Count, c.Upper.Count);
|
||||||
|
Assert.Equal(a.Count, c.Lower.Count);
|
||||||
|
Assert.Equal(a.Count, c.PercentB.Count);
|
||||||
|
Assert.Equal(a.Count, c.Zscore.Count);
|
||||||
|
Assert.Equal(a.Count, c.Bandwidth.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Edge_Test()
|
||||||
|
{
|
||||||
|
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
|
||||||
|
BBANDS_Series c = new(a, 4, 2.5);
|
||||||
|
Assert.Equal(a.Count, c.Count);
|
||||||
|
a.Add(double.NaN);
|
||||||
|
Assert.Equal(a.Count, c.Count);
|
||||||
|
Assert.Equal(a.Count, c.Mid.Count);
|
||||||
|
Assert.Equal(a.Count, c.Upper.Count);
|
||||||
|
Assert.Equal(a.Count, c.Lower.Count);
|
||||||
|
Assert.Equal(a.Count, c.PercentB.Count);
|
||||||
|
Assert.Equal(a.Count, c.Zscore.Count);
|
||||||
|
Assert.Equal(a.Count, c.Bandwidth.Count);
|
||||||
|
a.Add(double.PositiveInfinity);
|
||||||
|
Assert.Equal(a.Count, c.Count);
|
||||||
|
Assert.Equal(a.Count, c.Mid.Count);
|
||||||
|
Assert.Equal(a.Count, c.Upper.Count);
|
||||||
|
Assert.Equal(a.Count, c.Lower.Count);
|
||||||
|
Assert.Equal(a.Count, c.PercentB.Count);
|
||||||
|
Assert.Equal(a.Count, c.Zscore.Count);
|
||||||
|
Assert.Equal(a.Count, c.Bandwidth.Count);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -160,9 +160,25 @@ public class Skender_Stock
|
|||||||
var SK = this.quotes.GetMacd(12,26,9);
|
var SK = this.quotes.GetMacd(12,26,9);
|
||||||
|
|
||||||
Assert.Equal(Math.Round((double)SK.Last().Macd!, 8), Math.Round(QL.Last().v, 8));
|
Assert.Equal(Math.Round((double)SK.Last().Macd!, 8), Math.Round(QL.Last().v, 8));
|
||||||
|
Assert.Equal(Math.Round((double)SK.Last().Signal!, 8), Math.Round(QL.Signal.Last().v, 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
public void BBANDS()
|
||||||
|
{
|
||||||
|
BBANDS_Series QL = new(this.bars.Close, this.period, 2.0, useNaN: false);
|
||||||
|
var SK = this.quotes.GetBollingerBands(this.period, 2.0);
|
||||||
|
|
||||||
|
Assert.Equal(Math.Round((double)SK.Last().Sma!, 8), Math.Round(QL.Mid.Last().v, 8));
|
||||||
|
Assert.Equal(Math.Round((double)SK.Last().UpperBand!, 8), Math.Round(QL.Upper.Last().v, 8));
|
||||||
|
Assert.Equal(Math.Round((double)SK.Last().LowerBand!, 8), Math.Round(QL.Lower.Last().v, 8));
|
||||||
|
Assert.Equal(Math.Round((double)SK.Last().Width!, 8), Math.Round(QL.Bandwidth.Last().v, 8));
|
||||||
|
Assert.Equal(Math.Round((double)SK.Last().PercentB!, 8), Math.Round(QL.PercentB.Last().v, 8));
|
||||||
|
Assert.Equal(Math.Round((double)SK.Last().ZScore!, 8), Math.Round(QL.Zscore.Last().v, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
public void RSI()
|
public void RSI()
|
||||||
{
|
{
|
||||||
RSI_Series QL = new(this.bars.Close, this.period, useNaN: false);
|
RSI_Series QL = new(this.bars.Close, this.period, useNaN: false);
|
||||||
|
|||||||
@@ -164,8 +164,25 @@ public class TA_LIB
|
|||||||
MACD_Series QL = new(this.bars.Close, slow: 26, fast: 12, signal: 9, false);
|
MACD_Series QL = new(this.bars.Close, slow: 26, fast: 12, signal: 9, false);
|
||||||
Core.Macd(this.inclose, 0, this.bars.Count - 1, outMacd: this.TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _);
|
Core.Macd(this.inclose, 0, this.bars.Count - 1, outMacd: this.TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _);
|
||||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8));
|
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8));
|
||||||
|
Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 8), Math.Round(QL.Signal.Last().v, 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BBANDS()
|
||||||
|
{
|
||||||
|
double[] outMiddle = new double[this.bars.Count];
|
||||||
|
double[] outUpper = new double[this.bars.Count];
|
||||||
|
double[] outLower = new double[this.bars.Count];
|
||||||
|
BBANDS_Series QL = new(this.bars.Close, period:26, multiplier:2.0, false);
|
||||||
|
Core.Bbands(this.inclose, 0, this.bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod:26, optInNbDevUp:2.0, optInNbDevDn:2.0);
|
||||||
|
Assert.Equal(Math.Round(outUpper[outUpper.Length - outBegIdx - 1], 8), Math.Round(QL.Upper.Last().v, 8));
|
||||||
|
Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], 8), Math.Round(QL.Mid.Last().v, 8));
|
||||||
|
Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 8), Math.Round(QL.Lower.Last().v, 8));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void HL2()
|
public void HL2()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user