Skip to content

Commit

Permalink
Performance: Ticks#Goto will only load if the requested time is not c…
Browse files Browse the repository at this point in the history
…urrently loaded

Performance: Ticks#Goto will seek to the requested time based on current cursor.
In a use case where ticks is used to only load until a bar is filled will benefit from this algorithm greatly.
The new algorithm will go to previous tick once, and finish.
If compared to previous algorithm where it will always seek from beginning to the requested time.
  • Loading branch information
edward-yakop committed Jan 27, 2021
1 parent db7e59d commit 4c253c7
Showing 1 changed file with 79 additions and 26 deletions.
105 changes: 79 additions & 26 deletions api/tickdata/ticks/ticks.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,24 @@ func (t *Ticks) Goto(to time.Time) (isSuccess bool, err error) {

to = to.In(time.UTC) // Done to ease debugging
t.isCompleted = false
for currTime := to; currTime.Before(t.end); currTime = currTime.Add(time.Hour) {
bi := bi5.New(currTime, t.symbol, t.downloadFolderPath)

// Download might return errors when there's no tick data during weekend or holiday
if bi.Download() == nil {
t.ticks, err = bi.Ticks()
if err != nil {
t.complete()
return
} else if len(t.ticks) != 0 {
t.ticksDayHour = currTime
t.ticksIdx = t.searchTickIdx()
t.currTick = nil

isSuccess, err = t.Next()
currTick := t.currTick
for isSuccess && (to.After(currTick.UTC()) || to.Equal(currTick.UTC())) {
isSuccess, err = t.Next()
currTick = t.Current()
for currTime := t.timeToHour(to); currTime.Before(t.end); currTime = currTime.Add(time.Hour) {
if t.ticksDayHour.Equal(currTime) {
return t.resetTicksPointer(to)
} else {
bi := bi5.New(currTime, t.symbol, t.downloadFolderPath)

// Download might return errors when there's no tick data during weekend or holiday
if bi.Download() == nil {
t.ticks, err = bi.Ticks()
if err != nil {
t.complete()
return
} else if len(t.ticks) != 0 {
t.ticksIdx = 0
t.ticksDayHour = currTime
t.seek(to)
return true, nil
}

return
}
}
}
Expand All @@ -119,16 +115,73 @@ func (t Ticks) nextDownloadHour() time.Time {
return time.Date(next.Year(), next.Month(), next.Day(), next.Hour(), 0, 0, 0, time.UTC)
}

func (t Ticks) searchTickIdx() (idx int) {
func (t *Ticks) seek(target time.Time) {
count := len(t.ticks)
for idx = 0; idx < count; idx++ {
tick := t.ticks[idx]
if !tick.UTC().Before(t.start) {
i := t.ticksIdx
for ; i < count; i++ {
tickTime := t.ticks[i].UTC()
if tickTime.After(target) {
break
}
}

return idx - 1
if i > 0 {
i--
}
t.ticksIdx = i
t.currTick = t.ticks[i]
}

func (t Ticks) resetTicksPointer(to time.Time) (bool, error) {
if t.currTick == nil { // If beginning of hour
return t.Next()
}

currTickTime := t.currTick.UTC()
if currTickTime.Before(to) {
t.seek(to)
return true, nil
}

// CurrentTick before target is handled above,
// We only need to search backward
prevTick := t.prevTick()
for {
if currTickTime.Equal(to) {
return true, nil
} else {
if prevTick != nil {
prevTrickTime := prevTick.UTC()
if prevTrickTime.Before(to) {
return true, nil
} else {
// Prev is Equal or before, either way, we need to go left
t.ticksIdx--
t.currTick = prevTick

if prevTrickTime.Equal(to) {
// If it's Equal, we're done
return true, nil
}
}
} else {
t.ticksIdx = 0
t.currTick = t.ticks[0]
return true, nil
}
}
}
}

func (t Ticks) prevTick() *tickdata.TickData {
if t.ticksIdx == 0 {
return nil
}
return t.ticks[t.ticksIdx-1]
}

func (t Ticks) timeToHour(tt time.Time) time.Time {
return time.Date(tt.Year(), tt.Month(), tt.Day(), tt.Hour(), 0, 0, 0, tt.Location()).UTC()
}

var isLogSetup = false
Expand Down

0 comments on commit 4c253c7

Please sign in to comment.