-
Notifications
You must be signed in to change notification settings - Fork 235
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add(xignitefeeder): feature to run data feeding when the market is cl…
…osed (#488) * add(xignitefeeder): feature to run data feeding when the market is closed.
- Loading branch information
Showing
6 changed files
with
152 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package feed | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/alpacahq/marketstore/v4/utils/log" | ||
) | ||
|
||
// IntervalMarketTimeChecker is used where periodic processing is needed to run even when the market is closed. | ||
type IntervalMarketTimeChecker struct { | ||
MarketTimeChecker | ||
// LastTime holds the last time that IntervalTimeChceker.IsOpen returned true. | ||
LastTime time.Time | ||
Interval time.Duration | ||
} | ||
|
||
func NewIntervalMarketTimeChecker( | ||
mtc MarketTimeChecker, | ||
interval time.Duration, | ||
) *IntervalMarketTimeChecker { | ||
return &IntervalMarketTimeChecker{ | ||
MarketTimeChecker: mtc, | ||
LastTime: time.Time{}, | ||
Interval: interval, | ||
} | ||
} | ||
|
||
// IsOpen returns true when the market is open or the interval elapsed since LastTime. | ||
func (c *IntervalMarketTimeChecker) IsOpen(t time.Time) bool { | ||
return c.MarketTimeChecker.IsOpen(t) || c.intervalElapsed(t) | ||
} | ||
|
||
func (c *IntervalMarketTimeChecker) intervalElapsed(t time.Time) bool { | ||
elapsed := t.Sub(c.LastTime) >= c.Interval | ||
if elapsed { | ||
c.LastTime = t | ||
log.Debug("[Xignite Feeder] interval elapsed since last time: " + t.String()) | ||
} | ||
return elapsed | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package feed_test | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/alpacahq/marketstore/v4/contrib/xignitefeeder/feed" | ||
) | ||
|
||
var ( | ||
jst = time.FixedZone("Asia/Tokyo", 9*60*60) | ||
exampleDate = time.Date(2021, 8, 20, 0, 0, 0, 0, time.UTC) | ||
exampleDatePlus5min = time.Date(2021, 8, 20, 0, 5, 0, 0, time.UTC) | ||
exampleDatePlus4min59s = time.Date(2021, 8, 20, 0, 4, 59, 0, time.UTC) | ||
exampleDatePlus5minInJST = time.Date(2021, 8, 20, 9, 5, 0, 0, jst) | ||
) | ||
|
||
type mockMarketTimeChecker struct { | ||
isOpen bool | ||
} | ||
|
||
func (m *mockMarketTimeChecker) IsOpen(_ time.Time) bool { | ||
return m.isOpen | ||
} | ||
func (m *mockMarketTimeChecker) Sub(_ time.Time, _ int) (time.Time, error) { | ||
panic("not implemented") | ||
} | ||
|
||
func TestIntervalMarketTimeChecker_IsOpen(t *testing.T) { | ||
t.Parallel() | ||
tests := map[string]struct { | ||
MarketTimeChecker feed.MarketTimeChecker | ||
Interval time.Duration | ||
CurrentTime time.Time | ||
LastTime time.Time | ||
want bool | ||
}{ | ||
"ok: IsOpen returns true if the interval elapsed": { | ||
MarketTimeChecker: &mockMarketTimeChecker{isOpen: false}, | ||
Interval: 5 * time.Minute, | ||
LastTime: exampleDate, | ||
CurrentTime: exampleDatePlus5min, | ||
want: true, | ||
}, | ||
"ok: IsOpen returns false if the interval has not yet elapsed": { | ||
MarketTimeChecker: &mockMarketTimeChecker{isOpen: false}, | ||
Interval: 5 * time.Minute, | ||
LastTime: exampleDate, | ||
CurrentTime: exampleDatePlus4min59s, | ||
want: false, | ||
}, | ||
"ok: time in any location can be passed": { | ||
MarketTimeChecker: &mockMarketTimeChecker{isOpen: false}, | ||
Interval: 5 * time.Minute, | ||
LastTime: exampleDate, | ||
CurrentTime: exampleDatePlus5minInJST, | ||
want: true, | ||
}, | ||
"ok: always Open if the base market time checker is IsOpen=true": { | ||
MarketTimeChecker: &mockMarketTimeChecker{isOpen: true}, | ||
Interval: 5 * time.Minute, | ||
LastTime: exampleDate, | ||
CurrentTime: exampleDate, | ||
want: true, | ||
}, | ||
} | ||
for name := range tests { | ||
tt := tests[name] | ||
t.Run(name, func(t *testing.T) { | ||
t.Parallel() | ||
// --- given --- | ||
c := feed.NewIntervalMarketTimeChecker( | ||
tt.MarketTimeChecker, | ||
tt.Interval, | ||
) | ||
c.LastTime = tt.LastTime | ||
|
||
// --- when --- | ||
got := c.IsOpen(tt.CurrentTime) | ||
|
||
// --- then --- | ||
if got != tt.want { | ||
t.Errorf("IsOpen() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters