eighth version

This commit is contained in:
2026-06-08 11:55:36 +00:00
parent ebea17b411
commit e8b7d8e27c
15 changed files with 431 additions and 42 deletions
+11 -3
View File
@@ -86,16 +86,24 @@ func (l Loader) LatestQuote(ctx context.Context, instrumentUID string, depth int
if err != nil {
return domain.OrderBook{}, err
}
if book.ReceivedAt.IsZero() {
return domain.OrderBook{}, fmt.Errorf("quote received timestamp is missing")
quoteTs := quoteTimestamp(book)
if quoteTs.IsZero() {
return domain.OrderBook{}, fmt.Errorf("quote timestamp is missing")
}
age := l.nowUTC().Sub(book.ReceivedAt)
age := l.nowUTC().Sub(quoteTs)
if maxAge > 0 && age > maxAge {
return domain.OrderBook{}, fmt.Errorf("quote age %s exceeds %s", age, maxAge)
}
return book, nil
}
func quoteTimestamp(book domain.OrderBook) time.Time {
if !book.Time.IsZero() {
return book.Time.UTC()
}
return book.ReceivedAt.UTC()
}
func (l Loader) nowUTC() time.Time {
if l.clock == nil {
return time.Now().UTC()
+43
View File
@@ -0,0 +1,43 @@
package marketdata
import (
"context"
"strings"
"testing"
"time"
"github.com/shopspring/decimal"
"overnight-trading-bot/internal/domain"
"overnight-trading-bot/internal/tinvest"
)
type fixedClock struct {
now time.Time
}
func (c fixedClock) Now() time.Time {
return c.now
}
func (c fixedClock) Sleep(<-chan struct{}, time.Duration) bool {
return true
}
func TestLatestQuoteUsesExchangeTimestampForFreshness(t *testing.T) {
now := time.Date(2026, 6, 8, 18, 20, 0, 0, time.UTC)
gateway := tinvest.NewFakeGateway()
gateway.OrderBooks["uid"] = domain.OrderBook{
InstrumentUID: "uid",
Time: now.Add(-2 * time.Second),
ReceivedAt: now,
Bids: []domain.OrderBookLevel{{Price: decimal.NewFromInt(99), QuantityLots: 10}},
Asks: []domain.OrderBookLevel{{Price: decimal.NewFromInt(101), QuantityLots: 10}},
}
loader := NewLoader(nil, gateway)
loader.SetClock(fixedClock{now: now})
_, err := loader.LatestQuote(context.Background(), "uid", 20, time.Second)
if err == nil || !strings.Contains(err.Error(), "quote age") {
t.Fatalf("LatestQuote err=%v, want stale exchange timestamp rejection", err)
}
}