Files
gocryptotrader/exchanges/liqui/liqui.go
2018-08-07 13:05:13 +10:00

298 lines
9.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package liqui
import (
"errors"
"fmt"
"log"
"net/url"
"strconv"
"strings"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
const (
liquiAPIPublicURL = "https://api.Liqui.io/api"
liquiAPIPrivateURL = "https://api.Liqui.io/tapi"
liquiAPIPublicVersion = "3"
liquiAPIPrivateVersion = "1"
liquiInfo = "info"
liquiTicker = "ticker"
liquiDepth = "depth"
liquiTrades = "trades"
liquiAccountInfo = "getInfo"
liquiTrade = "Trade"
liquiActiveOrders = "ActiveOrders"
liquiOrderInfo = "OrderInfo"
liquiCancelOrder = "CancelOrder"
liquiTradeHistory = "TradeHistory"
liquiWithdrawCoin = "WithdrawCoin"
liquiAuthRate = 0
liquiUnauthRate = 1
)
// Liqui is the overarching type across the liqui package
type Liqui struct {
exchange.Base
Ticker map[string]Ticker
Info Info
}
// SetDefaults sets current default values for liqui
func (l *Liqui) SetDefaults() {
l.Name = "Liqui"
l.Enabled = false
l.Fee = 0.25
l.Verbose = false
l.Websocket = false
l.RESTPollingDelay = 10
l.Ticker = make(map[string]Ticker)
l.RequestCurrencyPairFormat.Delimiter = "_"
l.RequestCurrencyPairFormat.Uppercase = false
l.RequestCurrencyPairFormat.Separator = "-"
l.ConfigCurrencyPairFormat.Delimiter = "_"
l.ConfigCurrencyPairFormat.Uppercase = true
l.AssetTypes = []string{ticker.Spot}
l.SupportsAutoPairUpdating = true
l.SupportsRESTTickerBatching = true
l.Requester = request.New(l.Name, request.NewRateLimit(time.Second, liquiAuthRate), request.NewRateLimit(time.Second, liquiUnauthRate), common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
}
// Setup sets exchange configuration parameters for liqui
func (l *Liqui) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
l.SetEnabled(false)
} else {
l.Enabled = true
l.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
l.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
l.SetHTTPClientTimeout(exch.HTTPTimeout)
l.SetHTTPClientUserAgent(exch.HTTPUserAgent)
l.RESTPollingDelay = exch.RESTPollingDelay
l.Verbose = exch.Verbose
l.Websocket = exch.Websocket
l.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
l.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
l.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
err := l.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
}
err = l.SetAssetTypes()
if err != nil {
log.Fatal(err)
}
err = l.SetAutoPairDefaults()
if err != nil {
log.Fatal(err)
}
}
}
// GetFee returns a fee for a specific currency
func (l *Liqui) GetFee(currency string) (float64, error) {
val, ok := l.Info.Pairs[common.StringToLower(currency)]
if !ok {
return 0, errors.New("currency does not exist")
}
return val.Fee, nil
}
// GetAvailablePairs returns all available pairs
func (l *Liqui) GetAvailablePairs(nonHidden bool) []string {
var pairs []string
for x, y := range l.Info.Pairs {
if nonHidden && y.Hidden == 1 || x == "" {
continue
}
pairs = append(pairs, common.StringToUpper(x))
}
return pairs
}
// GetInfo provides all the information about currently active pairs, such as
// the maximum number of digits after the decimal point, the minimum price, the
// maximum price, the minimum transaction size, whether the pair is hidden, the
// commission for each pair.
func (l *Liqui) GetInfo() (Info, error) {
resp := Info{}
req := fmt.Sprintf("%s/%s/%s/", liquiAPIPublicURL, liquiAPIPublicVersion, liquiInfo)
return resp, l.SendHTTPRequest(req, &resp)
}
// GetTicker returns information about currently active pairs, such as: the
// maximum price, the minimum price, average price, trade volume, trade volume
// in currency, the last trade, Buy and Sell price. All information is provided
// over the past 24 hours.
//
// currencyPair - example "eth_btc"
func (l *Liqui) GetTicker(currencyPair string) (map[string]Ticker, error) {
type Response struct {
Data map[string]Ticker
Success int `json:"success"`
Error string `json:"error"`
}
response := Response{Data: make(map[string]Ticker)}
req := fmt.Sprintf("%s/%s/%s/%s", liquiAPIPublicURL, liquiAPIPublicVersion, liquiTicker, currencyPair)
return response.Data, l.SendHTTPRequest(req, &response.Data)
}
// GetDepth information about active orders on the pair. Additionally it accepts
// an optional GET-parameter limit, which indicates how many orders should be
// displayed (150 by default). Is set to less than 2000.
func (l *Liqui) GetDepth(currencyPair string) (Orderbook, error) {
type Response struct {
Data map[string]Orderbook
Success int `json:"success"`
Error string `json:"error"`
}
response := Response{Data: make(map[string]Orderbook)}
req := fmt.Sprintf("%s/%s/%s/%s", liquiAPIPublicURL, liquiAPIPublicVersion, liquiDepth, currencyPair)
return response.Data[currencyPair], l.SendHTTPRequest(req, &response.Data)
}
// GetTrades returns information about the last trades. Additionally it accepts
// an optional GET-parameter limit, which indicates how many orders should be
// displayed (150 by default). The maximum allowable value is 2000.
func (l *Liqui) GetTrades(currencyPair string) ([]Trades, error) {
type Response struct {
Data map[string][]Trades
Success int `json:"success"`
Error string `json:"error"`
}
response := Response{Data: make(map[string][]Trades)}
req := fmt.Sprintf("%s/%s/%s/%s", liquiAPIPublicURL, liquiAPIPublicVersion, liquiTrades, currencyPair)
return response.Data[currencyPair], l.SendHTTPRequest(req, &response.Data)
}
// GetAccountInfo returns information about the users current balance, API-key
// privileges, the number of open orders and Server Time. To use this method you
// need a privilege of the key info.
func (l *Liqui) GetAccountInfo() (AccountInfo, error) {
var result AccountInfo
return result,
l.SendAuthenticatedHTTPRequest(liquiAccountInfo, url.Values{}, &result)
}
// Trade creates orders on the exchange.
// to-do: convert orderid to int64
func (l *Liqui) Trade(pair, orderType string, amount, price float64) (float64, error) {
req := url.Values{}
req.Add("pair", pair)
req.Add("type", orderType)
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
req.Add("rate", strconv.FormatFloat(price, 'f', -1, 64))
var result Trade
return result.OrderID, l.SendAuthenticatedHTTPRequest(liquiTrade, req, &result)
}
// GetActiveOrders returns the list of your active orders.
func (l *Liqui) GetActiveOrders(pair string) (map[string]ActiveOrders, error) {
result := make(map[string]ActiveOrders)
req := url.Values{}
req.Add("pair", pair)
return result, l.SendAuthenticatedHTTPRequest(liquiActiveOrders, req, &result)
}
// GetOrderInfo returns the information on particular order.
func (l *Liqui) GetOrderInfo(OrderID int64) (map[string]OrderInfo, error) {
result := make(map[string]OrderInfo)
req := url.Values{}
req.Add("order_id", strconv.FormatInt(OrderID, 10))
return result, l.SendAuthenticatedHTTPRequest(liquiOrderInfo, req, &result)
}
// CancelOrder method is used for order cancelation.
func (l *Liqui) CancelOrder(OrderID int64) (bool, error) {
req := url.Values{}
req.Add("order_id", strconv.FormatInt(OrderID, 10))
var result CancelOrder
err := l.SendAuthenticatedHTTPRequest(liquiCancelOrder, req, &result)
if err != nil {
return false, err
}
return true, nil
}
// GetTradeHistory returns trade history
func (l *Liqui) GetTradeHistory(vals url.Values, pair string) (map[string]TradeHistory, error) {
result := make(map[string]TradeHistory)
if pair != "" {
vals.Add("pair", pair)
}
return result, l.SendAuthenticatedHTTPRequest(liquiTradeHistory, vals, &result)
}
// WithdrawCoins is designed for cryptocurrency withdrawals.
// API mentions that this isn't active now, but will be soon - you must provide the first 8 characters of the key
// in your ticket to support.
func (l *Liqui) WithdrawCoins(coin string, amount float64, address string) (WithdrawCoins, error) {
req := url.Values{}
req.Add("coinName", coin)
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
req.Add("address", address)
var result WithdrawCoins
return result, l.SendAuthenticatedHTTPRequest(liquiWithdrawCoin, req, &result)
}
// SendHTTPRequest sends an unauthenticated HTTP request
func (l *Liqui) SendHTTPRequest(path string, result interface{}) error {
return l.SendPayload("GET", path, nil, nil, result, false, l.Verbose)
}
// SendAuthenticatedHTTPRequest sends an authenticated http request to liqui
func (l *Liqui) SendAuthenticatedHTTPRequest(method string, values url.Values, result interface{}) (err error) {
if !l.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, l.Name)
}
if l.Nonce.Get() == 0 {
l.Nonce.Set(time.Now().Unix())
} else {
l.Nonce.Inc()
}
values.Set("nonce", l.Nonce.String())
values.Set("method", method)
encoded := values.Encode()
hmac := common.GetHMAC(common.HashSHA512, []byte(encoded), []byte(l.APISecret))
if l.Verbose {
log.Printf("Sending POST request to %s calling method %s with params %s\n", liquiAPIPrivateURL, method, encoded)
}
headers := make(map[string]string)
headers["Key"] = l.APIKey
headers["Sign"] = common.HexEncodeToString(hmac)
headers["Content-Type"] = "application/x-www-form-urlencoded"
return l.SendPayload("POST", liquiAPIPrivateURL, headers, strings.NewReader(encoded), result, true, l.Verbose)
}