Created
April 15, 2023 16:29
-
-
Save dim0xff/7798ffa5d362215ab361bdd47f9f7391 to your computer and use it in GitHub Desktop.
yahoo-finance-proxy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
yahoo-finance-proxy - прокси получения котировок из Yahoo Finance для https://github.com/KonishchevDmitry/investments | |
Работает на 15 апр 2023 | |
В config.yaml добавить | |
quotes: | |
custom_provider: | |
url: http://127.0.0.1:12345 | |
Собрать и запустить | |
$ go mod init yahoo-finance-proxy | |
$ go build | |
$ ./yahoo-finance-proxy | |
*/ | |
package main | |
import ( | |
"encoding/json" | |
"flag" | |
"io" | |
"log" | |
"net/http" | |
"net/url" | |
) | |
const yahooUrl = "https://query1.finance.yahoo.com/v7/finance/quote" | |
func main() { | |
var l string | |
flag.StringVar(&l, "l", ":12345", "listen on (:12345)") | |
flag.Parse() | |
log.Printf("start quotes proxy on %s", l) | |
http.HandleFunc("/v1/quotes", QuotesHandler) | |
log.Fatal(http.ListenAndServe(l, nil)) | |
} | |
type QuoteResult struct { | |
Symbol string `json:"symbol"` | |
Price string `json:"price"` | |
Currency string `json:"currency,omitempty"` | |
} | |
type QuoteResponse struct { | |
Quotes []*QuoteResult `json:"quotes"` | |
} | |
type YQuoteResponse struct { | |
QuoteResponse struct { | |
Error interface{} `json:"error"` | |
Result []struct { | |
Currency string `json:"currency"` | |
RegularMarketPrice struct { | |
Fmt string `json:"fmt"` | |
Raw float64 `json:"raw"` | |
} `json:"regularMarketPrice"` | |
Symbol string `json:"symbol"` | |
} `json:"result"` | |
} `json:"quoteResponse"` | |
} | |
func QuotesHandler(w http.ResponseWriter, req *http.Request) { | |
req.Body.Close() | |
s := req.URL.Query().Get("symbols") | |
if s == "" { | |
log.Printf("empty symbols: %s", req.URL.String()) | |
w.WriteHeader(http.StatusBadRequest) | |
w.Write([]byte("empty symbols")) | |
return | |
} | |
u, err := url.Parse(yahooUrl) | |
if err != nil { | |
log.Printf("can't parse url '%s': %v", yahooUrl, err) | |
w.WriteHeader(http.StatusInternalServerError) | |
w.Write([]byte(err.Error())) | |
return | |
} | |
q := make(url.Values) | |
q.Set("symbols", s) | |
q.Set("formatted", "true") | |
q.Set("fields", "regularMarketPrice,marketCap") | |
u.RawQuery = q.Encode() | |
yReq, err := http.NewRequest("GET", u.String(), nil) | |
if err != nil { | |
log.Printf("can't create request: %v", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
w.Write([]byte(err.Error())) | |
return | |
} | |
yReq.Header.Set("Referer", "https://finance.yahoo.com/") | |
yReq.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.61 Safari/537.36") | |
client := http.Client{} | |
yRes, err := client.Do(yReq) | |
if err != nil { | |
log.Printf("can't do request: %v", err) | |
w.WriteHeader(http.StatusBadGateway) | |
w.Write([]byte(err.Error())) | |
return | |
} | |
yBody, err := io.ReadAll(yRes.Body) | |
if err != nil { | |
log.Printf("can't read response: %v", err) | |
w.WriteHeader(http.StatusBadGateway) | |
w.Write([]byte(err.Error())) | |
return | |
} | |
yRes.Body.Close() | |
var yQuotes YQuoteResponse | |
err = json.Unmarshal(yBody, &yQuotes) | |
if err != nil { | |
log.Printf("can't unmarshal response '%s': %v", string(yBody), err) | |
w.WriteHeader(http.StatusBadGateway) | |
w.Write([]byte(err.Error())) | |
return | |
} | |
if yQuotes.QuoteResponse.Error != nil { | |
log.Printf("can't yQuotes error: %v", yQuotes.QuoteResponse.Error) | |
w.WriteHeader(http.StatusBadGateway) | |
if e, ok := yQuotes.QuoteResponse.Error.(string); ok { | |
w.Write([]byte(e)) | |
} else { | |
w.Write(yBody) | |
} | |
return | |
} | |
qRes := QuoteResponse{Quotes: []*QuoteResult{}} | |
for _, yq := range yQuotes.QuoteResponse.Result { | |
qRes.Quotes = append(qRes.Quotes, &QuoteResult{ | |
Symbol: yq.Symbol, | |
Price: yq.RegularMarketPrice.Fmt, | |
Currency: yq.Currency, | |
}) | |
} | |
rBody, err := json.Marshal(qRes) | |
if err != nil { | |
log.Printf("can't marshal qRes: %v", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
w.Write([]byte(err.Error())) | |
return | |
} | |
w.WriteHeader(http.StatusOK) | |
w.Write(rBody) | |
log.Printf("OK, %d", len(yQuotes.QuoteResponse.Result)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment