mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
New endpoint to retrieve values for all enabled currency data for all enabled exchanges and return it as JSON object for front end
535 lines
13 KiB
Go
535 lines
13 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"log"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
BITSTAMP_API_URL = "https://www.bitstamp.net/api/"
|
|
BITSTAMP_API_VERSION = "0"
|
|
BITSTAMP_API_TICKER = "ticker/"
|
|
BITSTAMP_API_TICKER_HOURLY = "ticker_hour/"
|
|
BITSTAMP_API_ORDERBOOK = "order_book/"
|
|
BITSTAMP_API_TRANSACTIONS = "transactions/"
|
|
BITSTAMP_API_EURUSD = "eur_usd/"
|
|
BITSTAMP_API_BALANCE = "balance/"
|
|
BITSTAMP_API_USER_TRANSACTIONS = "user_transactions/"
|
|
BITSTAMP_API_OPEN_ORDERS = "open_orders/"
|
|
BITSTAMP_API_ORDER_STATUS = "order_status"
|
|
BITSTAMP_API_CANCEL_ORDER = "cancel_order/"
|
|
BITSTAMP_API_CANCEL_ALL_ORDERS = "cancel_all_orders/"
|
|
BITSTAMP_API_BUY = "buy/"
|
|
BITSTAMP_API_SELL = "sell/"
|
|
BITSTAMP_API_WITHDRAWAL_REQUESTS = "withdrawal_requests/"
|
|
BITSTAMP_API_BITCOIN_WITHDRAWAL = "bitcoin_withdrawal/"
|
|
BITSTAMP_API_BITCOIN_DEPOSIT = "bitcoin_deposit_address/"
|
|
BITSTAMP_API_UNCONFIRMED_BITCOIN = "unconfirmed_btc/"
|
|
BITSTAMP_API_RIPPLE_WITHDRAWAL = "ripple_withdrawal/"
|
|
BITSTAMP_API_RIPPLE_DESPOIT = "ripple_address/"
|
|
)
|
|
|
|
type Bitstamp struct {
|
|
Name string
|
|
Enabled bool
|
|
Verbose bool
|
|
Websocket bool
|
|
RESTPollingDelay time.Duration
|
|
AuthenticatedAPISupport bool
|
|
ClientID, APIKey, APISecret string
|
|
Balance BitstampAccountBalance
|
|
TakerFee, MakerFee float64
|
|
BaseCurrencies []string
|
|
AvailablePairs []string
|
|
EnabledPairs []string
|
|
}
|
|
|
|
type BitstampTicker struct {
|
|
Last float64 `json:",string"`
|
|
High float64 `json:",string"`
|
|
Low float64 `json:",string"`
|
|
Vwap float64 `json:",string"`
|
|
Volume float64 `json:",string"`
|
|
Bid float64 `json:",string"`
|
|
Ask float64 `json:",string"`
|
|
}
|
|
|
|
type BitstampAccountBalance struct {
|
|
BTCReserved float64 `json:"usd_balance,string"`
|
|
Fee float64 `json:",string"`
|
|
BTCAvailable float64 `json:"btc_balance,string"`
|
|
USDReserved float64 `json:"usd_reserved,string"`
|
|
BTCBalance float64 `json:"btc_balance,string"`
|
|
USDBalance float64 `json:"usd_balance,string"`
|
|
USDAvailable float64 `json:"usd_available,string"`
|
|
}
|
|
|
|
type BitstampOrderbookBase struct {
|
|
Price float64
|
|
Amount float64
|
|
}
|
|
|
|
type BitstampOrderbook struct {
|
|
Timestamp int64 `json:"timestamp,string"`
|
|
Bids []BitstampOrderbookBase
|
|
Asks []BitstampOrderbookBase
|
|
}
|
|
|
|
type BitstampTransactions struct {
|
|
Date int64 `json:"date,string"`
|
|
TradeID int64 `json:"tid"`
|
|
Price float64 `json:"price,string"`
|
|
Type int `json:"type"`
|
|
Amount float64 `json:"amount,string"`
|
|
}
|
|
|
|
type BitstampEURUSDConversionRate struct {
|
|
Buy float64 `json:"buy,string"`
|
|
Sell float64 `json:"sell,string"`
|
|
}
|
|
|
|
type BitstampUserTransactions struct {
|
|
Date string `json:"datetime"`
|
|
TransID int64 `json:"id"`
|
|
Type int `json:"type"`
|
|
USD float64 `json:"usd,string"`
|
|
BTC float64 `json:"btc,string"`
|
|
BTCUSD float64 `json:"btc_usd,string"`
|
|
Fee float64 `json:"fee,string"`
|
|
OrderID interface{} `json:"order_id"`
|
|
}
|
|
|
|
type BitstampOrder struct {
|
|
ID int64 `json:"id"`
|
|
Date string `json:"date"`
|
|
Type int `json:"type"`
|
|
Price float64 `json:"price"`
|
|
Amount float64 `json:"amount"`
|
|
}
|
|
|
|
type BitstampOrderStatus struct {
|
|
Status string
|
|
Transactions []struct {
|
|
TradeID int64 `json:"tid"`
|
|
USD float64 `json:"usd,string"`
|
|
Price float64 `json:"price,string"`
|
|
Fee float64 `json:"fee,string"`
|
|
BTC float64 `json:"btc,string"`
|
|
}
|
|
}
|
|
|
|
type BitstampWithdrawalRequests struct {
|
|
OrderID int64 `json:"id"`
|
|
Date string `json:"datetime"`
|
|
Type int `json:"type"`
|
|
Amount float64 `json:"amount,string"`
|
|
Status int `json:"status"`
|
|
Data interface{}
|
|
}
|
|
|
|
type BitstampUnconfirmedBTCTransactions struct {
|
|
Amount float64 `json:"amount,string"`
|
|
Address string `json:"address"`
|
|
Confirmations int `json:"confirmations"`
|
|
}
|
|
|
|
func (b *Bitstamp) SetDefaults() {
|
|
b.Name = "Bitstamp"
|
|
b.Enabled = false
|
|
b.Verbose = false
|
|
b.Websocket = false
|
|
b.RESTPollingDelay = 10
|
|
}
|
|
|
|
func (b *Bitstamp) Start() {
|
|
go b.Run()
|
|
}
|
|
|
|
func (b *Bitstamp) GetName() string {
|
|
return b.Name
|
|
}
|
|
|
|
func (b *Bitstamp) Setup(exch Exchanges) {
|
|
if !exch.Enabled {
|
|
b.SetEnabled(false)
|
|
} else {
|
|
b.Enabled = true
|
|
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
|
|
b.SetAPIKeys(exch.ClientID, exch.APIKey, exch.APISecret)
|
|
b.RESTPollingDelay = exch.RESTPollingDelay
|
|
b.Verbose = exch.Verbose
|
|
b.Websocket = exch.Websocket
|
|
b.BaseCurrencies = SplitStrings(exch.BaseCurrencies, ",")
|
|
b.AvailablePairs = SplitStrings(exch.AvailablePairs, ",")
|
|
b.EnabledPairs = SplitStrings(exch.EnabledPairs, ",")
|
|
}
|
|
}
|
|
|
|
func (k *Bitstamp) GetEnabledCurrencies() []string {
|
|
return k.EnabledPairs
|
|
}
|
|
|
|
func (b *Bitstamp) SetEnabled(enabled bool) {
|
|
b.Enabled = enabled
|
|
}
|
|
|
|
func (b *Bitstamp) IsEnabled() bool {
|
|
return b.Enabled
|
|
}
|
|
|
|
func (b *Bitstamp) GetFee() float64 {
|
|
return b.Balance.Fee
|
|
}
|
|
|
|
func (b *Bitstamp) SetAPIKeys(clientID, apiKey, apiSecret string) {
|
|
b.ClientID = clientID
|
|
b.APIKey = apiKey
|
|
b.APISecret = apiSecret
|
|
}
|
|
|
|
func (b *Bitstamp) Run() {
|
|
if b.Verbose {
|
|
log.Printf("%s Websocket: %s.", b.GetName(), IsEnabled(b.Websocket))
|
|
log.Printf("%s polling delay: %ds.\n", b.GetName(), b.RESTPollingDelay)
|
|
log.Printf("%s %d currencies enabled: %s.\n", b.GetName(), len(b.EnabledPairs), b.EnabledPairs)
|
|
}
|
|
|
|
if b.Websocket {
|
|
go b.PusherClient()
|
|
}
|
|
|
|
for b.Enabled {
|
|
for _, x := range b.EnabledPairs {
|
|
currency := x
|
|
go func() {
|
|
ticker, err := b.GetTicker(true)
|
|
if err != nil {
|
|
log.Println(err)
|
|
return
|
|
}
|
|
log.Printf("Bitstamp %s: Last %f High %f Low %f Volume %f\n", currency, ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
|
AddExchangeInfo(b.GetName(), currency[0:3], currency[3:], ticker.Last, ticker.Volume)
|
|
}()
|
|
}
|
|
time.Sleep(time.Second * b.RESTPollingDelay)
|
|
}
|
|
}
|
|
|
|
func (b *Bitstamp) GetTicker(hourly bool) (BitstampTicker, error) {
|
|
path := BITSTAMP_API_URL
|
|
ticker := BitstampTicker{}
|
|
|
|
if hourly {
|
|
path += BITSTAMP_API_TICKER_HOURLY
|
|
} else {
|
|
path += BITSTAMP_API_TICKER
|
|
}
|
|
|
|
err := SendHTTPGetRequest(path, true, &ticker)
|
|
|
|
if err != nil {
|
|
return ticker, err
|
|
}
|
|
|
|
return ticker, nil
|
|
}
|
|
|
|
func (b *Bitstamp) GetTickerPrice(currency string) TickerPrice {
|
|
var tickerPrice TickerPrice
|
|
ticker, err := b.GetTicker(true)
|
|
if err != nil {
|
|
log.Println(err)
|
|
return tickerPrice
|
|
}
|
|
tickerPrice.Ask = ticker.Ask
|
|
tickerPrice.Bid = ticker.Bid
|
|
tickerPrice.CryptoCurrency = currency
|
|
tickerPrice.Low = ticker.Low
|
|
tickerPrice.Last = ticker.Last
|
|
tickerPrice.Volume = ticker.Volume
|
|
tickerPrice.High = ticker.High
|
|
|
|
return tickerPrice
|
|
}
|
|
|
|
func (b *Bitstamp) GetOrderbook() (BitstampOrderbook, error) {
|
|
type response struct {
|
|
Timestamp int64 `json:"timestamp,string"`
|
|
Bids [][]string
|
|
Asks [][]string
|
|
}
|
|
|
|
resp := response{}
|
|
err := SendHTTPGetRequest(BITSTAMP_API_URL+BITSTAMP_API_ORDERBOOK, true, &resp)
|
|
if err != nil {
|
|
return BitstampOrderbook{}, err
|
|
}
|
|
|
|
orderbook := BitstampOrderbook{}
|
|
orderbook.Timestamp = resp.Timestamp
|
|
|
|
for _, x := range resp.Bids {
|
|
price, err := strconv.ParseFloat(x[0], 64)
|
|
if err != nil {
|
|
log.Println(err)
|
|
continue
|
|
}
|
|
amount, err := strconv.ParseFloat(x[1], 64)
|
|
if err != nil {
|
|
log.Println(err)
|
|
continue
|
|
}
|
|
orderbook.Bids = append(orderbook.Bids, BitstampOrderbookBase{price, amount})
|
|
}
|
|
|
|
for _, x := range resp.Asks {
|
|
price, err := strconv.ParseFloat(x[0], 64)
|
|
if err != nil {
|
|
log.Println(err)
|
|
continue
|
|
}
|
|
amount, err := strconv.ParseFloat(x[1], 64)
|
|
if err != nil {
|
|
log.Println(err)
|
|
continue
|
|
}
|
|
orderbook.Asks = append(orderbook.Asks, BitstampOrderbookBase{price, amount})
|
|
}
|
|
|
|
return orderbook, nil
|
|
}
|
|
|
|
func (b *Bitstamp) GetTransactions(values url.Values) ([]BitstampTransactions, error) {
|
|
path := EncodeURLValues(BITSTAMP_API_URL+BITSTAMP_API_TRANSACTIONS, values)
|
|
transactions := []BitstampTransactions{}
|
|
err := SendHTTPGetRequest(path, true, &transactions)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return transactions, nil
|
|
}
|
|
|
|
func (b *Bitstamp) GetEURUSDConversionRate() (BitstampEURUSDConversionRate, error) {
|
|
rate := BitstampEURUSDConversionRate{}
|
|
err := SendHTTPGetRequest(BITSTAMP_API_URL+BITSTAMP_API_EURUSD, true, &rate)
|
|
|
|
if err != nil {
|
|
return rate, err
|
|
}
|
|
return rate, nil
|
|
}
|
|
|
|
func (b *Bitstamp) GetBalance() (BitstampAccountBalance, error) {
|
|
balance := BitstampAccountBalance{}
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_BALANCE, url.Values{}, &balance)
|
|
|
|
if err != nil {
|
|
return balance, err
|
|
}
|
|
return balance, nil
|
|
}
|
|
|
|
func (b *Bitstamp) GetUserTransactions(values url.Values) ([]BitstampUserTransactions, error) {
|
|
response := []BitstampUserTransactions{}
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_USER_TRANSACTIONS, values, &response)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
func (b *Bitstamp) GetOpenOrders() ([]BitstampOrder, error) {
|
|
resp := []BitstampOrder{}
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_OPEN_ORDERS, nil, &resp)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (b *Bitstamp) GetOrderStatus(OrderID int64) (BitstampOrderStatus, error) {
|
|
var req = url.Values{}
|
|
req.Add("id", strconv.FormatInt(OrderID, 10))
|
|
resp := BitstampOrderStatus{}
|
|
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_CANCEL_ORDER, req, &resp)
|
|
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (b *Bitstamp) CancelOrder(OrderID int64) (bool, error) {
|
|
var req = url.Values{}
|
|
result := false
|
|
req.Add("id", strconv.FormatInt(OrderID, 10))
|
|
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_CANCEL_ORDER, req, &result)
|
|
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (b *Bitstamp) CancelAllOrders() (bool, error) {
|
|
result := false
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_CANCEL_ALL_ORDERS, nil, &result)
|
|
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (b *Bitstamp) PlaceOrder(price float64, amount float64, buy bool) (BitstampOrder, error) {
|
|
var req = url.Values{}
|
|
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
|
req.Add("price", strconv.FormatFloat(price, 'f', -1, 64))
|
|
response := BitstampOrder{}
|
|
orderType := BITSTAMP_API_BUY
|
|
|
|
if !buy {
|
|
orderType = BITSTAMP_API_SELL
|
|
}
|
|
|
|
err := b.SendAuthenticatedHTTPRequest(orderType, req, &response)
|
|
|
|
if err != nil {
|
|
return response, err
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
func (b *Bitstamp) GetWithdrawalRequests() ([]BitstampWithdrawalRequests, error) {
|
|
resp := []BitstampWithdrawalRequests{}
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_WITHDRAWAL_REQUESTS, url.Values{}, &resp)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (b *Bitstamp) BitcoinWithdrawal(amount float64, address string) (string, error) {
|
|
var req = url.Values{}
|
|
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
|
req.Add("address", address)
|
|
|
|
type response struct {
|
|
ID string `json:"id"`
|
|
}
|
|
|
|
resp := response{}
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_BITCOIN_WITHDRAWAL, req, &resp)
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return resp.ID, nil
|
|
}
|
|
|
|
func (b *Bitstamp) GetBitcoinDepositAddress() (string, error) {
|
|
address := ""
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_BITCOIN_DEPOSIT, url.Values{}, &address)
|
|
|
|
if err != nil {
|
|
return address, err
|
|
}
|
|
return address, nil
|
|
}
|
|
|
|
func (b *Bitstamp) GetUnconfirmedBitcoinDeposits() ([]BitstampUnconfirmedBTCTransactions, error) {
|
|
response := []BitstampUnconfirmedBTCTransactions{}
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_UNCONFIRMED_BITCOIN, nil, &response)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
func (b *Bitstamp) RippleWithdrawal(amount float64, address, currency string) (bool, error) {
|
|
var req = url.Values{}
|
|
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
|
req.Add("address", address)
|
|
req.Add("currency", currency)
|
|
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_RIPPLE_WITHDRAWAL, req, nil)
|
|
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
func (b *Bitstamp) GetRippleDepositAddress() (string, error) {
|
|
type response struct {
|
|
Address string
|
|
}
|
|
|
|
resp := response{}
|
|
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_RIPPLE_DESPOIT, nil, &resp)
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return resp.Address, nil
|
|
}
|
|
|
|
func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, values url.Values, result interface{}) (err error) {
|
|
nonce := strconv.FormatInt(time.Now().UnixNano(), 10)
|
|
|
|
if values == nil {
|
|
values = url.Values{}
|
|
}
|
|
|
|
values.Set("key", b.APIKey)
|
|
values.Set("nonce", nonce)
|
|
hmac := GetHMAC(HASH_SHA256, []byte(nonce+b.ClientID+b.APIKey), []byte(b.APISecret))
|
|
values.Set("signature", strings.ToUpper(HexEncodeToString(hmac)))
|
|
path = BITSTAMP_API_URL + path
|
|
|
|
if b.Verbose {
|
|
log.Println("Sending POST request to " + path)
|
|
}
|
|
|
|
headers := make(map[string]string)
|
|
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
|
|
|
resp, err := SendHTTPRequest("POST", path, headers, strings.NewReader(values.Encode()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if b.Verbose {
|
|
log.Printf("Recieved raw: %s\n", resp)
|
|
}
|
|
|
|
err = JSONDecode([]byte(resp), &result)
|
|
|
|
if err != nil {
|
|
return errors.New("Unable to JSON Unmarshal response.")
|
|
}
|
|
|
|
return nil
|
|
}
|