Skip to content

Commit

Permalink
first
Browse files Browse the repository at this point in the history
  • Loading branch information
t0mk committed Jan 6, 2024
0 parents commit 6215b3c
Show file tree
Hide file tree
Showing 18 changed files with 10,338 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
on:
release:
types: [created]

permissions:
contents: write
packages: write

jobs:
release-linux-amd64:
name: release linux/amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: wangyoucao577/go-release-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: linux
goarch: amd64
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pri
vendor
*.swp
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# pri

CLI tool for getting cryptocurrency prices from 8 biggest exchanges. No API key needed


## TODO
- filter out delisted asset pairs, it's sometimes indicated in the api asset listsing
- make arbitrage groups, like
```golang
var btcUsdtTickers = []ExTick{
{"coinbase", "BTC-USD"},
{"binance", "BTCUSDT"},
{"kraken", "XBTUSDT"},
{"bitstamp", "btcusdt"},
{"huobi", "btcusdt"},
{"kucoin", "BTC-USDT"},
{"gateio", "BTC_USDT"},
{"bitfinex", "btcust"},
}
```
5 changes: 5 additions & 0 deletions consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package main

var findCommands = []string{
"f", "fi", "fin", "find", "f!", "fi!", "fin!", "find!",
}
49 changes: 49 additions & 0 deletions demo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package main

var btcUsdtTickers = []ExTick{
{"coinbase", "BTC-USD"},
{"binance", "BTCUSDT"},
{"kraken", "XBTUSDT"},
{"bitstamp", "btcusdt"},
{"huobi", "btcusdt"},
{"kucoin", "BTC-USDT"},
{"gateio", "BTC_USDT"},
{"bitfinex", "btcust"},
}

func floatSliceMean(slice []float64) float64 {
sum := 0.0
i := 0
for _, v := range slice {
if v == 0 {
continue
}
sum += v
i++
}
return sum / float64(i)
}

/*
func getBtcUsdt() float64 {
prices := []float64{}
for _, et := range btcUsdtTickers {
price := getExchangeTickerPrice(et)
prices = append(prices, price)
}
return floatSliceMean(prices)
}
func getBtcUsdtAsync() float64 {
prices := []float64{}
resultChan := make(chan float64)
for _, et := range btcUsdtTickers {
go getExchangeTickerPriceAsync(et, resultChan)
}
for i := 0; i < len(btcUsdtTickers); i++ {
price := <-resultChan
prices = append(prices, price)
}
return floatSliceMean(prices)
}
*/
292 changes: 292 additions & 0 deletions getters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
)

type TickerGetter func(string) (float64, error)

func getHTTPResponseBodyFromUrl(url string) ([]byte, error) {
if debug {
log.Println("getHTTPResponseBodyFromUrl", url)
}
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("http.Get: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("ioutil.ReadAll: %v", err)
}
if debug {
log.Println("BODY:", string(body))
}
return body, nil
}

type CoinbaseTicker struct {
Price string `json:"price"`
Ask string `json:"ask"`
Bid string `json:"bid"`
Volume string `json:"volume"`
Size string `json:"size"`
}

// ticker might be BTC-USD{T}
func CoinbaseGetter(ticker string) (float64, error) {
url := "https://api.pro.coinbase.com/products/" + ticker + "/ticker"
body, err := getHTTPResponseBodyFromUrl(url)
if err != nil {
return 0, err
}
var tickerData CoinbaseTicker
err = json.Unmarshal(body, &tickerData)
//fmt.Printf("Coinbase %s %#v\n", ticker, tickerData)
if err != nil {
return 0, err
}
a := tickerData.Ask
b := tickerData.Bid
af, err := strconv.ParseFloat(a, 64)
if err != nil {
return 0, err
}
bf, err := strconv.ParseFloat(b, 64)
if err != nil {
return 0, err
}
return (af + bf) / 2, nil
}

func GeminiGetter(ticker string) (float64, error) {
url := "https://api.gemini.com/v1/pubticker/" + ticker
body, err := getHTTPResponseBodyFromUrl(url)
if err != nil {
return 0, err
}
var tickerData CoinbaseTicker
err = json.Unmarshal(body, &tickerData)
if err != nil {
return 0, err
}
a := tickerData.Ask
b := tickerData.Bid
af, err := strconv.ParseFloat(a, 64)
if err != nil {
return 0, err
}
bf, err := strconv.ParseFloat(b, 64)
if err != nil {
return 0, err
}
return (af + bf) / 2, nil
}

type BitstampTicker struct {
Ask string `json:"ask"`
Bid string `json:"bid"`
}

func BitstampGetter(ticker string) (float64, error) {
url := "https://www.bitstamp.net/api/v2/ticker/" + ticker
body, err := getHTTPResponseBodyFromUrl(url)
if err != nil {
return 0, err
}
var tickerData BitstampTicker
err = json.Unmarshal(body, &tickerData)
if err != nil {
return 0, err
}
a := tickerData.Ask
b := tickerData.Bid
af, err := strconv.ParseFloat(a, 64)
if err != nil {
return 0, err
}
bf, err := strconv.ParseFloat(b, 64)
if err != nil {
return 0, err
}
return (af + bf) / 2, nil
}

type KrakenTicker struct {
Result map[string]struct {
A []string `json:"a"`
B []string `json:"b"`
} `json:"result"`
}

func KrakenGetter(ticker string) (float64, error) {
url := "https://api.kraken.com/0/public/Ticker?pair=" + ticker
body, err := getHTTPResponseBodyFromUrl(url)
if err != nil {
return 0, err
}
var tickerData KrakenTicker
err = json.Unmarshal(body, &tickerData)
if err != nil {
return 0, err
}
a := tickerData.Result[ticker].A[0]
b := tickerData.Result[ticker].B[0]
af, err := strconv.ParseFloat(a, 64)
if err != nil {
return 0, err
}
bf, err := strconv.ParseFloat(b, 64)
if err != nil {
return 0, err
}
return (af + bf) / 2, nil
}

type HuobiTicker struct {
Tick struct {
Bid []float64 `json:"bid"`
Ask []float64 `json:"ask"`
} `json:"tick"`
}

func HuobiGetter(ticker string) (float64, error) {
url := "https://api.huobi.pro/market/detail/merged?symbol=" + ticker
body, err := getHTTPResponseBodyFromUrl(url)
if err != nil {
return 0, err
}
var tickerData HuobiTicker
err = json.Unmarshal(body, &tickerData)
if err != nil {
return 0, err
}
a := tickerData.Tick.Ask[0]
b := tickerData.Tick.Bid[0]
return (a + b) / 2, nil
}

func BinanceGetter(ticker string) (float64, error) {
url := "https://api1.binance.com/api/v3/ticker/price?symbol=" + ticker
body, err := getHTTPResponseBodyFromUrl(url)
if err != nil {
return 0, err
}
var tickerData CoinbaseTicker
err = json.Unmarshal(body, &tickerData)
if err != nil {
return 0, err
}
price, err := strconv.ParseFloat(tickerData.Price, 64)
if err != nil {
return 0, err
}
return price, nil
}

type GateIOTicker struct {
Bid string `json:"highest_bid"`
Ask string `json:"lowest_ask"`
}

func GateIOGetter(ticker string) (float64, error) {
url := "https://api.gateio.ws/api/v4/spot/tickers?currency_pair=" + ticker
body, err := getHTTPResponseBodyFromUrl(url)
if err != nil {
return 0, err
}
var tickerData []GateIOTicker
err = json.Unmarshal(body, &tickerData)
if err != nil {
return 0, err
}
a := tickerData[0].Ask
b := tickerData[0].Bid
af, err := strconv.ParseFloat(a, 64)
if err != nil {
return 0, err
}
bf, err := strconv.ParseFloat(b, 64)
if err != nil {
return 0, err
}
return (af + bf) / 2, nil
}

type BitfinexTicker struct {
Mid string `json:"mid"`
}

func BitfinexGetter(ticker string) (float64, error) {
url := "https://api.bitfinex.com/v1/pubticker/" + ticker
body, err := getHTTPResponseBodyFromUrl(url)
if err != nil {
return 0, err
}
var tickerData BitfinexTicker
err = json.Unmarshal(body, &tickerData)
if err != nil {
return 0, err
}
price, err := strconv.ParseFloat(tickerData.Mid, 64)
if err != nil {
return 0, err
}
return price, nil
}

type KUCoinTicker struct {
Data struct {
Price string `json:"price"`
Bid string `json:"bestBid"`
Ask string `json:"bestAsk"`
} `json:"data"`
}

func KUCoinGetter(ticker string) (float64, error) {
url := "https://api.kucoin.com/api/v1/market/orderbook/level1?symbol=" + ticker
body, err := getHTTPResponseBodyFromUrl(url)
if err != nil {
return 0, err
}
var tickerData KUCoinTicker
err = json.Unmarshal(body, &tickerData)
if err != nil {
return 0, err
}
a := tickerData.Data.Ask
b := tickerData.Data.Bid
af, err := strconv.ParseFloat(a, 64)
if err != nil {
return 0, err
}
bf, err := strconv.ParseFloat(b, 64)
if err != nil {
return 0, err
}
return (af + bf) / 2, nil
}

type BitflyerTicker struct {
Ask float64 `json:"best_ask"`
Bid float64 `json:"best_bid"`
}

func BitflyerGetter(ticker string) (float64, error) {
url := "https://api.bitflyer.com/v1/ticker?product_code=" + ticker
body, err := getHTTPResponseBodyFromUrl(url)
if err != nil {
return 0, err
}
var tickerData BitflyerTicker
err = json.Unmarshal(body, &tickerData)
if err != nil {
return 0, err
}
return (tickerData.Ask + tickerData.Bid) / 2, nil
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/t0mk/pri

go 1.21.5
Loading

0 comments on commit 6215b3c

Please sign in to comment.