mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-24 23:16:52 +00:00
298 lines
9.5 KiB
Go
298 lines
9.5 KiB
Go
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 user’s 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)
|
||
}
|