Skip to content

Commit

Permalink
Chaging the type of Volume from int64 to float64. (#127)
Browse files Browse the repository at this point in the history
Fixes #126 by changing the Volume from int64 to float64. This is going
to be a breaking change for the projects depending to this module, so I
will be incrementing the minor version number.
  • Loading branch information
cinar committed Oct 21, 2023
1 parent 3959988 commit def9908
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 65 deletions.
13 changes: 6 additions & 7 deletions momentum_indicators.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func AwesomeOscillator(low, high []float64) []float64 {
// CO = Ema(fastPeriod, AD) - Ema(slowPeriod, AD)
//
// Returns co, ad.
func ChaikinOscillator(fastPeriod, slowPeriod int, low, high, closing []float64, volume []int64) ([]float64, []float64) {
func ChaikinOscillator(fastPeriod, slowPeriod int, low, high, closing, volume []float64) ([]float64, []float64) {
ad := AccumulationDistribution(high, low, closing, volume)
co := subtract(Ema(fastPeriod, ad), Ema(slowPeriod, ad))

Expand All @@ -41,7 +41,7 @@ func ChaikinOscillator(fastPeriod, slowPeriod int, low, high, closing []float64,
// periods, 3 and 10.
//
// Returns co, ad.
func DefaultChaikinOscillator(low, high, closing []float64, volume []int64) ([]float64, []float64) {
func DefaultChaikinOscillator(low, high, closing, volume []float64) ([]float64, []float64) {
return ChaikinOscillator(3, 10, low, high, closing, volume)
}

Expand Down Expand Up @@ -102,10 +102,9 @@ func DefaultPercentagePriceOscillator(price []float64) ([]float64, []float64, []
// Histogram = PVO - Signal
//
// Returns pvo, signal, histogram
func PercentageVolumeOscillator(fastPeriod, slowPeriod, signalPeriod int, volume []int64) ([]float64, []float64, []float64) {
volumeAsFloat := asFloat64(volume)
fastEma := Ema(fastPeriod, volumeAsFloat)
slowEma := Ema(slowPeriod, volumeAsFloat)
func PercentageVolumeOscillator(fastPeriod, slowPeriod, signalPeriod int, volume []float64) ([]float64, []float64, []float64) {
fastEma := Ema(fastPeriod, volume)
slowEma := Ema(slowPeriod, volume)
pvo := multiplyBy(divide(subtract(fastEma, slowEma), slowEma), 100)
signal := Ema(signalPeriod, pvo)
histogram := subtract(pvo, signal)
Expand All @@ -116,7 +115,7 @@ func PercentageVolumeOscillator(fastPeriod, slowPeriod, signalPeriod int, volume
// Default Percentage Volume Oscillator calculates it with the default periods of 12, 26, 9.
//
// Returns pvo, signal, histogram
func DefaultPercentageVolumeOscillator(volume []int64) ([]float64, []float64, []float64) {
func DefaultPercentageVolumeOscillator(volume []float64) ([]float64, []float64, []float64) {
return PercentageVolumeOscillator(12, 26, 9, volume)
}

Expand Down
4 changes: 2 additions & 2 deletions momentum_indicators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func TestChaikinOscillator(t *testing.T) {
high := []float64{10, 11, 12, 13, 14, 15, 16, 17}
low := []float64{1, 2, 3, 4, 5, 6, 7, 8}
closing := []float64{5, 6, 7, 8, 9, 10, 11, 12}
volume := []int64{100, 200, 300, 400, 500, 600, 700, 800}
volume := []float64{100, 200, 300, 400, 500, 600, 700, 800}
expected := []float64{0, -7.41, -18.52, -31.69, -46.09, -61.27, -76.95, -92.97}

actual, _ := ChaikinOscillator(2, 5, low, high, closing, volume)
Expand Down Expand Up @@ -76,7 +76,7 @@ func TestPercentagePriceOscillator(t *testing.T) {
}

func TestPercentageVolumeOscillator(t *testing.T) {
volume := []int64{
volume := []float64{
6954, 4511, 4474, 4126, 4572, 3936, 3192, 3090, 3476, 3852, 3107, 3604,
4145, 5192, 3560, 3961, 4322, 3901, 3392, 4278, 4212, 4428, 3846, 3824,
4142, 4964, 4683, 4630, 4746, 4254, 4197, 4236, 3877, 4474, 3943, 3969,
Expand Down
2 changes: 1 addition & 1 deletion strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Asset struct {
Closing []float64
High []float64
Low []float64
Volume []int64
Volume []float64
}

// Strategy function. It takes an Asset and returns
Expand Down
2 changes: 1 addition & 1 deletion strategy.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type Asset struct {
Closing []float64
High []float64
Low []float64
Volume []int64
Volume []float64
}
```

Expand Down
27 changes: 15 additions & 12 deletions trend_indicators.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,12 @@ func Min(period int, values []float64) []float64 {
// PSAR = PSAR[i - 1] - ((PSAR[i - 1] - EP) * AF)
//
// If the trend is Falling:
// - PSAR is the maximum of PSAR or the previous two high values.
// - If the current high is greather than or equals to PSAR, use EP.
// - PSAR is the maximum of PSAR or the previous two high values.
// - If the current high is greather than or equals to PSAR, use EP.
//
// If the trend is Rising:
// - PSAR is the minimum of PSAR or the previous two low values.
// - If the current low is less than or equals to PSAR, use EP.
// - PSAR is the minimum of PSAR or the previous two low values.
// - If the current low is less than or equals to PSAR, use EP.
//
// If PSAR is greater than the closing, trend is falling, and the EP
// is set to the minimum of EP or the low.
Expand Down Expand Up @@ -361,9 +361,10 @@ func Qstick(period int, opening, closing []float64) []float64 {
// crosses above 80%, and oversold when they crosses below
// 20%. The J line represents the divergence.
//
//
// RSV = ((Closing - Min(Low, rPeriod))
// / (Max(High, rPeriod) - Min(Low, rPeriod))) * 100
//
// / (Max(High, rPeriod) - Min(Low, rPeriod))) * 100
//
// K = Sma(RSV, kPeriod)
// D = Sma(K, dPeriod)
// J = (3 * K) - (2 * D)
Expand Down Expand Up @@ -498,9 +499,12 @@ func Tema(period int, values []float64) []float64 {
// Trima function calculates the Triangular Moving Average (TRIMA).
//
// If period is even:
// TRIMA = SMA(period / 2, SMA((period / 2) + 1, values))
//
// TRIMA = SMA(period / 2, SMA((period / 2) + 1, values))
//
// If period is odd:
// TRIMA = SMA((period + 1) / 2, SMA((period + 1) / 2, values))
//
// TRIMA = SMA((period + 1) / 2, SMA((period + 1) / 2, values))
//
// Returns trima.
func Trima(period int, values []float64) []float64 {
Expand Down Expand Up @@ -627,14 +631,13 @@ func Vortex(high, low, closing []float64) ([]float64, []float64) {
// VWMA = Sum(Price * Volume) / Sum(Volume) for a given Period.
//
// Returns vwma
func Vwma(period int, closing []float64, volume []int64) []float64 {
floatVolume := asFloat64(volume)
vwma := divide(Sum(period, multiply(closing, floatVolume)), Sum(period, floatVolume))
func Vwma(period int, closing, volume []float64) []float64 {
vwma := divide(Sum(period, multiply(closing, volume)), Sum(period, volume))

return vwma
}

// The DefaultVwma function calculates VWMA with a period of 20.
func DefaultVwma(closing []float64, volume []int64) []float64 {
func DefaultVwma(closing, volume []float64) []float64 {
return Vwma(20, closing, volume)
}
4 changes: 2 additions & 2 deletions trend_indicators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ func TestVortex(t *testing.T) {

func TestVwma(t *testing.T) {
closing := []float64{20, 21, 21, 19, 16}
volume := []int64{100, 50, 40, 50, 100}
volume := []float64{100, 50, 40, 50, 100}
expected := []float64{20, 20.33, 20.47, 20.29, 17.84}
period := 3

Expand All @@ -305,7 +305,7 @@ func TestVwma(t *testing.T) {

func TestDefaultVwma(t *testing.T) {
closing := []float64{20, 21, 21, 19, 16}
volume := []int64{100, 50, 40, 50, 100}
volume := []float64{100, 50, 40, 50, 100}
expected := []float64{20, 20.33, 20.47, 20.17, 18.94}

actual := DefaultVwma(closing, volume)
Expand Down
6 changes: 3 additions & 3 deletions trend_strategies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestTrendStrategy(t *testing.T) {
Low: []float64{
0, 0, 0, 0, 0,
},
Volume: []int64{
Volume: []float64{
0, 0, 0, 0, 0,
},
}
Expand Down Expand Up @@ -57,7 +57,7 @@ func TestVwmaStrategy(t *testing.T) {
Low: []float64{
0, 0, 0, 0, 0,
},
Volume: []int64{
Volume: []float64{
100, 50, 40, 50, 100,
},
}
Expand Down Expand Up @@ -90,7 +90,7 @@ func TestDefaultVwmaStrategy(t *testing.T) {
Low: []float64{
0, 0, 0, 0, 0,
},
Volume: []int64{
Volume: []float64{
100, 50, 40, 50, 100,
},
}
Expand Down
54 changes: 27 additions & 27 deletions volume_indicators.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const CMF_DEFAULT_PERIOD = 20
// AD = Previous AD + CMFV
//
// Returns ad.
func AccumulationDistribution(high, low, closing []float64, volume []int64) []float64 {
func AccumulationDistribution(high, low, closing, volume []float64) []float64 {
checkSameSize(high, low, closing)

ad := make([]float64, len(closing))
Expand All @@ -39,17 +39,19 @@ func AccumulationDistribution(high, low, closing []float64, volume []int64) []fl
// On-Balance Volume (OBV). It is a technical trading momentum indicator that
// uses volume flow to predict changes in stock price.
//
// volume, if Closing > Closing-Prev
// volume, if Closing > Closing-Prev
//
// OBV = OBV-Prev + 0, if Closing = Closing-Prev
// -volume, if Closing < Closing-Prev
//
// -volume, if Closing < Closing-Prev
//
// Returns obv
func Obv(closing []float64, volume []int64) []int64 {
func Obv(closing, volume []float64) []float64 {
if len(closing) != len(volume) {
panic("not all same size")
}

obv := make([]int64, len(volume))
obv := make([]float64, len(volume))

for i := 1; i < len(obv); i++ {
obv[i] = obv[i-1]
Expand All @@ -73,9 +75,9 @@ func Obv(closing []float64, volume []int64) []int64 {
// Money Flow Index = 100 - (100 / (1 + Money Ratio))
//
// Retruns money flow index values.
func MoneyFlowIndex(period int, high, low, closing []float64, volume []int64) []float64 {
func MoneyFlowIndex(period int, high, low, closing, volume []float64) []float64 {
typicalPrice, _ := TypicalPrice(low, high, closing)
rawMoneyFlow := multiply(typicalPrice, asFloat64(volume))
rawMoneyFlow := multiply(typicalPrice, volume)

signs := extractSign(diff(rawMoneyFlow, 1))
moneyFlow := multiply(signs, rawMoneyFlow)
Expand All @@ -93,7 +95,7 @@ func MoneyFlowIndex(period int, high, low, closing []float64, volume []int64) []
}

// Default money flow index with period 14.
func DefaultMoneyFlowIndex(high, low, closing []float64, volume []int64) []float64 {
func DefaultMoneyFlowIndex(high, low, closing, volume []float64) []float64 {
return MoneyFlowIndex(14, high, low, closing, volume)
}

Expand All @@ -103,12 +105,12 @@ func DefaultMoneyFlowIndex(high, low, closing []float64, volume []int64) []float
// 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)))
func ForceIndex(period int, closing, volume []float64) []float64 {
return Ema(period, multiply(diff(closing, 1), volume))
}

// The default Force Index (FI) with window size of 13.
func DefaultForceIndex(closing []float64, volume []int64) []float64 {
func DefaultForceIndex(closing, volume []float64) []float64 {
return ForceIndex(13, closing, volume)
}

Expand All @@ -121,15 +123,15 @@ func DefaultForceIndex(closing []float64, volume []int64) []float64 {
// EMV(14) = SMA(14, EMV(1))
//
// Returns ease of movement values.
func EaseOfMovement(period int, high, low []float64, volume []int64) []float64 {
func EaseOfMovement(period int, high, low, volume []float64) []float64 {
distanceMoved := diff(divideBy(add(high, low), 2), 1)
boxRatio := divide(divideBy(asFloat64(volume), float64(100000000)), subtract(high, low))
boxRatio := divide(divideBy(volume, float64(100000000)), subtract(high, low))
emv := Sma(period, divide(distanceMoved, boxRatio))
return emv
}

// The default Ease of Movement with the default period of 14.
func DefaultEaseOfMovement(high, low []float64, volume []int64) []float64 {
func DefaultEaseOfMovement(high, low, volume []float64) []float64 {
return EaseOfMovement(14, high, low, volume)
}

Expand All @@ -139,9 +141,9 @@ func DefaultEaseOfMovement(high, low []float64, volume []int64) []float64 {
// VPT = Previous VPT + (Volume * (Current Closing - Previous Closing) / Previous Closing)
//
// Returns volume price trend values.
func VolumePriceTrend(closing []float64, volume []int64) []float64 {
func VolumePriceTrend(closing, volume []float64) []float64 {
previousClosing := shiftRightAndFillBy(1, closing[0], closing)
vpt := multiply(asFloat64(volume), divide(subtract(closing, previousClosing), previousClosing))
vpt := multiply(volume, divide(subtract(closing, previousClosing), previousClosing))
return Sum(len(vpt), vpt)
}

Expand All @@ -151,13 +153,12 @@ func VolumePriceTrend(closing []float64, volume []int64) []float64 {
// VWAP = Sum(Closing * Volume) / Sum(Volume)
//
// Returns vwap values.
func VolumeWeightedAveragePrice(period int, closing []float64, volume []int64) []float64 {
v := asFloat64(volume)
return divide(Sum(period, multiply(closing, v)), Sum(period, v))
func VolumeWeightedAveragePrice(period int, closing, volume []float64) []float64 {
return divide(Sum(period, multiply(closing, volume)), Sum(period, volume))
}

// Default volume weighted average price with period of 14.
func DefaultVolumeWeightedAveragePrice(closing []float64, volume []int64) []float64 {
func DefaultVolumeWeightedAveragePrice(closing, volume []float64) []float64 {
return VolumeWeightedAveragePrice(14, closing, volume)
}

Expand All @@ -166,14 +167,14 @@ func DefaultVolumeWeightedAveragePrice(closing []float64, volume []int64) []floa
//
// If Volume is greather than Previous Volume:
//
// NVI = Previous NVI
// NVI = Previous NVI
//
// Otherwise:
//
// NVI = Previous NVI + (((Closing - Previous Closing) / Previous Closing) * Previous NVI)
// NVI = Previous NVI + (((Closing - Previous Closing) / Previous Closing) * Previous NVI)
//
// Returns nvi values.
func NegativeVolumeIndex(closing []float64, volume []int64) []float64 {
func NegativeVolumeIndex(closing, volume []float64) []float64 {
if len(closing) != len(volume) {
panic("not all same size")
}
Expand All @@ -199,17 +200,16 @@ func NegativeVolumeIndex(closing []float64, volume []int64) []float64 {
// Money Flow Multiplier = ((Closing - Low) - (High - Closing)) / (High - Low)
// Money Flow Volume = Money Flow Multiplier * Volume
// Chaikin Money Flow = Sum(20, Money Flow Volume) / Sum(20, Volume)
//
func ChaikinMoneyFlow(high, low, closing []float64, volume []int64) []float64 {
func ChaikinMoneyFlow(high, low, closing, volume []float64) []float64 {
moneyFlowMultiplier := divide(
subtract(subtract(closing, low), subtract(high, closing)),
subtract(high, low))

moneyFlowVolume := multiply(moneyFlowMultiplier, asFloat64(volume))
moneyFlowVolume := multiply(moneyFlowMultiplier, volume)

cmf := divide(
Sum(CMF_DEFAULT_PERIOD, moneyFlowVolume),
Sum(CMF_DEFAULT_PERIOD, asFloat64(volume)))
Sum(CMF_DEFAULT_PERIOD, volume))

return cmf
}
Loading

0 comments on commit def9908

Please sign in to comment.