Skip to content

Commit

Permalink
feature: extend indicators, extend seriesbase methods
Browse files Browse the repository at this point in the history
  • Loading branch information
zenixls2 committed Jun 29, 2022
1 parent 69533c0 commit 70f4676
Show file tree
Hide file tree
Showing 32 changed files with 253 additions and 103 deletions.
6 changes: 5 additions & 1 deletion pkg/indicator/ad.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Accumulation/Distribution Indicator (A/D)
*/
//go:generate callbackgen -type AD
type AD struct {
types.SeriesBase
types.IntervalWindow
Values types.Float64Slice
PrePrice float64
Expand All @@ -23,6 +24,9 @@ type AD struct {
}

func (inc *AD) Update(high, low, cloze, volume float64) {
if len(inc.Values) == 0 {
inc.SeriesBase.Series = inc
}
var moneyFlowVolume float64
if high == low {
moneyFlowVolume = 0
Expand Down Expand Up @@ -53,7 +57,7 @@ func (inc *AD) Length() int {
return len(inc.Values)
}

var _ types.Series = &AD{}
var _ types.SeriesExtend = &AD{}

func (inc *AD) calculateAndUpdate(kLines []types.KLine) {
for _, k := range kLines {
Expand Down
22 changes: 13 additions & 9 deletions pkg/indicator/alma.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import (
// @param sigma: the standard deviation applied to the combo line. This makes the combo line sharper
//go:generate callbackgen -type ALMA
type ALMA struct {
types.SeriesBase
types.IntervalWindow // required
Offset float64 // required: recommend to be 5
Sigma int // required: recommend to be 0.5
Weight []float64
Sum float64
weight []float64
sum float64
input []float64
Values types.Float64Slice
UpdateCallbacks []func(value float64)
Expand All @@ -27,26 +28,27 @@ const MaxNumOfALMA = 5_000
const MaxNumOfALMATruncateSize = 100

func (inc *ALMA) Update(value float64) {
if inc.Weight == nil {
inc.Weight = make([]float64, inc.Window)
if inc.weight == nil {
inc.SeriesBase.Series = inc
inc.weight = make([]float64, inc.Window)
m := inc.Offset * (float64(inc.Window) - 1.)
s := float64(inc.Window) / float64(inc.Sigma)
inc.Sum = 0.
inc.sum = 0.
for i := 0; i < inc.Window; i++ {
diff := float64(i) - m
wt := math.Exp(-diff * diff / 2. / s / s)
inc.Sum += wt
inc.Weight[i] = wt
inc.sum += wt
inc.weight[i] = wt
}
}
inc.input = append(inc.input, value)
if len(inc.input) >= inc.Window {
weightedSum := 0.0
inc.input = inc.input[len(inc.input)-inc.Window:]
for i := 0; i < inc.Window; i++ {
weightedSum += inc.Weight[inc.Window-i-1] * inc.input[i]
weightedSum += inc.weight[inc.Window-i-1] * inc.input[i]
}
inc.Values.Push(weightedSum / inc.Sum)
inc.Values.Push(weightedSum / inc.sum)
if len(inc.Values) > MaxNumOfALMA {
inc.Values = inc.Values[MaxNumOfALMATruncateSize-1:]
}
Expand All @@ -71,6 +73,8 @@ func (inc *ALMA) Length() int {
return len(inc.Values)
}

var _ types.SeriesExtend = &ALMA{}

func (inc *ALMA) calculateAndUpdate(allKLines []types.KLine) {
if inc.input == nil {
for _, k := range allKLines {
Expand Down
4 changes: 3 additions & 1 deletion pkg/indicator/atr.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

//go:generate callbackgen -type ATR
type ATR struct {
types.SeriesBase
types.IntervalWindow
PercentageVolatility types.Float64Slice

Expand All @@ -25,6 +26,7 @@ func (inc *ATR) Update(high, low, cloze float64) {
}

if inc.RMA == nil {
inc.SeriesBase.Series = inc
inc.RMA = &RMA{
IntervalWindow: types.IntervalWindow{Window: inc.Window},
Adjust: true,
Expand Down Expand Up @@ -73,7 +75,7 @@ func (inc *ATR) Length() int {
return inc.RMA.Length()
}

var _ types.Series = &ATR{}
var _ types.SeriesExtend = &ATR{}

func (inc *ATR) CalculateAndUpdate(kLines []types.KLine) {
for _, k := range kLines {
Expand Down
16 changes: 8 additions & 8 deletions pkg/indicator/boll.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,20 @@ type BOLL struct {

type BandType int

func (inc *BOLL) GetUpBand() types.Series {
return &inc.UpBand
func (inc *BOLL) GetUpBand() types.SeriesExtend {
return types.NewSeries(&inc.UpBand)
}

func (inc *BOLL) GetDownBand() types.Series {
return &inc.DownBand
func (inc *BOLL) GetDownBand() types.SeriesExtend {
return types.NewSeries(&inc.DownBand)
}

func (inc *BOLL) GetSMA() types.Series {
return &inc.SMA
func (inc *BOLL) GetSMA() types.SeriesExtend {
return types.NewSeries(&inc.SMA)
}

func (inc *BOLL) GetStdDev() types.Series {
return &inc.StdDev
func (inc *BOLL) GetStdDev() types.SeriesExtend {
return types.NewSeries(&inc.StdDev)
}

func (inc *BOLL) LastUpBand() float64 {
Expand Down
4 changes: 3 additions & 1 deletion pkg/indicator/cci.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
// with modification of ddof=0 to let standard deviation to be divided by N instead of N-1
//go:generate callbackgen -type CCI
type CCI struct {
types.SeriesBase
types.IntervalWindow
Input types.Float64Slice
TypicalPrice types.Float64Slice
Expand All @@ -23,6 +24,7 @@ type CCI struct {

func (inc *CCI) Update(value float64) {
if len(inc.TypicalPrice) == 0 {
inc.SeriesBase.Series = inc
inc.TypicalPrice.Push(value)
inc.Input.Push(value)
return
Expand Down Expand Up @@ -75,7 +77,7 @@ func (inc *CCI) Length() int {
return len(inc.Values)
}

var _ types.Series = &CCI{}
var _ types.SeriesExtend = &CCI{}

var three = fixedpoint.NewFromInt(3)

Expand Down
7 changes: 6 additions & 1 deletion pkg/indicator/cma.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,23 @@ import (
// Refer: https://en.wikipedia.org/wiki/Moving_average
//go:generate callbackgen -type CA
type CA struct {
types.SeriesBase
Interval types.Interval
Values types.Float64Slice
length float64
UpdateCallbacks []func(value float64)
}

func (inc *CA) Update(x float64) {
if len(inc.Values) == 0 {
inc.SeriesBase.Series = inc
}
newVal := (inc.Values.Last()*inc.length + x) / (inc.length + 1.)
inc.length += 1
inc.Values.Push(newVal)
if len(inc.Values) > MaxNumOfEWMA {
inc.Values = inc.Values[MaxNumOfEWMATruncateSize-1:]
inc.length = float64(len(inc.Values))
}
}

Expand All @@ -41,7 +46,7 @@ func (inc *CA) Length() int {
return len(inc.Values)
}

var _ types.Series = &CA{}
var _ types.SeriesExtend = &CA{}

func (inc *CA) calculateAndUpdate(allKLines []types.KLine) {
for _, k := range allKLines {
Expand Down
4 changes: 3 additions & 1 deletion pkg/indicator/dema.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
//go:generate callbackgen -type DEMA
type DEMA struct {
types.IntervalWindow
types.SeriesBase
Values types.Float64Slice
a1 *EWMA
a2 *EWMA
Expand All @@ -19,6 +20,7 @@ type DEMA struct {

func (inc *DEMA) Update(value float64) {
if len(inc.Values) == 0 {
inc.SeriesBase.Series = inc
inc.a1 = &EWMA{IntervalWindow: types.IntervalWindow{inc.Interval, inc.Window}}
inc.a2 = &EWMA{IntervalWindow: types.IntervalWindow{inc.Interval, inc.Window}}
}
Expand Down Expand Up @@ -46,7 +48,7 @@ func (inc *DEMA) Length() int {
return len(inc.Values)
}

var _ types.Series = &DEMA{}
var _ types.SeriesExtend = &DEMA{}

func (inc *DEMA) calculateAndUpdate(allKLines []types.KLine) {
if inc.a1 == nil {
Expand Down
12 changes: 6 additions & 6 deletions pkg/indicator/dmi.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ type DMI struct {
types.IntervalWindow
ADXSmoothing int
atr *ATR
DMP types.UpdatableSeries
DMN types.UpdatableSeries
DMP types.UpdatableSeriesExtend
DMN types.UpdatableSeriesExtend
DIPlus *types.Queue
DIMinus *types.Queue
ADX types.UpdatableSeries
ADX types.UpdatableSeriesExtend
PrevHigh, PrevLow float64
UpdateCallbacks []func(diplus, diminus, adx float64)
}
Expand Down Expand Up @@ -71,15 +71,15 @@ func (inc *DMI) Update(high, low, cloze float64) {

}

func (inc *DMI) GetDIPlus() types.Series {
func (inc *DMI) GetDIPlus() types.SeriesExtend {
return inc.DIPlus
}

func (inc *DMI) GetDIMinus() types.Series {
func (inc *DMI) GetDIMinus() types.SeriesExtend {
return inc.DIMinus
}

func (inc *DMI) GetADX() types.Series {
func (inc *DMI) GetADX() types.SeriesExtend {
return inc.ADX
}

Expand Down
4 changes: 3 additions & 1 deletion pkg/indicator/drift.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
// could be used in Monte Carlo Simulations
//go:generate callbackgen -type Drift
type Drift struct {
types.SeriesBase
types.IntervalWindow
chng *types.Queue
Values types.Float64Slice
Expand All @@ -22,6 +23,7 @@ type Drift struct {

func (inc *Drift) Update(value float64) {
if inc.chng == nil {
inc.SeriesBase.Series = inc
inc.SMA = &SMA{IntervalWindow: types.IntervalWindow{Interval: inc.Interval, Window: inc.Window}}
inc.chng = types.NewQueue(inc.Window)
inc.LastValue = value
Expand Down Expand Up @@ -64,7 +66,7 @@ func (inc *Drift) Length() int {
return inc.Values.Length()
}

var _ types.Series = &Drift{}
var _ types.SeriesExtend = &Drift{}

func (inc *Drift) calculateAndUpdate(allKLines []types.KLine) {
if inc.chng == nil {
Expand Down
4 changes: 3 additions & 1 deletion pkg/indicator/emv.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

//go:generate callbackgen -type EMV
type EMV struct {
types.SeriesBase
types.IntervalWindow
prevH float64
prevL float64
Expand All @@ -25,6 +26,7 @@ func (inc *EMV) Update(high, low, vol float64) {
inc.EMVScale = DefaultEMVScale
}
if inc.prevH == 0 || inc.Values == nil {
inc.SeriesBase.Series = inc
inc.prevH = high
inc.prevL = low
inc.Values = &SMA{IntervalWindow: inc.IntervalWindow}
Expand Down Expand Up @@ -59,7 +61,7 @@ func (inc *EMV) Length() int {
return inc.Values.Length()
}

var _ types.Series = &EMV{}
var _ types.SeriesExtend = &EMV{}

func (inc *EMV) calculateAndUpdate(allKLines []types.KLine) {
if inc.Values == nil {
Expand Down
4 changes: 3 additions & 1 deletion pkg/indicator/ewma.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const MaxNumOfEWMATruncateSize = 100
//go:generate callbackgen -type EWMA
type EWMA struct {
types.IntervalWindow
types.SeriesBase
Values types.Float64Slice
LastOpenTime time.Time

Expand All @@ -26,6 +27,7 @@ func (inc *EWMA) Update(value float64) {
var multiplier = 2.0 / float64(1+inc.Window)

if len(inc.Values) == 0 {
inc.SeriesBase.Series = inc
inc.Values.Push(value)
return
} else if len(inc.Values) > MaxNumOfEWMA {
Expand Down Expand Up @@ -136,4 +138,4 @@ func (inc *EWMA) Bind(updater KLineWindowUpdater) {
updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate)
}

var _ types.Series = &EWMA{}
var _ types.SeriesExtend = &EWMA{}
4 changes: 3 additions & 1 deletion pkg/indicator/hull.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
// Refer URL: https://fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/hull-moving-average
//go:generate callbackgen -type HULL
type HULL struct {
types.SeriesBase
types.IntervalWindow
ma1 *EWMA
ma2 *EWMA
Expand All @@ -20,6 +21,7 @@ type HULL struct {

func (inc *HULL) Update(value float64) {
if inc.result == nil {
inc.SeriesBase.Series = inc
inc.ma1 = &EWMA{IntervalWindow: types.IntervalWindow{inc.Interval, inc.Window / 2}}
inc.ma2 = &EWMA{IntervalWindow: types.IntervalWindow{inc.Interval, inc.Window}}
inc.result = &EWMA{IntervalWindow: types.IntervalWindow{inc.Interval, int(math.Sqrt(float64(inc.Window)))}}
Expand Down Expand Up @@ -50,7 +52,7 @@ func (inc *HULL) Length() int {
return inc.result.Length()
}

var _ types.Series = &HULL{}
var _ types.SeriesExtend = &HULL{}

// TODO: should we just ignore the possible overlapping?
func (inc *HULL) calculateAndUpdate(allKLines []types.KLine) {
Expand Down
7 changes: 5 additions & 2 deletions pkg/indicator/line.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
// 3. resistance
// of the market data, defined with series interface
type Line struct {
types.SeriesBase
types.IntervalWindow
start float64
end float64
Expand Down Expand Up @@ -63,14 +64,16 @@ func (l *Line) SetXY2(index int, value float64) {
}

func NewLine(startIndex int, startValue float64, endIndex int, endValue float64, interval types.Interval) *Line {
return &Line{
line := &Line{
start: startValue,
end: endValue,
startIndex: startIndex,
endIndex: endIndex,
currentTime: time.Time{},
Interval: interval,
}
line.SeriesBase.Series = line
return line
}

var _ types.Series = &Line{}
var _ types.SeriesExtend = &Line{}
Loading

0 comments on commit 70f4676

Please sign in to comment.