Skip to content

Commit

Permalink
Init project
Browse files Browse the repository at this point in the history
  • Loading branch information
ledongthuc committed May 21, 2021
0 parents commit 92343c7
Show file tree
Hide file tree
Showing 6 changed files with 288 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
gohowmuch
/build
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
build: clean
gox -output="./build/gohowmuch_{{.OS}}_{{.Arch}}"
echo "Build sucessfully"
clean:
rm build/*
echo "Clean"
traderview:
tmux
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<h1 align="center">Go How Much? 🪙</h1>

Inspired by https://github.com/monodyle/howmuch

<div align="center">
<p>Crypto coin price tracking on terminal.</p>
</div>

# Install


# Usage

Type from commandline

```
gohowmuch --symbol=doge
```

Change the symbol that avaiable on [https://www.binance.com/en/markets](binance)

Example:

```
gohowmuch --symbol=btc
gohowmuch --symbol=doge
gohowmuch --symbol=shib
```

# Open multiple

Suggest to use https://github.com/tmux/tmux with following command

```
tmux select-layout even-vertical;
```

# Build from source

1. Requirement

- Go 1.16

2. Build binary

```
go get;
go build -o gohowmuch;
```

3. Run gohowmuch

```
./gohowmuch
```

# License

MIT
12 changes: 12 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module github.com/ledongthuc/gohowmuch

go 1.16

require (
github.com/gorilla/websocket v1.4.2
github.com/guptarohit/asciigraph v0.5.2
github.com/mattn/go-runewidth v0.0.12 // indirect
github.com/rivo/tview v0.0.0-20210514202809-22dbf8415b04
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d
golang.org/x/text v0.3.5
)
29 changes: 29 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.2.1 h1:Gt8wk0jd5pIK2CyXNo/fqwxNWf726j1lQjEDdfbnqTc=
github.com/gdamore/tcell/v2 v2.2.1/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/guptarohit/asciigraph v0.5.2 h1:aG4kATuuyHQMdTi89KKVIRIcDSIHrsKIozo/UsUE5AM=
github.com/guptarohit/asciigraph v0.5.2/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/rivo/tview v0.0.0-20210514202809-22dbf8415b04 h1:9e47a4RJ9rCkPn6D2eb5OP3M2nMqcoRjL5JFTeKUVYc=
github.com/rivo/tview v0.0.0-20210514202809-22dbf8415b04/go.mod h1:Uajo+DndkMDGPzEw/Z92AgJrpx6Rvy2HRo/xP1YbXAI=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
178 changes: 178 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package main

import (
"encoding/json"
"flag"
"fmt"
"log"
"net/url"
"strconv"
"time"

"github.com/gorilla/websocket"
"github.com/guptarohit/asciigraph"
"github.com/rivo/tview"
"golang.org/x/term"
"golang.org/x/text/language"
"golang.org/x/text/message"
)

const (
// https://binance-docs.github.io/apidocs/spot/en/#aggregate-trade-streams
streamURL = "wss://stream.binance.com/stream"
graphCutSize = 10
)

func main() {
// variables
width, _, err := term.GetSize(0)
if err != nil {
panic("Can't get terminal size")
}
graphSize := width - graphCutSize
dataGraph := make([]float64, 0, graphSize)
price := float64(0)
priceUp := true
graph := ""
var symbol, symbolBase string
p := message.NewPrinter(language.Swedish)

// flags
flag.StringVar(&symbol, "symbol", "btc", "symbol")
flag.StringVar(&symbolBase, "symbolbase", "usdt", "symbol")
flag.Parse()
symbolText := fmt.Sprintf("%s / %s", symbol, symbolBase)

// UI building
app := tview.NewApplication()
textView := tview.NewTextView().
SetDynamicColors(true).
SetText(graph).
SetWrap(false).
SetChangedFunc(func() {
app.Draw()
})

// Listen changes from data, build graph
done := make(chan struct{}, 1)
data := make(chan float64, graphSize)
go listen(symbol, symbolBase, done, data)
go func() {
for {
select {
case <-done:
break
case datum := <-data:
if len(dataGraph) > 0 {
price = datum
priceUp = dataGraph[len(dataGraph)-1] < price
}

dataGraph = appendGraph(graphSize, dataGraph, datum)
graph = asciigraph.Plot(dataGraph, asciigraph.Precision(5), asciigraph.Height(5))
}
}
}()

// Periodly, update UI
go func() {
for {
select {
case <-done:
break
case <-time.After(300 * time.Millisecond):
width, _, _ = term.GetSize(0)
graphSize = width - graphCutSize
app.QueueUpdateDraw(func() {
colorText := "red"
if priceUp {
colorText = "green"
}
textView.SetText(p.Sprintf(" %s: [%s]%f[default]\n\n%v", symbolText, colorText, price, graph))
})
}
}
}()

if err := app.SetRoot(textView, true).EnableMouse(true).Run(); err != nil {
done <- struct{}{}
panic(err)
}

}

func appendGraph(size int, data []float64, newItem float64) []float64 {
if len(data) < size {
return append(data, newItem)
}

copy(data[0:], data[len(data)-size+1:])
data[size-1] = newItem
return data[:size-1]
}

type ReceiveMsg struct {
Stream string `json:"stream"`
Data struct {
P string `json:"p"`
} `json:"data"`
}

func listen(symbol, symbolBase string, done chan struct{}, data chan float64) {
u, err := url.Parse(streamURL)
if err != nil {
log.Fatal("Can't parse ", u)
}
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()

go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
panic(err)
}
var msg ReceiveMsg
if err = json.Unmarshal(message, &msg); err != nil {
panic(err)
}

p, err := strconv.ParseFloat(msg.Data.P, 64)
if err != nil {
continue
}
data <- p
}
}()

err = c.WriteMessage(websocket.TextMessage, []byte(`{"method": "SUBSCRIBE","params": ["`+symbol+symbolBase+`@aggTrade"],"id": 1}`))
if err != nil {
log.Println("write:", err)
return
}

for {
select {
case <-done:
log.Println("interrupt")

// Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection.
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-time.After(time.Second):
}
fmt.Print("Stop done")
return
}
}

}

0 comments on commit 92343c7

Please sign in to comment.