aboutsummaryrefslogtreecommitdiff
path: root/backend/internal/ibd/search.go
diff options
context:
space:
mode:
authorGravatar Anshul Gupta <ansg191@anshulg.com> 2024-08-11 13:15:50 -0700
committerGravatar Anshul Gupta <ansg191@anshulg.com> 2024-08-11 13:15:50 -0700
commit6a3c21fb0b1c126849f2bbff494403bbe901448e (patch)
tree5d7805524357c2c8a9819c39d2051a4e3633a1d5 /backend/internal/ibd/search.go
parent29c6040a51616e9e4cf6c70ee16391b2a3b238c9 (diff)
parentf34b92ded11b07f78575ac62c260a380c468e5ea (diff)
downloadibd-trader-6a3c21fb0b1c126849f2bbff494403bbe901448e.tar.gz
ibd-trader-6a3c21fb0b1c126849f2bbff494403bbe901448e.tar.zst
ibd-trader-6a3c21fb0b1c126849f2bbff494403bbe901448e.zip
Merge remote-tracking branch 'backend/main'
Diffstat (limited to 'backend/internal/ibd/search.go')
-rw-r--r--backend/internal/ibd/search.go111
1 files changed, 111 insertions, 0 deletions
diff --git a/backend/internal/ibd/search.go b/backend/internal/ibd/search.go
new file mode 100644
index 0000000..341b14b
--- /dev/null
+++ b/backend/internal/ibd/search.go
@@ -0,0 +1,111 @@
+package ibd
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "time"
+
+ "github.com/ansg191/ibd-trader-backend/internal/database"
+)
+
+const (
+ searchUrl = "https://ibdservices.investors.com/im/api/search"
+)
+
+var ErrSymbolNotFound = fmt.Errorf("symbol not found")
+
+func (c *Client) Search(ctx context.Context, symbol string) (database.Stock, error) {
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchUrl, nil)
+ if err != nil {
+ return database.Stock{}, err
+ }
+
+ _, cookie, err := c.getCookie(ctx, nil)
+ if err != nil {
+ return database.Stock{}, err
+ }
+ req.AddCookie(cookie)
+
+ params := url.Values{}
+ params.Set("key", symbol)
+ req.URL.RawQuery = params.Encode()
+
+ resp, err := c.Do(req)
+ if err != nil {
+ return database.Stock{}, err
+ }
+ defer func(Body io.ReadCloser) {
+ _ = Body.Close()
+ }(resp.Body)
+
+ if resp.StatusCode != http.StatusOK {
+ content, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return database.Stock{}, fmt.Errorf("failed to read response body: %w", err)
+ }
+ return database.Stock{}, fmt.Errorf(
+ "unexpected status code %d: %s",
+ resp.StatusCode,
+ string(content),
+ )
+ }
+
+ var sr searchResponse
+ if err = json.NewDecoder(resp.Body).Decode(&sr); err != nil {
+ return database.Stock{}, err
+ }
+
+ for _, stock := range sr.StockData {
+ if stock.Symbol == symbol {
+ return database.Stock{
+ Symbol: stock.Symbol,
+ Name: stock.Company,
+ IBDUrl: stock.QuoteUrl,
+ }, nil
+ }
+ }
+
+ return database.Stock{}, ErrSymbolNotFound
+}
+
+type searchResponse struct {
+ Status int `json:"_status"`
+ Timestamp string `json:"_timestamp"`
+ StockData []struct {
+ Id int `json:"id"`
+ Symbol string `json:"symbol"`
+ Company string `json:"company"`
+ PriceDate string `json:"priceDate"`
+ Price float64 `json:"price"`
+ PreviousPrice float64 `json:"previousPrice"`
+ PriceChange float64 `json:"priceChange"`
+ PricePctChange float64 `json:"pricePctChange"`
+ Volume int `json:"volume"`
+ VolumeChange int `json:"volumeChange"`
+ VolumePctChange int `json:"volumePctChange"`
+ QuoteUrl string `json:"quoteUrl"`
+ } `json:"stockData"`
+ News []struct {
+ Title string `json:"title"`
+ Category string `json:"category"`
+ Body string `json:"body"`
+ ImageAlt string `json:"imageAlt"`
+ ImageUrl string `json:"imageUrl"`
+ NewsUrl string `json:"newsUrl"`
+ CategoryUrl string `json:"categoryUrl"`
+ PublishDate time.Time `json:"publishDate"`
+ PublishDateUnixts int `json:"publishDateUnixts"`
+ Stocks []struct {
+ Id int `json:"id"`
+ Index int `json:"index"`
+ Symbol string `json:"symbol"`
+ PricePctChange string `json:"pricePctChange"`
+ } `json:"stocks"`
+ VideoFormat bool `json:"videoFormat"`
+ } `json:"news"`
+ FullUrl string `json:"fullUrl"`
+}