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
+
+
+
+
+ Jun 04, 2018
+
+
+
+
+
+
+
Get the last 24 hour summary of cryptocurrencies market.
+
+
Source Code
+
+
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{