plugins/stocks.go (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
package plugins
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"time"
"git.icyphox.sh/paprika/config"
"github.com/dustin/go-humanize"
"gopkg.in/irc.v3"
)
func init() {
Register(Stocks{})
}
type Stocks struct{}
var (
stockClient = &http.Client{
Timeout: 10 * time.Second,
}
api_endpoint = "https://cloud.iexapis.com/v1"
NoIEXApi = errors.New("No IEX API key")
)
func (Stocks) Triggers() []string {
return []string{".stock", ".stonk"}
}
type tickerData struct {
Quote struct {
Symbol string `json:"symbol"`
Current float64 `json:"latestPrice"`
High float64 `json:"high,omitempty"`
Low float64 `json:"low,omitempty"`
ChangePercent float64 `json:"changePercent"`
} `json:"quote"`
Stats struct {
Company string `json:"companyName"`
Change1y float64 `json:"year1ChangePercent"`
Change6M float64 `json:"month6ChangePercent"`
Change30d float64 `json:"day30ChangePercent"`
Change5d float64 `json:"day5ChangePercent"`
} `json:"stats"`
}
func formatMoneyNum(field string, value float64, percent bool) string {
if percent {
v := humanize.CommafWithDigits(value*100+0.00000000001, 2)
if value < 0 {
return fmt.Sprintf("%s: \x0304%s%%\x03 ", field, v)
} else {
return fmt.Sprintf("%s: \x0303%s%%\x03 ", field, v)
}
} else {
v := humanize.CommafWithDigits(value+0.00000000001, 2)
return fmt.Sprintf("%s: $%s ", field, v)
}
}
func getStock(symbol, apiKey string) (string, error) {
req, err := http.NewRequest("GET", api_endpoint+"/stock/market/batch", nil)
if err != nil {
return "[Stocks] Request construction error.", err
}
req.Header.Add("User-Agent", "github.com/icyphox/paprika")
q := req.URL.Query()
q.Add("token", apiKey)
q.Add("symbols", symbol)
q.Add("types", "quote,stats")
req.URL.RawQuery = q.Encode()
res, err := stockClient.Do(req)
if err != nil {
return "[Stocks] API Client Error", err
}
defer res.Body.Close()
if res.StatusCode == 404 {
return fmt.Sprintf("[Stocks] Could not get quote for \x02%s\x02", symbol), nil
}
var resData map[string]tickerData
err = json.NewDecoder(res.Body).Decode(&resData)
if err != nil {
return "[Stock] API response malformed", err
}
quote := resData[symbol].Quote
stats := resData[symbol].Stats
var outRes strings.Builder
outRes.WriteString(fmt.Sprintf("\x02%s (%s)\x02 - ", stats.Company, quote.Symbol))
outRes.WriteString(formatMoneyNum("Current", quote.Current, false))
if quote.High != 0.0 {
outRes.WriteString(formatMoneyNum("High", quote.High, false))
outRes.WriteString(formatMoneyNum("Low", quote.Low, false))
}
outRes.WriteString(formatMoneyNum("24h", quote.ChangePercent, true))
outRes.WriteString(formatMoneyNum("5d", stats.Change5d, true))
outRes.WriteString(formatMoneyNum("6M", stats.Change6M, true))
outRes.WriteString(formatMoneyNum("1y", stats.Change1y, true))
return outRes.String(), nil
}
func (Stocks) Execute(m *irc.Message) (string, error) {
parsed := strings.SplitN(m.Trailing(), " ", 3)
if len(parsed) != 2 {
return fmt.Sprintf("Usage: %s <Ticker>", parsed[0]), nil
}
sym := strings.ToUpper(parsed[1])
if apiKey, ok := config.C.ApiKeys["iex"]; ok {
return getStock(sym, apiKey)
}
return "", NoIEXApi
}
|