diff --git a/README.md b/README.md index da7c7ad..3484a7a 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ The following list of indicators are currently supported by this package: - Acceleration Bands - Actual True Range (ATR) -- Bollinger Band Width +- [Bollinger Band Width](volatility/README.md#type-bollingerbandwidth) - [Bollinger Bands](volatility/README.md#type-bollingerbands) - Chandelier Exit - Donchian Channel (DC) @@ -157,6 +157,14 @@ The following [repository implementations](asset/README.md#type-repository) are The [Sync function]() facilitates the synchronization of assets between designated source and target repositories by employing multi-worker concurrency for enhanced efficiency. This function serves the purpose of procuring the most recent snapshots from remote repositories and seamlessly transferring them to local repositories, such as file system repositories. +The `indicator-sync` command line tool also offers the capability of synchronizing data between the Tiingo Repository and the File System Repository. To illustrate its usage, consider the following example command: + +```bash +$ indicator-sync -key $TIINGO_KEY -target /home/user/assets -days 30 +``` + +This command effectively retrieves the most recent snapshots for assets residing within the `/home/user/assets` directory from the Tiingo Repository. In the event that the local asset file is devoid of content, it automatically extends its reach to synchronize 30 days' worth of snapshots, ensuring a comprehensive and up-to-date repository. + ## ⏳ Backtesting The [Backtest functionality](strategy/README.md#type-backtest), using the [Outcome](strategy/README.md#func-outcome), rigorously evaluates the potential performance of the specified strategies applied to a defined set of assets. It generates comprehensive visual representations for each strategy-asset pairing. @@ -172,6 +180,12 @@ if err != nil { } ``` +The `indicator-backtest` command line tool empowers users to conduct comprehensive backtesting of assets residing within a specified repository. This capability encompasses the application of all currently recognized strategies, culminating in the generation of detailed reports within a designated output directory. + +```bash +$ indicator-backtest -repository /home/user/assets -output /home/user/reports -workers 1 +``` + ## Usage Install package. diff --git a/volatility/README.md b/volatility/README.md index 736a8d2..7bd01a2 100644 --- a/volatility/README.md +++ b/volatility/README.md @@ -25,6 +25,10 @@ The information provided on this project is strictly for informational purposes ## Index - [Constants](<#constants>) +- [type BollingerBandWidth](<#BollingerBandWidth>) + - [func NewBollingerBandWidth\[T helper.Number\]\(\) \*BollingerBandWidth\[T\]](<#NewBollingerBandWidth>) + - [func \(b \*BollingerBandWidth\[T\]\) Compute\(c \<\-chan T\) \<\-chan T](<#BollingerBandWidth[T].Compute>) + - [func \(b \*BollingerBandWidth\[T\]\) IdlePeriod\(\) int](<#BollingerBandWidth[T].IdlePeriod>) - [type BollingerBands](<#BollingerBands>) - [func NewBollingerBands\[T helper.Number\]\(\) \*BollingerBands\[T\]](<#NewBollingerBands>) - [func \(b \*BollingerBands\[T\]\) Compute\(c \<\-chan T\) \(\<\-chan T, \<\-chan T, \<\-chan T\)](<#BollingerBands[T].Compute>) @@ -47,6 +51,58 @@ const ( ) ``` + +## type [BollingerBandWidth]() + +BollingerBandWidth represents the configuration parameters for calculating the Bollinger Band Width. It measures the percentage difference between the upper band and the lower band. It decreases as Bollinger Bands narrows and increases as Bollinger Bands widens. + +During a period of rising price volatity the band width widens, and during a period of low market volatity band width contracts. + +``` +Band Width = (Upper Band - Lower Band) / Middle BollingerBandWidth +``` + +Example: + +``` +bbw := NewBollingerBandWidth[float64]() +bbw.Compute(c) +``` + +```go +type BollingerBandWidth[T helper.Number] struct { + // Bollinger bands. + BollingerBands *BollingerBands[T] +} +``` + + +### func [NewBollingerBandWidth]() + +```go +func NewBollingerBandWidth[T helper.Number]() *BollingerBandWidth[T] +``` + +NewBollingerBandWidth function initializes a new Bollinger Band Width instance with the default parameters. + + +### func \(\*BollingerBandWidth\[T\]\) [Compute]() + +```go +func (b *BollingerBandWidth[T]) Compute(c <-chan T) <-chan T +``` + +Compute function takes a channel of numbers and computes the Bollinger Band Width. + + +### func \(\*BollingerBandWidth\[T\]\) [IdlePeriod]() + +```go +func (b *BollingerBandWidth[T]) IdlePeriod() int +``` + +IdlePeriod is the initial period that Bollinger Band Width won't yield any results. + ## type [BollingerBands]() diff --git a/volatility/bollinger_band_width.go b/volatility/bollinger_band_width.go new file mode 100644 index 0000000..7585f26 --- /dev/null +++ b/volatility/bollinger_band_width.go @@ -0,0 +1,49 @@ +// Copyright (c) 2021-2023 Onur Cinar. +// The source code is provided under GNU AGPLv3 License. +// https://github.com/cinar/indicator + +package volatility + +import ( + "github.com/cinar/indicator/helper" +) + +// BollingerBandWidth represents the configuration parameters for calculating the Bollinger Band Width. +// It measures the percentage difference between the upper band and the lower band. It decreases as +// Bollinger Bands narrows and increases as Bollinger Bands widens. +// +// During a period of rising price volatity the band width widens, and during a period of low market +// volatity band width contracts. +// +// Band Width = (Upper Band - Lower Band) / Middle BollingerBandWidth +// +// Example: +// +// bbw := NewBollingerBandWidth[float64]() +// bbw.Compute(c) +type BollingerBandWidth[T helper.Number] struct { + // Bollinger bands. + BollingerBands *BollingerBands[T] +} + +// NewBollingerBandWidth function initializes a new Bollinger Band Width instance with the default parameters. +func NewBollingerBandWidth[T helper.Number]() *BollingerBandWidth[T] { + return &BollingerBandWidth[T]{ + BollingerBands: NewBollingerBands[T](), + } +} + +// Compute function takes a channel of numbers and computes the Bollinger Band Width. +func (b *BollingerBandWidth[T]) Compute(c <-chan T) <-chan T { + upper, middle, lower := b.BollingerBands.Compute(c) + + return helper.Divide( + helper.Subtract(upper, lower), + middle, + ) +} + +// IdlePeriod is the initial period that Bollinger Band Width won't yield any results. +func (b *BollingerBandWidth[T]) IdlePeriod() int { + return b.BollingerBands.IdlePeriod() +} diff --git a/volatility/bollinger_band_width_test.go b/volatility/bollinger_band_width_test.go new file mode 100644 index 0000000..55a9a8b --- /dev/null +++ b/volatility/bollinger_band_width_test.go @@ -0,0 +1,39 @@ +// Copyright (c) 2021-2023 Onur Cinar. +// The source code is provided under GNU AGPLv3 License. +// https://github.com/cinar/indicator + +package volatility_test + +import ( + "testing" + + "github.com/cinar/indicator/helper" + "github.com/cinar/indicator/volatility" +) + +func TestBollingerBandWidth(t *testing.T) { + type Data struct { + Close float64 + Width float64 + } + + input, err := helper.ReadFromCsvFile[Data]("testdata/bollinger_band_width.csv", true) + if err != nil { + t.Fatal(err) + } + + inputs := helper.Duplicate(input, 2) + closings := helper.Map(inputs[0], func(d *Data) float64 { return d.Close }) + expected := helper.Map(inputs[1], func(d *Data) float64 { return d.Width }) + + bbw := volatility.NewBollingerBandWidth[float64]() + actual := bbw.Compute(closings) + actual = helper.RoundDigits(actual, 2) + + expected = helper.Skip(expected, bbw.IdlePeriod()) + + err = helper.CheckEquals(actual, expected) + if err != nil { + t.Fatal(err) + } +} diff --git a/volatility/testdata/bollinger_band_width.csv b/volatility/testdata/bollinger_band_width.csv new file mode 100644 index 0000000..0d7124f --- /dev/null +++ b/volatility/testdata/bollinger_band_width.csv @@ -0,0 +1,252 @@ +Close,Width +318.600006,0 +315.839996,0 +316.149994,0 +310.570007,0 +307.779999,0 +305.820007,0 +305.98999,0 +306.390015,0 +311.450012,0 +312.329987,0 +309.290009,0 +301.910004,0 +300,0 +300.029999,0 +302,0 +307.820007,0 +302.690002,0 +306.48999,0 +305.549988,0 +303.429993,0.07 +309.059998,0.06 +308.899994,0.05 +309.910004,0.05 +314.549988,0.05 +312.899994,0.05 +318.690002,0.06 +315.529999,0.07 +316.350006,0.07 +320.369995,0.08 +318.929993,0.08 +317.640015,0.09 +314.859985,0.08 +308.299988,0.08 +305.230011,0.07 +309.869995,0.07 +310.420013,0.07 +311.299988,0.06 +311.899994,0.06 +310.950012,0.06 +309.170013,0.05 +307.329987,0.05 +311.519989,0.05 +310.570007,0.05 +311.859985,0.05 +308.51001,0.05 +308.429993,0.05 +312.970001,0.05 +308.480011,0.05 +307.209991,0.04 +309.890015,0.04 +313.73999,0.03 +310.790009,0.03 +309.630005,0.03 +308.179993,0.02 +308.23999,0.02 +302.720001,0.03 +303.160004,0.04 +303.070007,0.04 +304.019989,0.04 +304.660004,0.04 +305.179993,0.04 +304.619995,0.04 +307.75,0.04 +312.450012,0.04 +316.970001,0.05 +311.119995,0.05 +311.369995,0.05 +304.820007,0.05 +303.630005,0.05 +302.880005,0.05 +305.329987,0.05 +297.880005,0.06 +302.01001,0.06 +293.51001,0.07 +301.059998,0.07 +303.850006,0.07 +299.730011,0.07 +298.369995,0.07 +298.920013,0.07 +302.140015,0.07 +302.320007,0.07 +305.299988,0.07 +305.079987,0.07 +308.769989,0.07 +310.309998,0.06 +309.070007,0.06 +310.390015,0.06 +312.51001,0.06 +312.619995,0.07 +313.700012,0.07 +314.549988,0.08 +318.049988,0.08 +319.73999,0.09 +323.790009,0.09 +324.630005,0.1 +323.089996,0.1 +323.820007,0.1 +324.329987,0.1 +326.049988,0.1 +324.339996,0.09 +320.529999,0.09 +326.230011,0.08 +328.549988,0.08 +330.170013,0.08 +325.859985,0.08 +323.220001,0.07 +320,0.06 +323.880005,0.06 +326.140015,0.05 +324.869995,0.04 +322.98999,0.04 +322.640015,0.03 +322.48999,0.03 +323.529999,0.03 +323.75,0.03 +327.390015,0.03 +329.76001,0.03 +330.390015,0.04 +329.130005,0.04 +323.109985,0.04 +320.200012,0.04 +319.019989,0.04 +320.600006,0.04 +322.190002,0.04 +321.079987,0.04 +323.119995,0.04 +329.480011,0.04 +328.579987,0.04 +333.410004,0.05 +335.420013,0.06 +335.950012,0.06 +335.290009,0.07 +333.600006,0.07 +336.390015,0.07 +335.899994,0.07 +339.820007,0.08 +338.309998,0.08 +338.670013,0.08 +338.609985,0.09 +336.959991,0.09 +335.25,0.08 +334.119995,0.07 +335.339996,0.07 +334.149994,0.06 +336.910004,0.05 +341,0.04 +342,0.03 +341.559998,0.03 +341.459991,0.03 +340.899994,0.03 +341.130005,0.03 +343.369995,0.03 +345.350006,0.04 +343.540009,0.04 +341.089996,0.04 +344.25,0.04 +345.339996,0.04 +342.429993,0.04 +346.609985,0.04 +345.76001,0.04 +349.630005,0.05 +347.579987,0.04 +349.799988,0.04 +349.309998,0.04 +349.809998,0.04 +351.959991,0.04 +352.26001,0.04 +351.190002,0.04 +353.809998,0.05 +349.98999,0.04 +362.579987,0.06 +363.730011,0.07 +358.019989,0.07 +356.980011,0.07 +358.350006,0.07 +358.480011,0.06 +354.5,0.06 +354.109985,0.06 +353.190002,0.05 +352.559998,0.05 +352.089996,0.05 +350.570007,0.05 +354.26001,0.05 +354.299988,0.04 +355.929993,0.04 +355.549988,0.04 +358.290009,0.04 +361.059998,0.04 +360.200012,0.04 +362.459991,0.04 +360.470001,0.04 +361.670013,0.04 +361.799988,0.04 +363.149994,0.04 +365.519989,0.05 +367.779999,0.05 +367.820007,0.06 +369.5,0.06 +367.859985,0.06 +370.429993,0.06 +370.480011,0.06 +366.820007,0.06 +363.279999,0.05 +360.160004,0.05 +361.709991,0.05 +359.420013,0.04 +357.779999,0.04 +357.059998,0.05 +350.299988,0.05 +348.079987,0.07 +343.040009,0.08 +343.690002,0.09 +345.059998,0.1 +346.339996,0.11 +345.450012,0.11 +348.559998,0.11 +348.429993,0.11 +345.660004,0.1 +345.089996,0.1 +346.230011,0.09 +345.390015,0.08 +340.890015,0.08 +338.660004,0.08 +335.859985,0.08 +336.839996,0.07 +338.630005,0.06 +336.899994,0.06 +336.160004,0.05 +331.709991,0.06 +337.410004,0.06 +341.329987,0.06 +343.75,0.06 +349.019989,0.06 +351.809998,0.06 +346.630005,0.06 +346.170013,0.06 +346.299988,0.06 +348.179993,0.06 +350.559998,0.06 +350.01001,0.07 +354.25,0.07 +356.790009,0.08 +359.859985,0.09 +358.929993,0.09 +361.329987,0.1 +361,0.1 +361.799988,0.1 +362.679993,0.1 +361.339996,0.08 +360.049988,0.08 +358.690002,0.07