alt/services/worker/internal/backtest/bar_source.go
toki 8c3c4ba5a2 feat: operator surface phase updates, worker backtest/kis live client, binary utilities
- Add bin/kis-paper-daily-smoke and bin/kis-sops-env utilities
- Update agent-roadmap for operator surface phase
- Add worker backtest bar source and Kis live client
- Update KIS live secret configuration and documentation
- Refine worker datacheck and daily chart price providers
2026-06-03 12:10:48 +09:00

53 lines
1.5 KiB
Go

package backtest
import (
"context"
"fmt"
"sort"
"time"
"git.toki-labs.com/toki/alt/packages/domain/market"
"git.toki-labs.com/toki/alt/services/worker/internal/storage"
)
// StorageBarSource adapts worker market-data storage ports to the backtest
// engine's market/timeframe/date-range input boundary.
type StorageBarSource struct {
instruments storage.InstrumentStore
bars storage.BarStore
}
func NewStorageBarSource(instruments storage.InstrumentStore, bars storage.BarStore) *StorageBarSource {
return &StorageBarSource{instruments: instruments, bars: bars}
}
func (s *StorageBarSource) GetBars(ctx context.Context, mkt market.Market, timeframe market.Timeframe, from, to time.Time) ([]market.Bar, error) {
if s == nil || s.instruments == nil || s.bars == nil {
return nil, fmt.Errorf("backtest storage bar source: storage is not configured")
}
instruments, err := s.instruments.ListInstruments(ctx)
if err != nil {
return nil, fmt.Errorf("backtest storage bar source: list instruments: %w", err)
}
var out []market.Bar
for _, inst := range instruments {
if inst.Market != mkt {
continue
}
bars, err := s.bars.GetBars(ctx, inst.ID, timeframe, from, to)
if err != nil {
return nil, fmt.Errorf("backtest storage bar source: get bars for %q: %w", inst.ID, err)
}
out = append(out, bars...)
}
sort.Slice(out, func(i, j int) bool {
if out[i].Timestamp.Equal(out[j].Timestamp) {
return out[i].InstrumentID < out[j].InstrumentID
}
return out[i].Timestamp.Before(out[j].Timestamp)
})
return out, nil
}