Skip to content

Commit

Permalink
expose circular buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
iamjinlei committed Jun 23, 2021
1 parent 1df8e43 commit ceb57e9
Show file tree
Hide file tree
Showing 13 changed files with 93 additions and 85 deletions.
10 changes: 5 additions & 5 deletions adxr.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ package tart
type AdxR struct {
n int64
adx *Adx
hist *cBuf
hist *CBuf
}

func NewAdxR(n int64) *AdxR {
return &AdxR{
n: n,
adx: NewAdx(n),
hist: newCBuf(n - 1),
hist: NewCBuf(n - 1),
}
}

func (a *AdxR) Update(h, l, c float64) float64 {
v := a.adx.Update(h, l, c)
old := a.hist.append(v)
old := a.hist.Append(v)

if a.hist.size() <= 3*a.n-2 {
if a.hist.Size() <= 3*a.n-2 {
return 0
}

Expand All @@ -33,7 +33,7 @@ func (a *AdxR) InitPeriod() int64 {
}

func (a *AdxR) Valid() bool {
return a.hist.size() > a.InitPeriod()
return a.hist.Size() > a.InitPeriod()
}

// Average Directional Movement Index Rating (ADXR) is a simple
Expand Down
34 changes: 21 additions & 13 deletions cbuf.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
package tart

// circular buffer maintaining fixed sized history
type cBuf struct {
type CBuf struct {
n int64
hist []float64
oldest int64
newest int64
sz int64
}

func newCBuf(n int64) *cBuf {
return &cBuf{
func NewCBuf(n int64) *CBuf {
return &CBuf{
n: n,
hist: make([]float64, n),
oldest: 0,
newest: n - 1,
}
}

func (c *cBuf) append(v float64) float64 {
// Append latest value and return oldest one
func (c *CBuf) Append(v float64) float64 {
old := c.hist[c.oldest]
c.hist[c.oldest] = v
c.newest = c.oldest
Expand All @@ -27,39 +28,44 @@ func (c *cBuf) append(v float64) float64 {
return old
}

func (c *cBuf) size() int64 {
// Number of values appended
func (c *CBuf) Size() int64 {
return c.sz
}

func (c *cBuf) indexToSeq(idx int64) int64 {
// From circular buf position to total sequence index
func (c *CBuf) IndexToSeq(idx int64) int64 {
if idx < c.oldest {
return c.sz - (c.oldest - idx)
} else {
return c.sz - c.n + (idx - c.oldest)
}
}

func (c *cBuf) newestIndex() int64 {
// Index of the latest value
func (c *CBuf) NewestIndex() int64 {
return c.newest
}

func (c *cBuf) oldestIndex() int64 {
// Index of the oldest value
func (c *CBuf) OldestIndex() int64 {
return c.oldest
}

// nthNewest(0) = newest
// nthNewest(1) = 2nd newest
func (c *cBuf) nthNewest(offset int64) float64 {
func (c *CBuf) NthNewest(offset int64) float64 {
return c.hist[(c.newest+c.n-offset)%c.n]
}

// nthOldest(0) = oldest
// nthOldest(1) = 2nd oldest
func (c *cBuf) nthOldest(offset int64) float64 {
func (c *CBuf) NthOldest(offset int64) float64 {
return c.hist[(c.oldest+offset)%c.n]
}

func (c *cBuf) min() (int64, float64) {
// Min value in buf
func (c *CBuf) Min() (int64, float64) {
min := c.hist[0]
minIdx := int64(0)
for i := 1; i < len(c.hist); i++ {
Expand All @@ -71,7 +77,8 @@ func (c *cBuf) min() (int64, float64) {
return minIdx, min
}

func (c *cBuf) max() (int64, float64) {
// Max value in buf
func (c *CBuf) Max() (int64, float64) {
max := c.hist[0]
maxIdx := int64(0)
for i := 1; i < len(c.hist); i++ {
Expand All @@ -83,7 +90,8 @@ func (c *cBuf) max() (int64, float64) {
return maxIdx, max
}

func (c *cBuf) iter(fn func(v float64)) {
// Iterate through buf elements and call function for each
func (c *CBuf) Iter(fn func(v float64)) {
idx := c.oldest
for i := int64(0); i < c.n; i++ {
fn(c.hist[idx])
Expand Down
26 changes: 13 additions & 13 deletions cbuf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,34 @@ import (
)

func TestCBuf(t *testing.T) {
c := newCBuf(7)
c := NewCBuf(7)
for v := 1.0; v < 10; v++ {
c.append(v)
assert.EqualValues(t, v, c.nthNewest(0))
assert.EqualValues(t, v, c.size())
assert.EqualValues(t, int(v-1)%7, c.newestIndex())
assert.EqualValues(t, int(v)%7, c.oldestIndex())
c.Append(v)
assert.EqualValues(t, v, c.NthNewest(0))
assert.EqualValues(t, v, c.Size())
assert.EqualValues(t, int(v-1)%7, c.NewestIndex())
assert.EqualValues(t, int(v)%7, c.OldestIndex())
}

// 8,9,3,4,5,6,7
// ^
// newest
expected := []float64{9, 8, 7, 6, 5, 4, 3}
for idx, ev := range expected {
assert.EqualValues(t, ev, c.nthNewest(int64(idx)))
assert.EqualValues(t, ev, c.NthNewest(int64(idx)))
}
expected = []float64{3, 4, 5, 6, 7, 8, 9}
for idx, ev := range expected {
assert.EqualValues(t, ev, c.nthOldest(int64(idx)))
assert.EqualValues(t, ev, c.NthOldest(int64(idx)))
}

assert.EqualValues(t, 2, c.indexToSeq(2))
assert.EqualValues(t, 6, c.indexToSeq(6))
assert.EqualValues(t, 7, c.indexToSeq(0))
assert.EqualValues(t, 8, c.indexToSeq(1))
assert.EqualValues(t, 2, c.IndexToSeq(2))
assert.EqualValues(t, 6, c.IndexToSeq(6))
assert.EqualValues(t, 7, c.IndexToSeq(0))
assert.EqualValues(t, 8, c.IndexToSeq(1))

sum := float64(0)
c.iter(func(v float64) {
c.Iter(func(v float64) {
sum += v
})
assert.EqualValues(t, 42, sum)
Expand Down
10 changes: 5 additions & 5 deletions dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,29 @@ import (
// Average deviation from mean value.
type Dev struct {
n int64
hist *cBuf
hist *CBuf
sum float64
}

func NewDev(n int64) *Dev {
return &Dev{
n: n,
hist: newCBuf(n),
hist: NewCBuf(n),
sum: 0,
}
}

func (d *Dev) Update(v float64) float64 {
old := d.hist.append(v)
old := d.hist.Append(v)
d.sum += v - old

if d.hist.size() < d.n {
if d.hist.Size() < d.n {
return 0
}

mean := d.sum / float64(d.n)
sum := float64(0)
d.hist.iter(func(v float64) {
d.hist.Iter(func(v float64) {
sum += math.Abs(v - mean)
})

Expand Down
6 changes: 3 additions & 3 deletions diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ package tart
// their point values.
type Diff struct {
n int64
hist *cBuf
hist *CBuf
sz int64
}

func NewDiff(n int64) *Diff {
return &Diff{
n: n,
hist: newCBuf(n),
hist: NewCBuf(n),
sz: 0,
}
}

func (d *Diff) Update(v float64) float64 {
d.sz++

old := d.hist.append(v)
old := d.hist.Append(v)

if d.sz <= d.n {
return 0
Expand Down
18 changes: 9 additions & 9 deletions max.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,44 @@ package tart
// Max value of the selected period.
type Max struct {
n int64
hist *cBuf
hist *CBuf
max float64
maxIdx int64
}

func NewMax(n int64) *Max {
return &Max{
n: n,
hist: newCBuf(n),
hist: NewCBuf(n),
max: 0,
maxIdx: 0,
}
}

func (m *Max) Update(v float64) (int64, float64) {
m.hist.append(v)
m.hist.Append(v)

if m.hist.size() < m.n {
if m.hist.Size() < m.n {
return 0, 0
}

if m.hist.size() == m.n || m.maxIdx == m.hist.newestIndex() {
m.maxIdx, m.max = m.hist.max()
if m.hist.Size() == m.n || m.maxIdx == m.hist.NewestIndex() {
m.maxIdx, m.max = m.hist.Max()
} else if m.max <= v {
// conforming to TA-Lib which updates maxIdx on equality
m.max = v
m.maxIdx = m.hist.newestIndex()
m.maxIdx = m.hist.NewestIndex()
}

return m.hist.indexToSeq(m.maxIdx), m.max
return m.hist.IndexToSeq(m.maxIdx), m.max
}

func (m *Max) InitPeriod() int64 {
return m.n - 1
}

func (m *Max) Valid() bool {
return m.hist.size() > m.InitPeriod()
return m.hist.Size() > m.InitPeriod()
}

// Max value of the selected period.
Expand Down
18 changes: 9 additions & 9 deletions min.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,44 @@ package tart
// Min value of the selected period.
type Min struct {
n int64
hist *cBuf
hist *CBuf
min float64
minIdx int64
}

func NewMin(n int64) *Min {
return &Min{
n: n,
hist: newCBuf(n),
hist: NewCBuf(n),
min: 0,
minIdx: 0,
}
}

func (m *Min) Update(v float64) (int64, float64) {
m.hist.append(v)
m.hist.Append(v)

if m.hist.size() < m.n {
if m.hist.Size() < m.n {
return 0, 0
}

if m.hist.size() == m.n || m.minIdx == m.hist.newestIndex() {
m.minIdx, m.min = m.hist.min()
if m.hist.Size() == m.n || m.minIdx == m.hist.NewestIndex() {
m.minIdx, m.min = m.hist.Min()
} else if m.min >= v {
// conforming to TA-Lib which updates minIdx on equality
m.min = v
m.minIdx = m.hist.newestIndex()
m.minIdx = m.hist.NewestIndex()
}

return m.hist.indexToSeq(m.minIdx), m.min
return m.hist.IndexToSeq(m.minIdx), m.min
}

func (m *Min) InitPeriod() int64 {
return m.n - 1
}

func (m *Min) Valid() bool {
return m.hist.size() > m.InitPeriod()
return m.hist.Size() > m.InitPeriod()
}

// Min value of the selected period.
Expand Down
6 changes: 3 additions & 3 deletions roc.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@ package tart
// https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/roc
type Roc struct {
n int64
hist *cBuf
hist *CBuf
sz int64
}

func NewRoc(n int64) *Roc {
return &Roc{
n: n,
hist: newCBuf(n),
hist: NewCBuf(n),
sz: 0,
}
}

func (r *Roc) Update(v float64) float64 {
r.sz++

old := r.hist.append(v)
old := r.hist.Append(v)

if r.sz <= r.n {
return 0
Expand Down
Loading

0 comments on commit ceb57e9

Please sign in to comment.