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
447 lines
12 KiB
Go
447 lines
12 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
LOCALBITCOINS_API_URL = "https://localbitcoins.com"
|
|
LOCALBITCOINS_API_TICKER = "/bitcoinaverage/ticker-all-currencies/"
|
|
LOCALBITCOINS_API_BITCOINCHARTS = "/bitcoincharts/"
|
|
LOCALBITCOINS_API_PINCODE = "pincode/"
|
|
LOCALBITCOINS_API_WALLET = "wallet/"
|
|
LOCALBITCOINS_API_MYSELF = "myself/"
|
|
LOCALBITCOINS_API_WALLET_BALANCE = "wallet-balance/"
|
|
LOCALBITCOINS_API_WALLET_SEND = "wallet-send/"
|
|
LOCALBITCOINS_API_WALLET_SEND_PIN = "wallet-send-pin/"
|
|
LOCALBITCOINS_API_WALLET_ADDRESS = "wallet-addr/"
|
|
)
|
|
|
|
type LocalBitcoins struct {
|
|
Name string
|
|
Enabled bool
|
|
Verbose bool
|
|
Websocket bool
|
|
RESTPollingDelay time.Duration
|
|
AuthenticatedAPISupport bool
|
|
Password, APIKey, APISecret string
|
|
TakerFee, MakerFee float64
|
|
BaseCurrencies []string
|
|
AvailablePairs []string
|
|
EnabledPairs []string
|
|
}
|
|
|
|
func (l *LocalBitcoins) SetDefaults() {
|
|
l.Name = "LocalBitcoins"
|
|
l.Enabled = false
|
|
l.Verbose = false
|
|
l.Verbose = false
|
|
l.Websocket = false
|
|
l.RESTPollingDelay = 10
|
|
}
|
|
|
|
func (l *LocalBitcoins) GetName() string {
|
|
return l.Name
|
|
}
|
|
|
|
func (l *LocalBitcoins) SetEnabled(enabled bool) {
|
|
l.Enabled = enabled
|
|
}
|
|
|
|
func (l *LocalBitcoins) IsEnabled() bool {
|
|
return l.Enabled
|
|
}
|
|
|
|
func (l *LocalBitcoins) Setup(exch Exchanges) {
|
|
if !exch.Enabled {
|
|
l.SetEnabled(false)
|
|
} else {
|
|
l.Enabled = true
|
|
l.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
|
|
l.SetAPIKeys(exch.APIKey, exch.APISecret)
|
|
l.RESTPollingDelay = exch.RESTPollingDelay
|
|
l.Verbose = exch.Verbose
|
|
l.Websocket = exch.Websocket
|
|
l.BaseCurrencies = SplitStrings(exch.BaseCurrencies, ",")
|
|
l.AvailablePairs = SplitStrings(exch.AvailablePairs, ",")
|
|
l.EnabledPairs = SplitStrings(exch.EnabledPairs, ",")
|
|
}
|
|
}
|
|
|
|
func (k *LocalBitcoins) GetEnabledCurrencies() []string {
|
|
return k.EnabledPairs
|
|
}
|
|
|
|
func (l *LocalBitcoins) Start() {
|
|
go l.Run()
|
|
}
|
|
|
|
func (l *LocalBitcoins) GetFee(maker bool) float64 {
|
|
if maker {
|
|
return l.MakerFee
|
|
} else {
|
|
return l.TakerFee
|
|
}
|
|
}
|
|
|
|
func (l *LocalBitcoins) Run() {
|
|
if l.Verbose {
|
|
log.Printf("%s polling delay: %ds.\n", l.GetName(), l.RESTPollingDelay)
|
|
log.Printf("%s %d currencies enabled: %s.\n", l.GetName(), len(l.EnabledPairs), l.EnabledPairs)
|
|
}
|
|
|
|
for l.Enabled {
|
|
ticker, err := l.GetTicker()
|
|
|
|
if err != nil {
|
|
log.Println(err)
|
|
goto sleep
|
|
}
|
|
for _, x := range l.EnabledPairs {
|
|
currency := x[3:]
|
|
log.Printf("LocalBitcoins BTC %s: Last %f Average 1h %f Average 24h %f Volume %f\n", currency, ticker[currency].Rates.Last,
|
|
ticker[currency].Avg1h, ticker[currency].Avg24h, ticker[currency].VolumeBTC)
|
|
AddExchangeInfo(l.GetName(), x[0:3], x[3:], ticker[currency].Rates.Last, ticker[currency].VolumeBTC)
|
|
}
|
|
sleep:
|
|
time.Sleep(time.Second * l.RESTPollingDelay)
|
|
}
|
|
}
|
|
|
|
func (l *LocalBitcoins) SetAPIKeys(apiKey, apiSecret string) {
|
|
l.APIKey = apiKey
|
|
l.APISecret = apiSecret
|
|
}
|
|
|
|
type LocalBitcoinsTicker struct {
|
|
Avg12h float64 `json:"avg_12h"`
|
|
Avg1h float64 `json:"avg_1h"`
|
|
Avg24h float64 `json:"avg_24h"`
|
|
Rates struct {
|
|
Last float64 `json:"last,string"`
|
|
} `json:"rates"`
|
|
VolumeBTC float64 `json:"volume_btc,string"`
|
|
}
|
|
|
|
func (l *LocalBitcoins) GetTicker() (map[string]LocalBitcoinsTicker, error) {
|
|
result := make(map[string]LocalBitcoinsTicker)
|
|
err := SendHTTPGetRequest(LOCALBITCOINS_API_URL+LOCALBITCOINS_API_TICKER, true, &result)
|
|
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (l *LocalBitcoins) GetTickerPrice(currency string) TickerPrice {
|
|
var tickerPrice TickerPrice
|
|
ticker, err := l.GetTicker()
|
|
if err != nil {
|
|
log.Println(err)
|
|
return tickerPrice
|
|
}
|
|
tickerPrice.Ask = ticker[currency].Rates.Last
|
|
tickerPrice.CryptoCurrency = currency
|
|
|
|
return tickerPrice
|
|
}
|
|
|
|
type LocalBitcoinsTrade struct {
|
|
TID int64 `json:"tid"`
|
|
Date int64 `json:"date"`
|
|
Amount float64 `json:"amount,string"`
|
|
Price float64 `json:"price,string"`
|
|
}
|
|
|
|
func (l *LocalBitcoins) GetTrades(currency string, values url.Values) ([]LocalBitcoinsTrade, error) {
|
|
path := EncodeURLValues(fmt.Sprintf("%s/%s/trades.json", LOCALBITCOINS_API_URL+LOCALBITCOINS_API_BITCOINCHARTS, currency), values)
|
|
result := []LocalBitcoinsTrade{}
|
|
err := SendHTTPGetRequest(path, true, &result)
|
|
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
type LocalBitcoinsOrderbookStructure struct {
|
|
Price float64
|
|
Amount float64
|
|
}
|
|
|
|
type LocalBitcoinsOrderbook struct {
|
|
Bids []LocalBitcoinsOrderbookStructure `json:"bids"`
|
|
Asks []LocalBitcoinsOrderbookStructure `json:"asks"`
|
|
}
|
|
|
|
func (l *LocalBitcoins) GetOrderbook(currency string) (LocalBitcoinsOrderbook, error) {
|
|
type response struct {
|
|
Bids [][]string `json:"bids"`
|
|
Asks [][]string `json:"asks"`
|
|
}
|
|
|
|
path := fmt.Sprintf("%s/%s/orderbook.json", LOCALBITCOINS_API_URL+LOCALBITCOINS_API_BITCOINCHARTS, currency)
|
|
resp := response{}
|
|
err := SendHTTPGetRequest(path, true, &resp)
|
|
|
|
if err != nil {
|
|
return LocalBitcoinsOrderbook{}, err
|
|
}
|
|
|
|
orderbook := LocalBitcoinsOrderbook{}
|
|
|
|
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, LocalBitcoinsOrderbookStructure{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, LocalBitcoinsOrderbookStructure{price, amount})
|
|
}
|
|
|
|
return orderbook, nil
|
|
}
|
|
|
|
type LocalBitcoinsAccountInfo struct {
|
|
Username string `json:"username"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
AgeText string `json:"age_text"`
|
|
TradingPartners int `json:"trading_partners_count"`
|
|
FeedbacksUnconfirmed int `json:"feedbacks_unconfirmed_count"`
|
|
TradeVolumeText string `json:"trade_volume_text"`
|
|
HasCommonTrades bool `json:"has_common_trades"`
|
|
HasFeedback bool `json:"has_feedback"`
|
|
ConfirmedTradesText string `json:"confirmed_trade_count_text"`
|
|
BlockedCount int `json:"blocked_count"`
|
|
FeedbackScore int `json:"feedback_score"`
|
|
FeedbackCount int `json:"feedback_count"`
|
|
URL string `json:"url"`
|
|
TrustedCount int `json:"trusted_count"`
|
|
IdentityVerifiedAt time.Time `json:"identify_verified_at"`
|
|
}
|
|
|
|
func (l *LocalBitcoins) GetAccountInfo(username string, self bool) (LocalBitcoinsAccountInfo, error) {
|
|
type response struct {
|
|
Data LocalBitcoinsAccountInfo `json:"data"`
|
|
}
|
|
resp := response{}
|
|
|
|
if self {
|
|
err := l.SendAuthenticatedHTTPRequest("GET", LOCALBITCOINS_API_MYSELF, nil, &resp)
|
|
|
|
if err != nil {
|
|
return resp.Data, err
|
|
}
|
|
} else {
|
|
path := fmt.Sprintf("%s/api/account_info/%s/", LOCALBITCOINS_API_URL, username)
|
|
err := SendHTTPGetRequest(path, true, &resp)
|
|
|
|
if err != nil {
|
|
return resp.Data, err
|
|
}
|
|
}
|
|
|
|
return resp.Data, nil
|
|
}
|
|
|
|
func (l *LocalBitcoins) CheckPincode(pin int) (bool, error) {
|
|
type response struct {
|
|
Data struct {
|
|
PinOK bool `json:"pincode_ok"`
|
|
} `json:"data"`
|
|
}
|
|
resp := response{}
|
|
values := url.Values{}
|
|
values.Set("pincode", strconv.Itoa(pin))
|
|
err := l.SendAuthenticatedHTTPRequest("POST", LOCALBITCOINS_API_PINCODE, values, &resp)
|
|
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if !resp.Data.PinOK {
|
|
return false, errors.New("Pin invalid.")
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
type LocalBitcoinsBalance struct {
|
|
Balance float64 `json:"balance,string"`
|
|
Sendable float64 `json:"Sendable,string"`
|
|
}
|
|
|
|
type LocalBitcoinsWalletTransaction struct {
|
|
TXID string `json:"txid"`
|
|
Amount float64 `json:"amount,string"`
|
|
Description string `json:"description"`
|
|
TXType int `json:"tx_type"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type LocalBitcoinsWalletAddressList struct {
|
|
Address string `json:"address"`
|
|
Received float64 `json:"received,string"`
|
|
}
|
|
|
|
type LocalBitcoinsWalletInfo struct {
|
|
Message string `json:"message"`
|
|
Total LocalBitcoinsBalance `json:"total"`
|
|
SentTransactions30d []LocalBitcoinsWalletTransaction `json:"sent_transactions_30d"`
|
|
ReceivedTransactions30d []LocalBitcoinsWalletTransaction `json:"received_transactions_30d"`
|
|
ReceivingAddressCount int `json:"receiving_address_count"`
|
|
ReceivingAddressList []LocalBitcoinsWalletAddressList `json:"receiving_address_list"`
|
|
}
|
|
|
|
func (l *LocalBitcoins) GetWalletInfo() (LocalBitcoinsWalletInfo, error) {
|
|
type response struct {
|
|
Data LocalBitcoinsWalletInfo `json:"data"`
|
|
}
|
|
resp := response{}
|
|
err := l.SendAuthenticatedHTTPRequest("GET", LOCALBITCOINS_API_WALLET, nil, &resp)
|
|
|
|
if err != nil {
|
|
return LocalBitcoinsWalletInfo{}, err
|
|
}
|
|
|
|
if resp.Data.Message != "OK" {
|
|
return LocalBitcoinsWalletInfo{}, errors.New("Unable to fetch wallet info.")
|
|
}
|
|
|
|
return resp.Data, nil
|
|
}
|
|
|
|
type LocalBitcoinsWalletBalanceInfo struct {
|
|
Message string `json:"message"`
|
|
Total LocalBitcoinsBalance `json:"total"`
|
|
ReceivingAddressCount int `json:"receiving_address_count"` // always 1
|
|
ReceivingAddressList []LocalBitcoinsWalletAddressList `json:"receiving_address_list"`
|
|
}
|
|
|
|
func (l *LocalBitcoins) GetWalletBalance() (LocalBitcoinsWalletBalanceInfo, error) {
|
|
type response struct {
|
|
Data LocalBitcoinsWalletBalanceInfo `json:"data"`
|
|
}
|
|
resp := response{}
|
|
err := l.SendAuthenticatedHTTPRequest("GET", LOCALBITCOINS_API_WALLET_BALANCE, nil, &resp)
|
|
|
|
if err != nil {
|
|
return LocalBitcoinsWalletBalanceInfo{}, err
|
|
}
|
|
|
|
if resp.Data.Message != "OK" {
|
|
return LocalBitcoinsWalletBalanceInfo{}, errors.New("Unable to fetch wallet balance.")
|
|
}
|
|
|
|
return resp.Data, nil
|
|
}
|
|
|
|
func (l *LocalBitcoins) WalletSend(address string, amount float64, pin int) (bool, error) {
|
|
values := url.Values{}
|
|
values.Set("address", address)
|
|
values.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
|
path := LOCALBITCOINS_API_WALLET_SEND
|
|
|
|
if pin > 0 {
|
|
values.Set("pincode", strconv.Itoa(pin))
|
|
path = LOCALBITCOINS_API_WALLET_SEND_PIN
|
|
}
|
|
|
|
type response struct {
|
|
Data struct {
|
|
Message string `json:"message"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
resp := response{}
|
|
err := l.SendAuthenticatedHTTPRequest("POST", path, values, &resp)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if resp.Data.Message != "Money is being sent" {
|
|
return false, errors.New("Unable to send Bitcoins.")
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
func (l *LocalBitcoins) GetWalletAddress() (string, error) {
|
|
type response struct {
|
|
Data struct {
|
|
Message string `json:"message"`
|
|
Address string `json:"address"`
|
|
}
|
|
}
|
|
resp := response{}
|
|
err := l.SendAuthenticatedHTTPRequest("POST", LOCALBITCOINS_API_WALLET_ADDRESS, nil, &resp)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if resp.Data.Message != "OK!" {
|
|
return "", errors.New("Unable to fetch wallet address.")
|
|
}
|
|
|
|
return resp.Data.Address, nil
|
|
}
|
|
|
|
func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, values url.Values, result interface{}) (err error) {
|
|
nonce := strconv.FormatInt(time.Now().UnixNano(), 10)
|
|
payload := ""
|
|
path = "/api/" + path
|
|
|
|
if len(values) > 0 {
|
|
payload = values.Encode()
|
|
}
|
|
|
|
message := string(nonce) + l.APIKey + path + payload
|
|
hmac := GetHMAC(HASH_SHA256, []byte(message), []byte(l.APISecret))
|
|
headers := make(map[string]string)
|
|
headers["Apiauth-Key"] = l.APIKey
|
|
headers["Apiauth-Nonce"] = string(nonce)
|
|
headers["Apiauth-Signature"] = StringToUpper(HexEncodeToString(hmac))
|
|
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
|
|
|
resp, err := SendHTTPRequest(method, LOCALBITCOINS_API_URL+path, headers, bytes.NewBuffer([]byte(payload)))
|
|
|
|
if l.Verbose {
|
|
log.Printf("Recieved raw: \n%s\n", resp)
|
|
}
|
|
|
|
err = JSONDecode([]byte(resp), &result)
|
|
|
|
if err != nil {
|
|
return errors.New("Unable to JSON Unmarshal response.")
|
|
}
|
|
|
|
return nil
|
|
}
|