Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ The following list of indicators are currently supported by this package:

- [Percent B](volatility/README.md#PercentB)
- [Acceleration Bands](volatility/README.md#AccelerationBands)
- [Annualized Historical Volatility (AHV)](volatility/README.md#AnnualizedHistoricalVolatility)
- [Average True Range (ATR)](volatility/README.md#Atr)
- [Bollinger Band Width](volatility/README.md#BollingerBandWidth)
- [Bollinger Bands](volatility/README.md#BollingerBands)
Expand Down
95 changes: 95 additions & 0 deletions volatility/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ The information provided on this project is strictly for informational purposes
- [func \(a \*AccelerationBands\[T\]\) Compute\(high, low, closing \<\-chan T\) \(\<\-chan T, \<\-chan T, \<\-chan T\)](<#AccelerationBands[T].Compute>)
- [func \(a \*AccelerationBands\[T\]\) ComputeWithContext\(ctx context.Context, high, low, closing \<\-chan T\) \(\<\-chan T, \<\-chan T, \<\-chan T\)](<#AccelerationBands[T].ComputeWithContext>)
- [func \(a \*AccelerationBands\[T\]\) IdlePeriod\(\) int](<#AccelerationBands[T].IdlePeriod>)
- [type AnnualizedHistoricalVolatility](<#AnnualizedHistoricalVolatility>)
- [func NewAnnualizedHistoricalVolatility\[T helper.Number\]\(\) \*AnnualizedHistoricalVolatility\[T\]](<#NewAnnualizedHistoricalVolatility>)
- [func NewAnnualizedHistoricalVolatilityWithPeriod\[T helper.Number\]\(period int\) \*AnnualizedHistoricalVolatility\[T\]](<#NewAnnualizedHistoricalVolatilityWithPeriod>)
- [func \(a \*AnnualizedHistoricalVolatility\[T\]\) Compute\(prices \<\-chan T\) \<\-chan T](<#AnnualizedHistoricalVolatility[T].Compute>)
- [func \(a \*AnnualizedHistoricalVolatility\[T\]\) ComputeWithContext\(ctx context.Context, prices \<\-chan T\) \<\-chan T](<#AnnualizedHistoricalVolatility[T].ComputeWithContext>)
- [func \(a \*AnnualizedHistoricalVolatility\[T\]\) IdlePeriod\(\) int](<#AnnualizedHistoricalVolatility[T].IdlePeriod>)
- [func \(a \*AnnualizedHistoricalVolatility\[T\]\) String\(\) string](<#AnnualizedHistoricalVolatility[T].String>)
- [type Atr](<#Atr>)
- [func NewAtr\[T helper.Number\]\(\) \*Atr\[T\]](<#NewAtr>)
- [func NewAtrWithMa\[T helper.Number\]\(ma trend.Ma\[T\]\) \*Atr\[T\]](<#NewAtrWithMa>)
Expand Down Expand Up @@ -120,6 +127,19 @@ The information provided on this project is strictly for informational purposes

## Constants

<a name="DefaultAnnualizedHistoricalVolatilityPeriod"></a>

```go
const (
// DefaultAnnualizedHistoricalVolatilityPeriod is the default period for
// Annualized Historical Volatility (AHV).
DefaultAnnualizedHistoricalVolatilityPeriod = 21

// DefaultTradingDaysPerYear is the standard number of trading days in a year.
DefaultTradingDaysPerYear = 252
)
```

<a name="DefaultChandelierExitPeriod"></a>

```go
Expand Down Expand Up @@ -297,6 +317,81 @@ func (a *AccelerationBands[T]) IdlePeriod() int

IdlePeriod is the initial period that Acceleration Bands won't yield any results.

<a name="AnnualizedHistoricalVolatility"></a>
## type [AnnualizedHistoricalVolatility](<https://github.com/cinar/indicator/blob/master/volatility/annualized_historical_volatility.go#L30-L36>)

AnnualizedHistoricalVolatility represents the configuration parameters for calculating Annualized Historical Volatility \(AHV\). It annualizes the Historical Volatility by multiplying it by the square root of the number of trading days per year.

```
AHV = HV × √TradingDaysPerYear
```

```go
type AnnualizedHistoricalVolatility[T helper.Number] struct {
// Hv is the underlying Historical Volatility indicator.
Hv *HistoricalVolatility[T]

// TradingDaysPerYear is the number of trading days in a year (default: 252).
TradingDaysPerYear int
}
```

<a name="NewAnnualizedHistoricalVolatility"></a>
### func [NewAnnualizedHistoricalVolatility](<https://github.com/cinar/indicator/blob/master/volatility/annualized_historical_volatility.go#L40>)

```go
func NewAnnualizedHistoricalVolatility[T helper.Number]() *AnnualizedHistoricalVolatility[T]
```

NewAnnualizedHistoricalVolatility function initializes a new Annualized Historical Volatility instance with the default parameters.

<a name="NewAnnualizedHistoricalVolatilityWithPeriod"></a>
### func [NewAnnualizedHistoricalVolatilityWithPeriod](<https://github.com/cinar/indicator/blob/master/volatility/annualized_historical_volatility.go#L46>)

```go
func NewAnnualizedHistoricalVolatilityWithPeriod[T helper.Number](period int) *AnnualizedHistoricalVolatility[T]
```

NewAnnualizedHistoricalVolatilityWithPeriod function initializes a new Annualized Historical Volatility instance with the given period.

<a name="AnnualizedHistoricalVolatility[T].Compute"></a>
### func \(\*AnnualizedHistoricalVolatility\[T\]\) [Compute](<https://github.com/cinar/indicator/blob/master/volatility/annualized_historical_volatility.go#L73>)

```go
func (a *AnnualizedHistoricalVolatility[T]) Compute(prices <-chan T) <-chan T
```

Compute wraps ComputeWithContext for backwards compatibility.

Deprecated: Use ComputeWithContext instead.

<a name="AnnualizedHistoricalVolatility[T].ComputeWithContext"></a>
### func \(\*AnnualizedHistoricalVolatility\[T\]\) [ComputeWithContext](<https://github.com/cinar/indicator/blob/master/volatility/annualized_historical_volatility.go#L55>)

```go
func (a *AnnualizedHistoricalVolatility[T]) ComputeWithContext(ctx context.Context, prices <-chan T) <-chan T
```

ComputeWithContext function takes a channel of prices and computes the Annualized Historical Volatility over the specified period.

<a name="AnnualizedHistoricalVolatility[T].IdlePeriod"></a>
### func \(\*AnnualizedHistoricalVolatility\[T\]\) [IdlePeriod](<https://github.com/cinar/indicator/blob/master/volatility/annualized_historical_volatility.go#L61>)

```go
func (a *AnnualizedHistoricalVolatility[T]) IdlePeriod() int
```

IdlePeriod is the initial period that Annualized Historical Volatility won't yield any results.

<a name="AnnualizedHistoricalVolatility[T].String"></a>
### func \(\*AnnualizedHistoricalVolatility\[T\]\) [String](<https://github.com/cinar/indicator/blob/master/volatility/annualized_historical_volatility.go#L66>)

```go
func (a *AnnualizedHistoricalVolatility[T]) String() string
```

String function returns a string representation of the Annualized Historical Volatility.

<a name="Atr"></a>
## type [Atr](<https://github.com/cinar/indicator/blob/master/volatility/atr.go#L32-L35>)

Expand Down
75 changes: 75 additions & 0 deletions volatility/annualized_historical_volatility.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) 2021-2026 Onur Cinar.
// The source code is provided under GNU AGPLv3 License.
// https://github.com/cinar/indicator

package volatility

import (
"fmt"
"math"

"context"

"github.com/cinar/indicator/v2/helper"
)

const (
// DefaultAnnualizedHistoricalVolatilityPeriod is the default period for
// Annualized Historical Volatility (AHV).
DefaultAnnualizedHistoricalVolatilityPeriod = 21

// DefaultTradingDaysPerYear is the standard number of trading days in a year.
DefaultTradingDaysPerYear = 252
)

// AnnualizedHistoricalVolatility represents the configuration parameters for calculating
// Annualized Historical Volatility (AHV). It annualizes the Historical Volatility by
// multiplying it by the square root of the number of trading days per year.
//
// AHV = HV × √TradingDaysPerYear
type AnnualizedHistoricalVolatility[T helper.Number] struct {
// Hv is the underlying Historical Volatility indicator.
Hv *HistoricalVolatility[T]

// TradingDaysPerYear is the number of trading days in a year (default: 252).
TradingDaysPerYear int
}

// NewAnnualizedHistoricalVolatility function initializes a new Annualized Historical Volatility
// instance with the default parameters.
func NewAnnualizedHistoricalVolatility[T helper.Number]() *AnnualizedHistoricalVolatility[T] {
return NewAnnualizedHistoricalVolatilityWithPeriod[T](DefaultAnnualizedHistoricalVolatilityPeriod)
}

// NewAnnualizedHistoricalVolatilityWithPeriod function initializes a new Annualized Historical
// Volatility instance with the given period.
func NewAnnualizedHistoricalVolatilityWithPeriod[T helper.Number](period int) *AnnualizedHistoricalVolatility[T] {
return &AnnualizedHistoricalVolatility[T]{
Hv: NewHistoricalVolatilityWithPeriod[T](period),
TradingDaysPerYear: DefaultTradingDaysPerYear,
}
}

// ComputeWithContext function takes a channel of prices and computes the Annualized Historical
// Volatility over the specified period.
func (a *AnnualizedHistoricalVolatility[T]) ComputeWithContext(ctx context.Context, prices <-chan T) <-chan T {
hv := a.Hv.ComputeWithContext(ctx, prices)
return helper.MultiplyByWithContext(ctx, hv, T(math.Sqrt(float64(a.TradingDaysPerYear))))
}

// IdlePeriod is the initial period that Annualized Historical Volatility won't yield any results.
func (a *AnnualizedHistoricalVolatility[T]) IdlePeriod() int {
return a.Hv.IdlePeriod()
}

// String function returns a string representation of the Annualized Historical Volatility.
func (a *AnnualizedHistoricalVolatility[T]) String() string {
return fmt.Sprintf("AHV(%d)", a.Hv.Period)
}

// Compute wraps ComputeWithContext for backwards compatibility.
//
// Deprecated: Use ComputeWithContext instead.
func (a *AnnualizedHistoricalVolatility[T]) Compute(prices <-chan T) <-chan T {
return a.ComputeWithContext(context.Background(), prices)
}
67 changes: 67 additions & 0 deletions volatility/annualized_historical_volatility_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) 2021-2026 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/v2/helper"
"github.com/cinar/indicator/v2/volatility"
)

func TestAnnualizedHistoricalVolatilityDefaultAndString(t *testing.T) {
ahv := volatility.NewAnnualizedHistoricalVolatility[float64]()

if ahv.Hv.Period != volatility.DefaultAnnualizedHistoricalVolatilityPeriod {
t.Fatalf("expected period %d, got %d", volatility.DefaultAnnualizedHistoricalVolatilityPeriod, ahv.Hv.Period)
}

if ahv.TradingDaysPerYear != volatility.DefaultTradingDaysPerYear {
t.Fatalf("expected trading days %d, got %d", volatility.DefaultTradingDaysPerYear, ahv.TradingDaysPerYear)
}

if ahv.IdlePeriod() != volatility.DefaultAnnualizedHistoricalVolatilityPeriod {
t.Fatalf("expected idle period %d, got %d", volatility.DefaultAnnualizedHistoricalVolatilityPeriod, ahv.IdlePeriod())
}

if ahv.String() != "AHV(21)" {
t.Fatalf("expected AHV(21), got %s", ahv.String())
}
}

func TestAnnualizedHistoricalVolatilityWithInvalidPeriod(t *testing.T) {
ahv := volatility.NewAnnualizedHistoricalVolatilityWithPeriod[float64](0)

if ahv.Hv.Period != volatility.DefaultAnnualizedHistoricalVolatilityPeriod {
t.Fatalf("expected default period %d, got %d", volatility.DefaultAnnualizedHistoricalVolatilityPeriod, ahv.Hv.Period)
}
}

func TestAnnualizedHistoricalVolatility(t *testing.T) {
type Data struct {
Close float64 `header:"Close"`
Ahv float64 `header:"Ahv"`
}

input, err := helper.ReadFromCsvFile[Data]("testdata/annualized_historical_volatility.csv")
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.Ahv })

ahv := volatility.NewAnnualizedHistoricalVolatility[float64]()
actual := ahv.Compute(closings)
actual = helper.RoundDigits(actual, 8)

expected = helper.Skip(expected, ahv.IdlePeriod())

err = helper.CheckEquals(actual, expected)
if err != nil {
t.Fatal(err)
}
}
Loading
Loading