Skip to content

Commit

Permalink
Buy and hold, trend, MACD, RSI, Bollinger Bands, Awesome Oscillator, …
Browse files Browse the repository at this point in the history
…and Williams R strategies are added.
  • Loading branch information
cinar committed Sep 10, 2021
1 parent 9439c0d commit 3be9665
Show file tree
Hide file tree
Showing 3 changed files with 360 additions and 3 deletions.
141 changes: 139 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

# Indicator Go

Indicator is a Golang module providing various stock technical analysis indicators for trading. The following list of indicators are currently supported by this package:
Indicator is a Golang module providing various stock technical analysis indicators, and strategies for trading.

## Indicators Provided

The following list of indicators are currently supported by this package:

- [Simple Moving Average (SMA)](#simple-moving-average-sma)
- [Moving Standard Deviation (Std)](#moving-standard-deviation-std)
Expand All @@ -27,6 +31,19 @@ Indicator is a Golang module providing various stock technical analysis indicato
- [Acceleration Bands](#acceleration-bands)
- [Accumulation/Distribution (A/D)](#accumulationdistribution-ad)

## Strategies Provided

The following list of strategies are currently supported by this package:

- [Buy and Hold Strategy](#buy-and-hold-strategy)
- [Trend Strategy](#trend-strategy)
- [MACD Strategy](#macd-strategy)
- [RSI Strategy](#rsi-strategy)
- [MACD and RSI Strategy](#macd-and-rsi-strategy)
- [Bollinger Bands Strategy](#bollinger-bands-strategy)
- [Awesome Oscillator Strategy](#awesome-oscillator-strategy)
- [Williams R Strategy](#williams-r-strategy)

## Usage

Install package.
Expand All @@ -39,7 +56,7 @@ Import indicator.

```Golang
import (
"indicator"
"github.com/cinar/indicator"
)
```

Expand Down Expand Up @@ -328,6 +345,126 @@ Based on [Accumulation/Distribution Indicator (A/D)](https://www.investopedia.co
ad := indicator.AccumulationDistribution(high, low, close,
```

### Strategies

The strategies are where the results from one or more indicators gets combined to produce a recommended action.

The stragies operates on an [Asset](https://pkg.go.dev/github.com/cinar/indicator#Asset) with the following members.

```golang
type Asset struct {
Date []time.Time
Open []float64
Close []float64
High []float64
Low []float64
Volume []int64
}
```

The [StrategyFunction](https://pkg.go.dev/github.com/cinar/indicator#StrategyFunction) takes an [Asset](https://pkg.go.dev/github.com/cinar/indicator#Asset), and provides an array of [Action](https://pkg.go.dev/github.com/cinar/indicator#Action) for each row.

```golang
// Strategy function.
type StrategyFunction func(Asset) []Action
```

The following [Action](https://pkg.go.dev/github.com/cinar/indicator#Action) values are currently provided.

```golang
type Action int

const (
HOLD Action = iota
BUY
SELL
)
```

#### Buy and Hold Strategy

The [BuyAndHoldStrategy](https://pkg.go.dev/github.com/cinar/indicator#BuyAndHoldStrategy) provides a simple strategy to buy the given asset and hold it. It provides a good indicator for the change of asset's value without any other strategy is used.

```golang
actions := indicator.BuyAndHoldStrategy(asset)
```

#### Trend Strategy

The [TrendStrategy](https://pkg.go.dev/github.com/cinar/indicator#TrendStrategy) provides a simply strategy to buy the given asset following the asset's closing value increases in *count* subsequent rows. Produces the sell action following the asset's closing value decreases in *count* subsequent rows.

```golang
actions := indicator.TrendStrategy(asset, 4)
```

The function signature of [TrendStrategy](https://pkg.go.dev/github.com/cinar/indicator#TrendStrategy) does not match the [StrategyFunction](https://pkg.go.dev/github.com/cinar/indicator#StrategyFunction) type, as it requires an additional *count* parameter. The [MakeTrendStrategy](https://pkg.go.dev/github.com/cinar/indicator#MakeTrendStrategy) function can be used to return a [StrategyFunction](https://pkg.go.dev/github.com/cinar/indicator#StrategyFunction) instance based on the given *count* value.

```golang
strategy := indicator.MakeTrendStrategy(4)
actions := strategy(asset)
```

#### MACD Strategy

The [MacdStrategy](https://pkg.go.dev/github.com/cinar/indicator#MacdStrategy) uses the *macd*, and *signal* values that are generated by the [Macd](https://pkg.go.dev/github.com/cinar/indicator#Macd) indicator function to provide a BUY action when *macd* crosses above *signal*, and SELL action when *macd* crosses below *signal*.

```golang
actions := indicator.MacdStrategy(asset)
```

#### RSI Strategy

The [RsiStrategy](https://pkg.go.dev/github.com/cinar/indicator#RsiStrategy) uses the *rsi* values that are generated by the [Rsi](https://pkg.go.dev/github.com/cinar/indicator#Rsi) indicator function to provide a BUY action when *rsi* is below the *buyAt* parameter, and a SELL action when *rsi* is above the *sellAt* parameter.

```golang
actions := indicator.RsiStrategy(asset, 70, 30)
```

The RSI strategy is usually used with 70-30, or 80-20 values. The [DefaultRsiStrategy](https://pkg.go.dev/github.com/cinar/indicator#DefaultRsiStrategy) function uses the 70-30 values.

```golang
actions := indicator.DefaultRsiStrategy(asset)
```

The function signature of [RsiStrategy](https://pkg.go.dev/github.com/cinar/indicator#RsiStrategy) does not match the [StrategyFunction](https://pkg.go.dev/github.com/cinar/indicator#StrategyFunction) type, as it requires an additional *sellAt*, and *buyAt* parameters. The [MakeRsiStrategy](https://pkg.go.dev/github.com/cinar/indicator#MakeRsiStrategy) function can be used to return a [StrategyFunction](https://pkg.go.dev/github.com/cinar/indicator#StrategyFunction) instance based on the given *sellAt*, and *buyAt* values.

```golang
strategy := indicator.MakeRsiStrategy(80, 20)
actions := strategy(asset)
```

#### MACD and RSI Strategy

The [MacdAndRsiStrategy](https://pkg.go.dev/github.com/cinar/indicator#MacdAndRsiStrategy) function uses the actions generated by the [MacdStrategy](https://pkg.go.dev/github.com/cinar/indicator#MacdStrategy) and the [DefaultRsiStrategy](https://pkg.go.dev/github.com/cinar/indicator#DefaultRsiStrategy) to provide BUY and SELL actions.

```golang
actions := indicator.MacdAndRsiStrategy(asset)
```

#### Bollinger Bands Strategy

The [BollingerBandsStrategy](https://pkg.go.dev/github.com/cinar/indicator#BollingerBandsStrategy) uses the *upperBand*, and *lowerBand* values that are generated by the [BollingerBands](https://pkg.go.dev/github.com/cinar/indicator#BollingerBands) indicator function to provide a SELL action when the asset's closing is above the *upperBand*, and a BUY action when the asset's closing is below the *lowerBand* values.

```golang
actions := indicator.BollingerBandsStrategy(asset)
```

#### Awesome Oscillator Strategy

The [AwesomeOscillatorStrategy](https://pkg.go.dev/github.com/cinar/indicator#AwesomeOscillatorStrategy) uses the *ao* values that are generated by the [AwesomeOscillator](https://pkg.go.dev/github.com/cinar/indicator#AwesomeOscillator) indicator function to provide a SELL action when the *ao* is below zero, and a BUY action when *ao* is above zero.

```golang
actions := indicator.AwesomeOscillatorStrategy(asset)
```

#### Williams R Strategy

The [WilliamsRStrategy](https://pkg.go.dev/github.com/cinar/indicator#WilliamsRStrategy) uses the *wr* values that are generated by the [WilliamsR](https://pkg.go.dev/github.com/cinar/indicator#WilliamsR) indicator function to provide a SELL action when the *wr* is below -20, and a BUY action when *wr* is above -80.

```golang
actions := indicator.WilliamsRStrategy(asset)
```

## License

The source code is provided under MIT License.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/cinar/indicator

go 1.16
go 1.14
220 changes: 220 additions & 0 deletions strategy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
package indicator

import (
"log"
"time"
)

// Strategy action.
type Action int

const (
HOLD Action = iota
BUY
SELL
)

// Asset values.
type Asset struct {
Date []time.Time
Open []float64
Close []float64
High []float64
Low []float64
Volume []int64
}

// Strategy function. It takes an Asset and returns
// actions for each row.
type StrategyFunction func(Asset) []Action

// Buy and hold strategy. Buys at the beginning and holds.
func BuyAndHoldStrategy(asset Asset) []Action {
actions := make([]Action, len(asset.Date))

for i := 0; i < len(actions); i++ {
actions[i] = BUY
}

return actions
}

// Trend strategy. Buy when trending up for count times,
// sell when trending down for count times.
func TrendStrategy(asset Asset, count int) []Action {
if count < 1 {
log.Fatal("count cannot be less than 1")
}

actions := make([]Action, len(asset.Date))

if len(actions) == 0 {
return actions
}

var lastClose float64 = asset.Close[0]
var trendCount int
var trendUp bool

actions[0] = HOLD

for i := 1; i < len(actions); i++ {
close := asset.Close[i]

if trendUp && (lastClose <= close) {
trendCount++
} else if !trendUp && (lastClose >= close) {
trendCount++
} else {
trendUp = !trendUp
trendCount = 1
}

lastClose = close

if trendCount == count {
if trendUp {
actions[i] = BUY
} else {
actions[i] = SELL
}
} else {
actions[i] = HOLD
}
}

return actions
}

// Make trend strategy function.
func MakeTrendStrategy(count int) StrategyFunction {
return func(asset Asset) []Action {
return TrendStrategy(asset, count)
}
}

// MACD strategy.
func MacdStrategy(asset Asset) []Action {
actions := make([]Action, len(asset.Date))

macd, signal := Macd(asset.Close)

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

return actions
}

// RSI strategy. Sells above sell at, buys below buy at.
func RsiStrategy(asset Asset, sellAt, buyAt float64) []Action {
actions := make([]Action, len(asset.Date))

_, rsi := Rsi(asset.Close)

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

return actions
}

// Default RSI strategy function. It buys
// below 30 and sells above 70.
func DefaultRsiStrategy(asset Asset) []Action {
return RsiStrategy(asset, 70, 30)
}

// Make RSI strategy function.
func MakeRsiStrategy(sellAt, buyAt float64) StrategyFunction {
return func(asset Asset) []Action {
return RsiStrategy(asset, sellAt, buyAt)
}
}

// MACD and RSI strategy.
func MacdAndRsiStrategy(asset Asset) []Action {
actions := make([]Action, len(asset.Date))

macdActions := MacdStrategy(asset)
rsiActions := DefaultRsiStrategy(asset)

for i := 0; i < len(actions); i++ {
if macdActions[i] == rsiActions[i] {
actions[i] = macdActions[i]
} else {
actions[i] = HOLD
}
}

return actions
}

// Bollinger bands strategy function.
func BollingerBandsStrategy(asset Asset) []Action {
actions := make([]Action, len(asset.Date))

_, upperBand, lowerBand := BollingerBands(asset.Close)

for i := 0; i < len(actions); i++ {
if asset.Close[i] > upperBand[i] {
actions[i] = SELL
} else if asset.Close[i] < lowerBand[i] {
actions[i] = BUY
} else {
actions[i] = HOLD
}
}

return actions
}

// Awesome oscillator strategy function.
func AwesomeOscillatorStrategy(asset Asset) []Action {
actions := make([]Action, len(asset.Date))

ao := AwesomeOscillator(asset.Low, asset.High)

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

return actions
}

// Williams R strategy function.
func WilliamsRStrategy(asset Asset) []Action {
actions := make([]Action, len(asset.Date))

wr := WilliamsR(asset.Low, asset.High, asset.Close)

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

return actions
}

0 comments on commit 3be9665

Please sign in to comment.