instruments

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 16, 2026 License: MIT Imports: 13 Imported by: 0

README

kite-mcp-instruments

Go Reference

Kite instruments fetcher + cache for the algo2go ecosystem. Provides NSE/BSE symbol-to-token resolution, search by symbol/exchange/segment, TTL-based cache refresh aligned to market hours, and Manager lifecycle management (Start/Stop/Refresh).

Used by Sundeepg98/kite-mcp-server across the broker-services + MCP tool layer for symbol resolution (buy/sell/search tools), options-chain construction, market-hours gating, and Telegram trading commands.

Why a separate module?

Kite instruments is a foundational primitive any algo2go consumer that places orders or queries market data needs independent of kite-mcp-server. Hosting as a module:

  • Centralizes the Kite instruments source-of-truth across consumers
  • Lets the cache + refresh schedule version independently
  • Pairs cleanly with algo2go/kite-mcp-isttz (market-hours alignment) for the broker-data primitives stack

Stability promise

v0.x — unstable. Type signatures may evolve. Pin v0.1.0 deliberately.

Install

go get github.com/algo2go/kite-mcp-instruments@v0.1.0

Public API

  • Manager — lifecycle-managed instruments fetcher with cache
  • Cache — symbol-to-token map with TTL-based refresh
  • Instrument — DTO struct (Token, Symbol, Exchange, Segment, etc.)
  • Search helpers: BySymbol, ByExchange, BySegment, ByToken
  • IST market-hours-aligned refresh (every market-open + EOD)

Dependencies

  • github.com/algo2go/kite-mcp-isttz v0.1.0 — IST timezone + market hours
  • github.com/stretchr/testify — assertions
  • go.uber.org/goleak — goroutine-leak detection in tests

All algo2go deps are published modules; no upstream replace directives needed.

Test caveat

Some tests (TestNew_*InstrumentsManager*, TestNewConfigConstructor, TestManager_MoreAccessors) hit api.kite.trade for live instrument fetch. They fail under WSL2 DNS resolution but pass on Fly.io BOM region with direct egress. These are pre-existing CI-environment- specific flakes documented across F1-F7 + 5/5 module dispatches in the parent repo.

Reference consumer

Sundeepg98/kite-mcp-server — consumed across kc/manager_*, kc/options.go, kc/broker_services.go, kc/ports/instrument.go, kc/ops/scanner.go, kc/ops/payoff.go, kc/telegram/bot.go, mcp/market_tools.go, mcp/trade/option_tools.go, mcp/trade/options_greeks_tool.go, mcp/alerts/alert_tools.go.

License

MIT — see LICENSE.

Authors

Original design: Sundeepg98 (Zerodha Tech). Multi-module promotion (2026-05-10): algo2go contributors.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInstrumentNotFound is returned when instrument was not found in the
	// loaded map.
	ErrInstrumentNotFound = errors.New("instrument not found")

	// ErrSegmentNotFound is returned when segment was not found in the
	// loaded map.
	ErrSegmentNotFound = errors.New("instrument segment not found")
)

Functions

func ExchTokenToInstToken

func ExchTokenToInstToken(segID, exchToken uint32) uint32

ExchTokenToInstToken converts an exchange token to an instrument token.

func GetSegmentID

func GetSegmentID(instToken uint32) uint32

GetSegmentID returns the segment ID for the instrument token.

Types

type Config

type Config struct {
	UpdateConfig   *UpdateConfig          // defaults to DefaultUpdateConfig() if nil
	Logger         *slog.Logger           // required
	TestData       map[uint32]*Instrument // if set, skips HTTP loading and uses test data
	InstrumentsURL string                 // URL to fetch instruments from; defaults to Kite API URL
}

Config holds configuration for creating a new instruments manager

type Instrument

type Instrument struct {
	ID                string  `json:"id"`
	InstrumentToken   uint32  `json:"instrument_token"`
	ExchangeToken     uint32  `json:"exchange_token"`
	Tradingsymbol     string  `json:"tradingsymbol"`
	Exchange          string  `json:"exchange"`
	ISIN              string  `json:"isin"`
	Name              string  `json:"name"`
	Series            string  `json:"series"`
	LastPrice         float64 `json:"last_price"`
	Strike            float64 `json:"strike"`
	TickSize          float64 `json:"tick_size"`
	LotSize           int     `json:"lot_size"`
	Multiplier        int     `json:"multiplier"`
	InstrumentType    string  `json:"instrument_type"`
	Segment           string  `json:"segment"`
	DeliveryUnits     string  `json:"delivery_units"`
	PriceUnits        string  `json:"price_units"`
	FreezeQuantity    uint32  `json:"freeze_quantity"`
	MaxOrderQuantity  int     `json:"max_order_quantity"`
	ExpiryType        string  `json:"expiry_type"`
	ExpiryDate        string  `json:"expiry_date"`
	ExerciseStartDate string  `json:"exercise_start_date"`
	ExerciseEndDate   string  `json:"exercise_end_date"`
	IssueDate         string  `json:"issue_date"`
	ListingDate       string  `json:"listing_date"`
	MaturityDate      string  `json:"maturity_date"`
	LowerCircuitLimit float64 `json:"lower_circuit_limit"`
	UpperCircuitLimit float64 `json:"upper_circuit_limit"`

	// In FO, a large number of strikes are marked "inactive".
	Active bool `json:"active"`
}

type InstrumentManagerInterface

type InstrumentManagerInterface interface {
	// GetByID returns an instrument using the symbol (exchange:tradingsymbol).
	GetByID(id string) (Instrument, error)

	// GetByTradingsymbol returns an instrument using exchange and trading symbol.
	GetByTradingsymbol(exchange, tradingsymbol string) (Instrument, error)

	// GetByISIN returns instruments matching the given ISIN.
	GetByISIN(isin string) ([]Instrument, error)

	// GetByInstToken returns an instrument using its instrument token.
	GetByInstToken(token uint32) (Instrument, error)

	// GetByExchToken returns an instrument using exchange and exchange token.
	GetByExchToken(exch string, exchToken uint32) (Instrument, error)

	// Filter returns instruments matching the given filter function.
	Filter(filter func(Instrument) bool) []Instrument

	// GetAllByUnderlying returns F&O instruments for the given underlying.
	GetAllByUnderlying(exchange, underlying string) ([]Instrument, error)

	// Count returns the number of instruments loaded.
	Count() int

	// GetUpdateStats returns current update statistics.
	GetUpdateStats() UpdateStats

	// UpdateInstruments fetches and updates instrument data.
	UpdateInstruments() error

	// ForceUpdateInstruments forces an instrument update regardless of timing.
	ForceUpdateInstruments() error

	// Shutdown gracefully shuts down the instruments manager.
	Shutdown()
}

InstrumentManagerInterface defines operations for looking up instrument metadata (symbols, tokens, ISIN, etc.).

Anchor 5 PR 5.4 (per .research/anchor-5-prs-design.md): this interface was relocated from `kc/interfaces.go:508` to its owning package (kc/instruments) so that kc/ports/instrument.go can eventually drop its kc-parent import in PR 5.5 (Wave B-2). The legacy `kc.InstrumentManagerInterface` is preserved as a single-line type alias in kc/interfaces.go to keep the existing 10+ reverse-dep call sites compiling unchanged. Both names reference the SAME interface — Go type aliases are not new types — so satisfaction by *Manager (this package) is preserved at the alias site.

Method set (12 methods, identical to the pre-move interface — only the type qualifier changes since we are now in the instruments package):

GetByID, GetByTradingsymbol, GetByISIN — symbol/ISIN lookup
GetByInstToken, GetByExchToken         — token lookup
Filter, GetAllByUnderlying             — predicate / F&O filter
Count                                  — total loaded count
GetUpdateStats, UpdateInstruments,
ForceUpdateInstruments                 — refresh lifecycle
Shutdown                               — graceful teardown

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager provides thread-safe access to instrument data. All public methods are thread-safe and can be called concurrently.

func New

func New(cfg Config) (*Manager, error)

New creates a new instruments manager with the given configuration If TestData is provided, the manager will use test data instead of loading from HTTP

func (*Manager) Count

func (m *Manager) Count() int

Count returns the number of instruments loaded.

func (*Manager) Filter

func (m *Manager) Filter(filter func(Instrument) bool) []Instrument

Filter returns a list of instruments filtered by the given filter.

func (*Manager) ForceUpdateInstruments

func (m *Manager) ForceUpdateInstruments() error

ForceUpdateInstruments forces an instrument update regardless of when it was last updated

func (*Manager) GetAllByUnderlying

func (m *Manager) GetAllByUnderlying(exchange, underlying string) ([]Instrument, error)

GetAllByUnderlying returns a list of F&O instruments associated with the underlying tradingsymbol.

func (*Manager) GetByExchToken

func (m *Manager) GetByExchToken(exch string, exchToken uint32) (Instrument, error)

GetByExchToken takes an exchange token.

func (*Manager) GetByID

func (m *Manager) GetByID(id string) (Instrument, error)

GetByID returns an instrument using the symbol.

func (*Manager) GetByISIN

func (m *Manager) GetByISIN(isin string) ([]Instrument, error)

GetByISIN returns a set of instruments using ISIN.

func (*Manager) GetByInstToken

func (m *Manager) GetByInstToken(token uint32) (Instrument, error)

GetByInstToken returns an instrument using instrument token.

func (*Manager) GetByTradingsymbol

func (m *Manager) GetByTradingsymbol(exchange, tradingsymbol string) (Instrument, error)

GetByTradingsymbol returns an instrument using exchange and trading symbol.

func (*Manager) GetConfig

func (m *Manager) GetConfig() *UpdateConfig

GetConfig returns a copy of the current configuration. Returns a copy to prevent callers from mutating shared state.

func (*Manager) GetUpdateStats

func (m *Manager) GetUpdateStats() UpdateStats

GetUpdateStats returns current update statistics

func (*Manager) Insert

func (m *Manager) Insert(inst *Instrument)

Insert inserts a new instrument. This method is thread-safe and acquires its own write lock.

func (*Manager) LoadInitialData

func (m *Manager) LoadInitialData() error

LoadInitialData loads instruments data and should be called after manager creation

func (*Manager) LoadMap

func (m *Manager) LoadMap(tokenToInstrument map[uint32]*Instrument)

LoadMap from tokenToInstrument map to the manager. This method is thread-safe and acquires its own write lock.

func (*Manager) Shutdown

func (m *Manager) Shutdown()

Shutdown gracefully shuts down the instruments manager

func (*Manager) UpdateConfig

func (m *Manager) UpdateConfig(config *UpdateConfig)

UpdateConfig updates the manager configuration

func (*Manager) UpdateInstruments

func (m *Manager) UpdateInstruments() error

UpdateInstruments fetches instruments from Kite and updates the internal instruments data. The first call in a day will fetch instruments from the Kite API; subsequent calls within the same day will have no effect.

type UpdateConfig

type UpdateConfig struct {
	// UpdateHour is the hour in IST when instruments should be updated (0-23)
	UpdateHour int
	// UpdateMinute is the minute when instruments should be updated (0-59)
	UpdateMinute int
	// RetryAttempts is the number of retry attempts for failed updates
	RetryAttempts int
	// RetryDelay is the delay between retry attempts
	RetryDelay time.Duration
	// EnableScheduler enables automatic scheduled updates
	EnableScheduler bool
}

UpdateConfig holds configuration for instrument updates

func DefaultUpdateConfig

func DefaultUpdateConfig() *UpdateConfig

DefaultUpdateConfig returns the default update configuration

type UpdateStats

type UpdateStats struct {
	LastUpdateTime      time.Time
	LastUpdateCount     int
	TotalUpdates        int
	FailedUpdates       int
	MemoryUsageBytes    int64
	ScheduledNextUpdate time.Time
}

UpdateStats holds statistics about instrument updates

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL