Skip to content

Commit

Permalink
Force Index is added.
Browse files Browse the repository at this point in the history
  • Loading branch information
cinar committed Jan 14, 2022
1 parent 8837894 commit 9bc86fa
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 30 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ The following list of indicators are currently supported by this package:
### Volume Indicators

- [Accumulation/Distribution (A/D)](volume_indicators.md#accumulationdistribution-ad)
- [On-Balance Volume (OBV)](volume_indicators.md#on-balance-volume-obv)
- [Force Index (FI)](volume_indicators.md#force-index-fi)
- [Money Flow Index (MFI)](volume_indicators.md#money-flow-index-mfi)
- [On-Balance Volume (OBV)](volume_indicators.md#on-balance-volume-obv)

## Strategies Provided

Expand Down Expand Up @@ -88,6 +89,7 @@ The following list of strategies are currently supported by this package:

### Volume Strategies

- [Force Index Strategy](volume_strategies.md#force-index-strategy)
- [Money Flow Index Strategy](volume_strategies.md#money-flow-index-strategy)

### Compound Strategies
Expand Down
12 changes: 1 addition & 11 deletions helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,7 @@ func substract(values1, values2 []float64) []float64 {

// Difference between current and before values.
func diff(values []float64, before int) []float64 {
if before >= len(values) {
panic("before greather or equals to size")
}

result := make([]float64, len(values))

for i := before; i < len(values); i++ {
result[i] = values[i] - values[i-before]
}

return result
return substract(values, shiftRight(1, values))
}

// Percent difference between current and before values.
Expand Down
12 changes: 1 addition & 11 deletions helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,19 +140,9 @@ func TestSubstract(t *testing.T) {
}
}

func TestDiffWithLargerBefore(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Fatal("did not check size")
}
}()

diff([]float64{}, 10)
}

func TestDiff(t *testing.T) {
values := []float64{1, 2, 1, 4, 2, 2, 6, 8, 2, 10}
expected := []float64{0, 1, -1, 3, -2, 0, 4, 2, -6, 8}
expected := []float64{1, 1, -1, 3, -2, 0, 4, 2, -6, 8}
before := 1

actual := diff(values, before)
Expand Down
15 changes: 15 additions & 0 deletions volume_indicators.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,18 @@ func MoneyFlowIndex(period int, high, low, closing []float64, volume []int64) []
func DefaultMoneyFlowIndex(high, low, closing []float64, volume []int64) []float64 {
return MoneyFlowIndex(14, high, low, closing, volume)
}

// The Force Index (FI) uses the closing price and the volume to assess
// the power behind a move and identify turning points.
//
// Force Index = EMA(period, (Current - Previous) * Volume)
//
// Returns force index.
func ForceIndex(period int, closing []float64, volume []int64) []float64 {
return Ema(period, multiply(diff(closing, 1), asFloat64(volume)))
}

// The default Force Index (FI) with window size of 13.
func DefaultForceIndex(closing []float64, volume []int64) []float64 {
return ForceIndex(13, closing, volume)
}
32 changes: 25 additions & 7 deletions volume_indicators.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
Volumne indicators measure the strength of a trend based the volume.

- [Accumulation/Distribution (A/D)](#accumulationdistribution-ad)
- [On-Balance Volume (OBV)](#on-balance-volume-obv)
- [Force Index (FI)](#force-index-fi)
- [Money Flow Index (MFI)](#money-flow-index-mfi)
- [On-Balance Volume (OBV)](#on-balance-volume-obv)

#### Accumulation/Distribution (A/D)

Expand All @@ -24,18 +25,22 @@ Based on [Accumulation/Distribution Indicator (A/D)](https://www.investopedia.co
ad := indicator.AccumulationDistribution(high, low, closing, volume)
```

#### On-Balance Volume (OBV)
#### Force Index (FI)

The [Obv](https://pkg.go.dev/github.com/cinar/indicator#Obv) function calculates a technical trading momentum indicator that uses volume flow to predict changes in stock price.
The [ForceIndex](https://pkg.go.dev/github.com/cinar/indicator#ForceIndex) uses the closing price and the volume to assess the power behind a move and identify turning points.

```
volume, if Closing > Closing-Prev
OBV = OBV-Prev + 0, if Closing = Closing-Prev
-volume, if Closing < Closing-Prev
Force Index = EMA(period, (Current - Previous) * Volume)
```

```Golang
result := indicator.Obv(closing, volume)
fi := indicator.ForceIndex(period, closing, volume)
```

The [DefaultForceIndex](https://pkg.go.dev/github.com/cinar/indicator#DefaultForceIndex) function uses the default period of 13.

```Golang
fi := DefaultForceIndex(closing, volume)
```

#### Money Flow Index (MFI)
Expand All @@ -54,6 +59,19 @@ result := indicator.MoneyFlowIndex(period, high, low, closing, volume)

The [DefaultMoneyFlowIndex](https://pkg.go.dev/github.com/cinar/indicator#DefaultMoneyFlowIndex) function uses the default period of 14.

#### On-Balance Volume (OBV)

The [Obv](https://pkg.go.dev/github.com/cinar/indicator#Obv) function calculates a technical trading momentum indicator that uses volume flow to predict changes in stock price.

```
volume, if Closing > Closing-Prev
OBV = OBV-Prev + 0, if Closing = Closing-Prev
-volume, if Closing < Closing-Prev
```

```Golang
result := indicator.Obv(closing, volume)
```

## Disclaimer

Expand Down
39 changes: 39 additions & 0 deletions volume_indicators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,42 @@ func TestMoneyFlowIndex(t *testing.T) {
}
}
}

func TestForceIndex(t *testing.T) {
closing := []float64{9, 11, 7, 10, 8}
volume := []int64{100, 110, 80, 120, 90}
expected := []float64{900, 220, -320, 360, -180}
period := 1

result := ForceIndex(period, closing, volume)
if len(result) != len(expected) {
t.Fatal("result not same size")
}

for i := 0; i < len(result); i++ {
actual := roundDigits(result[i], 2)

if actual != expected[i] {
t.Fatalf("result %d actual %f expected %f", i, actual, expected[i])
}
}
}

func TestDefaultForceIndex(t *testing.T) {
closing := []float64{9, 11, 7, 10, 8}
volume := []int64{100, 110, 80, 120, 90}
expected := []float64{900, 802.86, 642.45, 602.1, 490.37}

result := DefaultForceIndex(closing, volume)
if len(result) != len(expected) {
t.Fatal("result not same size")
}

for i := 0; i < len(result); i++ {
actual := roundDigits(result[i], 2)

if actual != expected[i] {
t.Fatalf("result %d actual %f expected %f", i, actual, expected[i])
}
}
}
20 changes: 20 additions & 0 deletions volume_strategies.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package indicator

// Money flow index strategy.
func MoneyFlowIndexStrategy(asset Asset) []Action {
actions := make([]Action, len(asset.Date))

Expand All @@ -24,3 +25,22 @@ func MoneyFlowIndexStrategy(asset Asset) []Action {

return actions
}

// Force index strategy function.
func ForceIndexStrategy(asset Asset) []Action {
actions := make([]Action, len(asset.Date))

forceIndex := DefaultForceIndex(asset.Closing, asset.Volume)

for i := 0; i < len(actions); i++ {
if forceIndex[i] > 0 {
actions[i] = BUY
} else if forceIndex[i] < 0 {
actions[i] = SELL
} else {
actions[i] = HOLD
}
}

return actions
}
9 changes: 9 additions & 0 deletions volume_strategies.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@

Volume strategies generate signals based on a volume indicator.

- [Force Index Strategy](#force-index-strategy)
- [Money Flow Index Strategy](#money-flow-index-strategy)

#### Force Index Strategy

The [ForceIndexStrategy](https://pkg.go.dev/github.com/cinar/indicator#ForceIndexStrategy) uses the _fi_ values that are generated by the [Force Index (FI)](volume_indicators.md#force-index-fi) indicator function to provide a _BUY_ action when _fi_ is greather than zero, and a _SELL_ action when _fi_ is less than zero, a _HOLD_ action otherwise.

```Golang
actions := ForceIndexStrategy(asset)
```

#### Money Flow Index Strategy

The [MoneyFlowIndexStrategy](https://pkg.go.dev/github.com/cinar/indicator#MoneyFlowIndexStrategy) uses the _mfi_ values that are generated by the [Money Flow Index (MFI)](volume_indicators.md#money-flow-index-mfi) indicator function to provide a _SELL_ action when _mfi_ is greather than or equal to 80, and a _BUY_ action when _mfi_ is less than or equal to 20.
Expand Down

0 comments on commit 9bc86fa

Please sign in to comment.