- Add asset_type column to instrument table (migration 000003) - Extend market domain types with asset_type and related fields - Update proto definitions for common and market messages - Regenerate Dart and Go protobuf code - Add shared query surface for US market data - Add KIS US daily itemchartprice provider and tests - Update backtest and operator components for US market support - Update socket market mapping for new asset types - Move paper-trading-command-workflow to archive - Add agent-task for m-us-market-expansion (subtasks 02+01, 03+01, 04+02,03)
116 lines
3.1 KiB
Go
116 lines
3.1 KiB
Go
package socket
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
altv1 "git.toki-labs.com/toki/alt/packages/contracts/gen/go/alt/v1"
|
|
"git.toki-labs.com/toki/alt/packages/domain/market"
|
|
)
|
|
|
|
func instrumentToProto(inst market.Instrument) *altv1.Instrument {
|
|
return &altv1.Instrument{
|
|
Id: string(inst.ID),
|
|
Market: marketToProto(inst.Market),
|
|
Venue: venueToProto(inst.Venue),
|
|
Symbol: inst.Symbol,
|
|
Name: inst.Name,
|
|
Currency: currencyToProto(inst.Currency),
|
|
ProviderSymbols: cloneProviderSymbols(inst.ProviderSymbols),
|
|
AssetType: assetTypeToProto(inst.AssetType),
|
|
}
|
|
}
|
|
|
|
func assetTypeToProto(at market.AssetType) altv1.AssetType {
|
|
switch at {
|
|
case market.AssetTypeEquity:
|
|
return altv1.AssetType_ASSET_TYPE_EQUITY
|
|
case market.AssetTypeETF:
|
|
return altv1.AssetType_ASSET_TYPE_ETF
|
|
default:
|
|
return altv1.AssetType_ASSET_TYPE_UNSPECIFIED
|
|
}
|
|
}
|
|
|
|
func assetTypeFromProto(at altv1.AssetType) (market.AssetType, error) {
|
|
switch at {
|
|
case altv1.AssetType_ASSET_TYPE_UNSPECIFIED:
|
|
return "", nil
|
|
case altv1.AssetType_ASSET_TYPE_EQUITY:
|
|
return market.AssetTypeEquity, nil
|
|
case altv1.AssetType_ASSET_TYPE_ETF:
|
|
return market.AssetTypeETF, nil
|
|
default:
|
|
return "", fmt.Errorf("unsupported asset type %q", at.String())
|
|
}
|
|
}
|
|
|
|
func instrumentsToProto(insts []market.Instrument) []*altv1.Instrument {
|
|
out := make([]*altv1.Instrument, len(insts))
|
|
for i, inst := range insts {
|
|
out[i] = instrumentToProto(inst)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func barToProto(bar market.Bar) *altv1.Bar {
|
|
return &altv1.Bar{
|
|
InstrumentId: string(bar.InstrumentID),
|
|
Timeframe: timeframeToProto(bar.Timeframe),
|
|
TimestampUnixMs: timeToUnixMs(bar.Timestamp),
|
|
Open: priceToProto(bar.Open),
|
|
High: priceToProto(bar.High),
|
|
Low: priceToProto(bar.Low),
|
|
Close: priceToProto(bar.Close),
|
|
Volume: quantityToProto(bar.Volume),
|
|
}
|
|
}
|
|
|
|
func barsToProto(bars []market.Bar) []*altv1.Bar {
|
|
out := make([]*altv1.Bar, len(bars))
|
|
for i, bar := range bars {
|
|
out[i] = barToProto(bar)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// venueFromProto converts a proto venue to the domain venue. The unspecified
|
|
// venue maps to an empty domain venue because an import selector may not pin a
|
|
// venue (e.g. a watchlist selector); only out-of-range enum values are an error.
|
|
func venueFromProto(v altv1.Venue) (market.Venue, error) {
|
|
switch v {
|
|
case altv1.Venue_VENUE_UNSPECIFIED:
|
|
return "", nil
|
|
case altv1.Venue_VENUE_KRX:
|
|
return market.VenueKRX, nil
|
|
case altv1.Venue_VENUE_NASDAQ:
|
|
return market.VenueNASDAQ, nil
|
|
case altv1.Venue_VENUE_NYSE:
|
|
return market.VenueNYSE, nil
|
|
default:
|
|
return "", fmt.Errorf("unsupported venue %q", v.String())
|
|
}
|
|
}
|
|
|
|
func venueToProto(v market.Venue) altv1.Venue {
|
|
switch v {
|
|
case market.VenueKRX:
|
|
return altv1.Venue_VENUE_KRX
|
|
case market.VenueNASDAQ:
|
|
return altv1.Venue_VENUE_NASDAQ
|
|
case market.VenueNYSE:
|
|
return altv1.Venue_VENUE_NYSE
|
|
default:
|
|
return altv1.Venue_VENUE_UNSPECIFIED
|
|
}
|
|
}
|
|
|
|
func cloneProviderSymbols(symbols map[string]string) map[string]string {
|
|
if len(symbols) == 0 {
|
|
return nil
|
|
}
|
|
out := make(map[string]string, len(symbols))
|
|
for k, v := range symbols {
|
|
out[k] = v
|
|
}
|
|
return out
|
|
}
|