diff --git a/_site/content/posts/modules/cryptocurrencies/bittrex.md b/_site/content/posts/modules/cryptocurrencies/bittrex.md new file mode 100644 index 00000000..99fc7272 --- /dev/null +++ b/_site/content/posts/modules/cryptocurrencies/bittrex.md @@ -0,0 +1,85 @@ +--- +title: "Bittrex" +date: 2018-06-04T20:06:40-07:00 +draft: false +--- + +Added in `v0.0.5`. + +Get the last 24 hour summary of cryptocurrencies market using [Bittrex](https://bittrex.com). + +## Source Code + +```bash +wtf/cryptoexchanges/bittrex/ +``` + +## Required ENV Vars + +None. + +## Keyboard Commands + +None. + +## Configuration + +```yaml +bittrex: + enabled: true + position: + top: 1 + left: 2 + height: 3 + width: 1 + refreshInterval: 5 + summary: + BTC: + displayName: Bitcoin + market: + - LTC + - ETH + colors: + base: + name: orange + displayName: red + market: + name: red + field: white + value: green +``` + +### Attributes + +`colors.base.name`
+Values: Any X11 +color name. + +`colors.base.dispayName`
+Values: Any X11 +color name. + +`colors.market.name`
+Values: Any X11 +color name. + +`colors.market.field`
+Values: Any X11 +color name. + +`colors.market.value`
+Values: Any X11 +color name. + +`summary`
+ +`enabled`
+Determines whether or not this module is executed and if its data displayed onscreen.
+Values: `true`, `false`. + +`position`
+Defines where in the grid this module's widget will be displayed.
+ +`refreshInterval`
+How often, in seconds, this module will update its data.
+Values: A positive integer, `0..n`. diff --git a/cryptoexchanges/bittrex/bittrex.go b/cryptoexchanges/bittrex/bittrex.go new file mode 100644 index 00000000..c06f65cb --- /dev/null +++ b/cryptoexchanges/bittrex/bittrex.go @@ -0,0 +1,49 @@ +package bittrex + +type summaryList struct { + items []*bCurrency +} + +// Base Currency +type bCurrency struct { + name string + displayName string + markets []*mCurrency +} + +// Market Currency +type mCurrency struct { + name string + summaryInfo +} + +type summaryInfo struct { + Low string + High string + Volume string + Last string + OpenSellOrders string + OpenBuyOrders string +} + +type summaryResponse struct { + Success bool `json:"success"` + Message string `json:"message"` + Result []struct { + MarketName string `json:"MarketName"` + High float64 `json:"High"` + Low float64 `json:"Low"` + Last float64 `json:"Last"` + Volume float64 `json:"Volume"` + OpenSellOrders int `json:"OpenSellOrders"` + OpenBuyOrders int `json:"OpenBuyOrders"` + } `json:"result"` +} + +func (list *summaryList) addSummaryItem(name, displayName string, marketList []*mCurrency) { + list.items = append(list.items, &bCurrency{ + name: name, + displayName: displayName, + markets: marketList, + }) +} diff --git a/cryptoexchanges/bittrex/display.go b/cryptoexchanges/bittrex/display.go new file mode 100644 index 00000000..2718e0f7 --- /dev/null +++ b/cryptoexchanges/bittrex/display.go @@ -0,0 +1,67 @@ +package bittrex + +import ( + "bytes" + "fmt" + "text/template" +) + +func (widget *Widget) display() { + if ok == false { + widget.View.SetText(fmt.Sprintf("%s", errorText)) + return + } + + str := "" + str += summaryText(&widget.summaryList, &widget.TextColors) + + widget.View.SetText(fmt.Sprintf("%s", str)) +} + +func summaryText(list *summaryList, colors *TextColors) string { + str := "" + + for _, baseCurrency := range list.items { + str += fmt.Sprintf(" [%s]%s[%s] (%s)\n\n", colors.base.displayName, baseCurrency.displayName, colors.base.name, baseCurrency.name) + + resultTemplate := template.New("bittrex") + + for _, marketCurrency := range baseCurrency.markets { + writer := new(bytes.Buffer) + + strTemplate, _ := resultTemplate.Parse( + " [{{.nameColor}}]{{.mName}}\n" + + formatableText("High", "High") + + formatableText("Low", "Low") + + formatableText("Last", "Last") + + formatableText("Volume", "Volume") + + "\n" + + formatableText("Open Buy", "OpenBuyOrders") + + formatableText("Open Sell", "OpenSellOrders"), + ) + + strTemplate.Execute(writer, map[string]string{ + "nameColor": colors.market.name, + "fieldColor": colors.market.field, + "valueColor": colors.market.value, + "mName": marketCurrency.name, + "High": marketCurrency.High, + "Low": marketCurrency.Low, + "Last": marketCurrency.Last, + "Volume": marketCurrency.Volume, + "OpenBuyOrders": marketCurrency.OpenBuyOrders, + "OpenSellOrders": marketCurrency.OpenSellOrders, + }) + + str += writer.String() + "\n" + } + + } + + return str + +} + +func formatableText(key, value string) string { + return fmt.Sprintf("[{{.fieldColor}}]%12s: [{{.valueColor}}]{{.%s}}\n", key, value) +} diff --git a/cryptoexchanges/bittrex/widget.go b/cryptoexchanges/bittrex/widget.go new file mode 100644 index 00000000..3f6f4d92 --- /dev/null +++ b/cryptoexchanges/bittrex/widget.go @@ -0,0 +1,190 @@ +package bittrex + +import ( + "encoding/json" + "fmt" + "time" + + "net/http" + + "github.com/olebedev/config" + "github.com/senorprogrammer/wtf/wtf" +) + +// Config is a pointer to the global config object +var Config *config.Config + +type TextColors struct { + base struct { + name string + displayName string + } + market struct { + name string + field string + value string + } +} + +var ok = true +var errorText = "" +var started = false +var baseURL = "https://bittrex.com/api/v1.1/public/getmarketsummary" + +// Widget define wtf widget to register widget later +type Widget struct { + wtf.TextWidget + summaryList + TextColors +} + +// NewWidget Make new instance of widget +func NewWidget() *Widget { + + widget := Widget{ + TextWidget: wtf.NewTextWidget(" Bittrex ", "bittrex", false), + summaryList: summaryList{}, + } + + started = false + ok = true + errorText = "" + + widget.config() + widget.setSummaryList() + + return &widget +} + +func (widget *Widget) config() { + widget.TextColors.base.name = Config.UString("wtf.mods.bittrex.colors.base.name", "red") + widget.TextColors.base.displayName = Config.UString("wtf.mods.bittrex.colors.base.displayName", "grey") + widget.TextColors.market.name = Config.UString("wtf.mods.bittrex.colors.market.name", "red") + widget.TextColors.market.field = Config.UString("wtf.mods.bittrex.colors.market.field", "coral") + widget.TextColors.market.value = Config.UString("wtf.mods.bittrex.colors.market.value", "white") +} + +func (widget *Widget) setSummaryList() { + sCurrencies, _ := Config.Map("wtf.mods.bittrex.summary") + for baseCurrencyName := range sCurrencies { + displayName, _ := Config.String("wtf.mods.bittrex.summary." + baseCurrencyName + ".displayName") + mCurrencyList := makeSummaryMarketList(baseCurrencyName) + widget.summaryList.addSummaryItem(baseCurrencyName, displayName, mCurrencyList) + } +} + +func makeSummaryMarketList(currencyName string) []*mCurrency { + mCurrencyList := []*mCurrency{} + + configMarketList, _ := Config.List("wtf.mods.bittrex.summary." + currencyName + ".market") + for _, mCurrencyName := range configMarketList { + mCurrencyList = append(mCurrencyList, makeMarketCurrency(mCurrencyName.(string))) + } + + return mCurrencyList +} + +func makeMarketCurrency(name string) *mCurrency { + return &mCurrency{ + name: name, + summaryInfo: summaryInfo{ + High: "", + Low: "", + Volume: "", + Last: "", + OpenBuyOrders: "", + OpenSellOrders: "", + }, + } +} + +/* -------------------- Exported Functions -------------------- */ + +// Refresh & update after interval time +func (widget *Widget) Refresh() { + if widget.Disabled() { + return + } + + if started == false { + go func() { + for { + widget.updateSummary() + time.Sleep(time.Second * time.Duration(widget.RefreshInterval())) + } + }() + started = true + } + + widget.UpdateRefreshedAt() + + widget.display() + +} + +/* -------------------- Unexported Functions -------------------- */ + +func (widget *Widget) updateSummary() { + // In case if anything bad happened! + defer func() { + recover() + }() + + client := &http.Client{ + Timeout: time.Duration(5 * time.Second), + } + + for _, baseCurrency := range widget.summaryList.items { + for _, mCurrency := range baseCurrency.markets { + request := makeRequest(baseCurrency.name, mCurrency.name) + response, err := client.Do(request) + + if err != nil { + ok = false + errorText = "Please Check Your Internet Connection!" + break + } else { + ok = true + errorText = "" + } + + if response.StatusCode != http.StatusOK { + errorText = response.Status + ok = false + break + } else { + ok = true + errorText = "" + } + + defer response.Body.Close() + jsonResponse := summaryResponse{} + decoder := json.NewDecoder(response.Body) + decoder.Decode(&jsonResponse) + + if !jsonResponse.Success { + ok = false + errorText = fmt.Sprintf("%s-%s: %s", baseCurrency.name, mCurrency.name, jsonResponse.Message) + break + } + ok = true + errorText = "" + + mCurrency.Last = fmt.Sprintf("%f", jsonResponse.Result[0].Last) + mCurrency.High = fmt.Sprintf("%f", jsonResponse.Result[0].High) + mCurrency.Low = fmt.Sprintf("%f", jsonResponse.Result[0].Low) + mCurrency.Volume = fmt.Sprintf("%f", jsonResponse.Result[0].Volume) + mCurrency.OpenBuyOrders = fmt.Sprintf("%d", jsonResponse.Result[0].OpenBuyOrders) + mCurrency.OpenSellOrders = fmt.Sprintf("%d", jsonResponse.Result[0].OpenSellOrders) + } + } + + widget.display() +} + +func makeRequest(baseName, marketName string) *http.Request { + url := fmt.Sprintf("%s?market=%s-%s", baseURL, baseName, marketName) + request, _ := http.NewRequest("GET", url, nil) + + return request +} diff --git a/docs/posts/modules/bittrex/index.html b/docs/posts/modules/bittrex/index.html new file mode 100644 index 00000000..8ab9753c --- /dev/null +++ b/docs/posts/modules/bittrex/index.html @@ -0,0 +1,243 @@ + + + + + + + + + + + + + Module: Bittrex | WTF - A Terminal Dashboard + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

Module: Bittrex

+ +
+ +
+ +

Get the last 24 hour summary of cryptocurrencies market.

+ +

Source Code

+
+
wtf/bittrex/
+
+

Required ENV Variables

+ +

None.

+ +

Keyboard Commands

+ +

None.

+ +

Configuration

+
+
bittrex:
+  enabled: true
+  position:
+    top: 1
+    left: 2
+    height: 1
+    width: 1
+  refreshInterval: 15
+  summary: 
+   BTC:
+     displayName: Bitcoin
+     market: 
+       - ETH
+       - LTC
+   ETH:
+     displayName: Ethereum
+     market: 
+       - LTC
+  colors: 
+   base: 
+     name: red
+     displayName: grey
+   market:
+     name: red
+     field: coral
+     value: white
+
+
+
+

Attributes

+ + + +

+ enabled +
Determines whether or not this module is executed and if its data displayed onscreen. +
Values: + true, + false.

+ +

+ position +
Defines where in the grid this module’s widget will be displayed. +
+

+ +

+ updateInterval +
How often, in seconds, this module will update its data. +
Values: A positive integer +
Default Value: 10

+ +

+ colors +
Sets color of texts. +
Values: A valid color +

+ +
+ + +
+ + + + \ No newline at end of file diff --git a/wtf.go b/wtf.go index 6dd4df87..dc0e0b3e 100644 --- a/wtf.go +++ b/wtf.go @@ -13,6 +13,7 @@ import ( "github.com/senorprogrammer/wtf/bamboohr" "github.com/senorprogrammer/wtf/clocks" "github.com/senorprogrammer/wtf/cmdrunner" + "github.com/senorprogrammer/wtf/cryptoexchanges/bittrex" "github.com/senorprogrammer/wtf/cryptoexchanges/cryptolive" "github.com/senorprogrammer/wtf/gcal" "github.com/senorprogrammer/wtf/git" @@ -177,6 +178,8 @@ func makeWidgets(app *tview.Application, pages *tview.Pages) { todo.Config = Config weather.Config = Config wtf.Config = Config + cryptolive.Config = Config + bittrex.Config = Config // Always in alphabetical order Widgets = []wtf.Wtfable{ @@ -199,6 +202,9 @@ func makeWidgets(app *tview.Application, pages *tview.Pages) { textfile.NewWidget(app, pages), todo.NewWidget(app, pages), weather.NewWidget(app, pages), + cryptolive.NewWidget(), + prettyweather.NewWidget(), + bittrex.NewWidget(), } FocusTracker = wtf.FocusTracker{