Remove Liqui exchange from GCT

This commit is contained in:
Adrian Gallagher
2019-02-05 11:17:05 +11:00
parent 978b91a692
commit d7368c1a8d
14 changed files with 10 additions and 1618 deletions

View File

@@ -40,7 +40,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
| ItBit | Yes | NA | No |
| Kraken | Yes | NA | NA |
| LakeBTC | Yes | No | NA |
| Liqui | Yes | No | NA |
| LocalBitcoins | Yes | NA | NA |
| OKCoin China | Yes | Yes | No |
| OKCoin International | Yes | Yes | No |

View File

@@ -8,6 +8,12 @@ import (
log "github.com/thrasher-/gocryptotrader/logger"
)
const (
// Default number of enabled exchanges. Modify this whenever an exchange is
// added or removed
defaultEnabledExchanges = 29
)
func TestGetCurrencyConfig(t *testing.T) {
cfg := GetConfig()
err := cfg.LoadConfig(ConfigTestFile)
@@ -408,7 +414,7 @@ func TestGetEnabledExchanges(t *testing.T) {
}
exchanges := cfg.GetEnabledExchanges()
if len(exchanges) != 30 {
if len(exchanges) != defaultEnabledExchanges {
t.Error(
"Test failed. TestGetEnabledExchanges. Enabled exchanges value mismatch",
)
@@ -460,7 +466,6 @@ func TestGetDisabledExchanges(t *testing.T) {
}
func TestCountEnabledExchanges(t *testing.T) {
defaultEnabledExchanges := 30
GetConfigEnabledExchanges := GetConfig()
err := GetConfigEnabledExchanges.LoadConfig(ConfigTestFile)
if err != nil {
@@ -489,7 +494,7 @@ func TestGetConfigCurrencyPairFormat(t *testing.T) {
)
}
exchFmt, err := cfg.GetConfigCurrencyPairFormat("Liqui")
exchFmt, err := cfg.GetConfigCurrencyPairFormat("Yobit")
if !exchFmt.Uppercase || exchFmt.Delimiter != "_" {
t.Errorf(
"Test failed. TestGetConfigCurrencyPairFormat. Invalid values",
@@ -513,7 +518,7 @@ func TestGetRequestCurrencyPairFormat(t *testing.T) {
)
}
exchFmt, err := cfg.GetRequestCurrencyPairFormat("Liqui")
exchFmt, err := cfg.GetRequestCurrencyPairFormat("Bitfinex")
if exchFmt.Uppercase || exchFmt.Delimiter != "_" || exchFmt.Separator != "-" {
t.Errorf(
"Test failed. TestGetRequestCurrencyPairFormat. Invalid values",

View File

@@ -986,48 +986,6 @@
}
]
},
{
"name": "Liqui",
"enabled": true,
"verbose": false,
"websocket": false,
"useSandbox": false,
"restPollingDelay": 10,
"httpTimeout": 15000000000,
"httpUserAgent": "",
"authenticatedApiSupport": false,
"apiKey": "Key",
"apiSecret": "Secret",
"apiUrl": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
"apiUrlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
"proxyAddress": "",
"websocketUrl": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API",
"availablePairs": "ANT_ETH,BNT_ETH,HOT_ETH,OAX_ETH,AST_BTC,SALT_ETH,LTC_BTC,ETH_BTC,GNO_USDT,SAN_ETH,RLC_ETH,STORJ_BTC,WPR_BTC,OMG_ETH,INS_ETH,AION_ETH,PRO_BTC,KNC_USDT,DASH_ETH,SNT_BTC,AION_USDT,ADX_BTC,MANA_ETH,WINGS_BTC,ETH_USDT,GUP_ETH,CVC_USDT,OAX_BTC,AGI_ETH,TTU_ETH,SNT_ETH,TNT_USDT,LTC_USDT,RLC_BTC,TRST_USDT,SNT_USDT,OMG_USDT,BCHABC_USDT,REP_ETH,ADX_USDT,DGD_USDT,GNO_BTC,SNGLS_USDT,AION_BTC,WINGS_ETH,ENJ_ETH,DASH_BTC,WPR_USDT,TRST_BTC,OMG_BTC,TRX_BTC,STORJ_USDT,BMC_USDT,CLN_USDT,IND_BTC,ENG_BTC,AST_ETH,DGD_ETH,LDC_ETH,ENJ_USDT,TNT_ETH,TRX_ETH,DGD_BTC,ENG_ETH,SALT_BTC,CLN_BTC,GNO_ETH,TRST_ETH,ANT_BTC,ANT_USDT,PRO_USDT,GUP_USDT,SNGLS_BTC,MANA_BTC,CVC_BTC,SALT_USDT,BTC_USDT,TNT_BTC,BNT_USDT,PAY_USDT,WINGS_USDT,BMC_BTC,ENG_USDT,GNT_USDT,OAX_USDT,GUP_BTC,GNT_BTC,SRN_ETH,TTU_USDT,GNT_ETH,REP_USDT,RLC_USDT,SAN_BTC,BCHABC_ETH,MANA_USDT,PRO_ETH,TRX_USDT,CLN_ETH,LDC_USDT,AGI_BTC,INS_BTC,STORJ_ETH,PAY_ETH,LDC_BTC,CVC_ETH,INS_USDT,SAN_USDT,ENJ_BTC,AGI_USDT,TTU_BTC,BNT_BTC,IND_ETH,IND_USDT,AST_USDT,WPR_ETH,HOT_BTC,REP_BTC,SNGLS_ETH,ADX_ETH,BMC_ETH,KNC_BTC,DASH_USDT,BCHABC_BTC,KNC_ETH,LTC_ETH,HOT_USDT,PAY_BTC",
"enabledPairs": "ETH_BTC,LTC_BTC,DASH_BTC",
"baseCurrencies": "USD",
"assetTypes": "SPOT",
"supportsAutoPairUpdates": true,
"configCurrencyPairFormat": {
"uppercase": true,
"delimiter": "_"
},
"requestCurrencyPairFormat": {
"uppercase": false,
"delimiter": "_",
"separator": "-"
},
"bankAccounts": [
{
"bankName": "",
"bankAddress": "",
"accountName": "",
"accountNumber": "",
"swiftCode": "",
"iban": "",
"supportedCurrencies": ""
}
]
},
{
"name": "LocalBitcoins",
"enabled": true,

View File

@@ -27,7 +27,6 @@ import (
"github.com/thrasher-/gocryptotrader/exchanges/itbit"
"github.com/thrasher-/gocryptotrader/exchanges/kraken"
"github.com/thrasher-/gocryptotrader/exchanges/lakebtc"
"github.com/thrasher-/gocryptotrader/exchanges/liqui"
"github.com/thrasher-/gocryptotrader/exchanges/localbitcoins"
"github.com/thrasher-/gocryptotrader/exchanges/okcoin"
"github.com/thrasher-/gocryptotrader/exchanges/okex"
@@ -178,8 +177,6 @@ func LoadExchange(name string, useWG bool, wg *sync.WaitGroup) error {
exch = new(kraken.Kraken)
case "lakebtc":
exch = new(lakebtc.LakeBTC)
case "liqui":
exch = new(liqui.Liqui)
case "localbitcoins":
exch = new(localbitcoins.LocalBitcoins)
case "okcoin china":

View File

@@ -589,7 +589,7 @@ func TestGetAndFormatExchangeCurrencies(t *testing.T) {
pairs = append(pairs, pair.NewCurrencyPairDelimiter("BTC_USD", "_"))
pairs = append(pairs, pair.NewCurrencyPairDelimiter("LTC_BTC", "_"))
actual, err := GetAndFormatExchangeCurrencies("Liqui", pairs)
actual, err := GetAndFormatExchangeCurrencies("Yobit", pairs)
if err != nil {
t.Errorf("Test failed - Exchange TestGetAndFormatExchangeCurrencies error %s", err)
}

View File

@@ -1,133 +0,0 @@
# GoCryptoTrader package Liqui
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
[![Build Status](https://travis-ci.org/thrasher-/gocryptotrader.svg?branch=master)](https://travis-ci.org/thrasher-/gocryptotrader)
[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/thrasher-/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-/gocryptotrader/exchanges/liqui)
[![Coverage Status](http://codecov.io/github/thrasher-/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-/gocryptotrader)](https://goreportcard.com/report/github.com/thrasher-/gocryptotrader)
This liqui package is part of the GoCryptoTrader codebase.
## This is still in active development
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://gocryptotrader.herokuapp.com/)
## Liqui Exchange
### Current Features
+ REST Support
### How to enable
+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
+ Individual package example below:
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### How to do REST public/private calls
+ If enabled via "configuration".json file the exchange will be added to the
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
the wrapper interface functions for accessing exchange data. View routines.go
for an example of integration usage with GoCryptoTrader. Rudimentary example
below:
main.go
```go
var l exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "Liqui" {
l = bot.exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := l.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := l.GetOrderbookEx()
if err != nil {
// Handle error
}
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
// set and AuthenticatedAPISupport is set to true
// Fetches current account information
accountInfo, err := l.GetAccountInfo()
if err != nil {
// Handle error
}
```
+ If enabled via individually importing package, rudimentary example below:
```go
// Public calls
// Fetches current ticker information
ticker, err := l.GetTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := l.GetOrderBook()
if err != nil {
// Handle error
}
// Private calls - make sure your APIKEY and APISECRET are set and
// AuthenticatedAPISupport is set to true
// GetUserInfo returns account info
accountInfo, err := l.GetUserInfo(...)
if err != nil {
// Handle error
}
// Submits an order and the exchange and returns its tradeID
tradeID, err := l.Trade(...)
if err != nil {
// Handle error
}
```
### Please click GoDocs chevron above to view current GoDoc information for this package
## Contribution
Please feel free to submit any pull requests or suggest any desired features to be added.
When submitting a PR, please abide by our coding guidelines:
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
+ Code must adhere to our [coding style](https://github.com/thrasher-/gocryptotrader/blob/master/doc/coding_style.md).
+ Pull requests need to be based on and opened against the `master` branch.
## Donations
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***

View File

@@ -1,348 +0,0 @@
package liqui
import (
"errors"
"fmt"
"net/url"
"strconv"
"strings"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
log "github.com/thrasher-/gocryptotrader/logger"
)
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.RESTPollingDelay = 10
l.Ticker = make(map[string]Ticker)
l.APIWithdrawPermissions = exchange.WithdrawCryptoWithAPIPermission |
exchange.NoFiatWithdrawals
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))
l.APIUrlDefault = liquiAPIPublicURL
l.APIUrl = l.APIUrlDefault
l.APIUrlSecondaryDefault = liquiAPIPrivateURL
l.APIUrlSecondary = l.APIUrlSecondaryDefault
l.WebsocketInit()
}
// 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.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)
}
err = l.SetAPIURL(exch)
if err != nil {
log.Fatal(err)
}
err = l.SetClientProxyAddress(exch.ProxyAddress)
if err != nil {
log.Fatal(err)
}
}
}
// 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/", l.APIUrl, 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", l.APIUrl, 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", l.APIUrl, 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", l.APIUrl, liquiAPIPublicVersion, liquiTrades, currencyPair)
return response.Data[currencyPair], l.SendHTTPRequest(req, &response.Data)
}
// GetAccountInformation 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) GetAccountInformation() (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
err := l.SendAuthenticatedHTTPRequest(liquiTrade, req, &result)
if result.Success == 0 {
return -1, errors.New(result.Error)
}
return result.OrderID, err
}
// GetOpenOrders returns the list of your active orders.
func (l *Liqui) GetOpenOrders(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)
}
// GetOrderInfoByID returns the information on particular order.
func (l *Liqui) GetOrderInfoByID(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)
}
// CancelExistingOrder method is used for order cancelation.
func (l *Liqui) CancelExistingOrder(OrderID int64) error {
req := url.Values{}
req.Add("order_id", strconv.FormatInt(OrderID, 10))
var result CancelOrder
err := l.SendAuthenticatedHTTPRequest(liquiCancelOrder, req, &result)
if result.Success == 0 {
return errors.New(result.Error)
}
return err
}
// 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
err := l.SendAuthenticatedHTTPRequest(liquiWithdrawCoin, req, &result)
if err != nil {
return WithdrawCoins{}, err
}
if len(result.Error) > 0 {
return result, errors.New(result.Error)
}
return result, nil
}
// 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.Debugf("Sending POST request to %s calling method %s with params %s\n",
l.APIUrlSecondary, 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",
l.APIUrlSecondary, headers,
strings.NewReader(encoded),
result,
true,
l.Verbose)
}
// GetFee returns an estimate of fee based on type of transaction
func (l *Liqui) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
var fee float64
switch feeBuilder.FeeType {
case exchange.CryptocurrencyTradeFee:
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount, feeBuilder.IsMaker)
case exchange.CryptocurrencyWithdrawalFee:
fee = getCryptocurrencyWithdrawalFee(feeBuilder.FirstCurrency)
}
if fee < 0 {
fee = 0
}
return fee, nil
}
func getCryptocurrencyWithdrawalFee(currency string) float64 {
return WithdrawalFees[currency]
}
func calculateTradingFee(purchasePrice, amount float64, isMaker bool) (fee float64) {
if isMaker {
fee = 0.001
} else {
fee = 0.0025
}
return fee * purchasePrice * amount
}

View File

@@ -1,411 +0,0 @@
package liqui
import (
"net/url"
"testing"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
var l Liqui
const (
apiKey = ""
apiSecret = ""
canManipulateRealOrders = false
)
func TestSetDefaults(t *testing.T) {
l.SetDefaults()
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
liquiConfig, err := cfg.GetExchangeConfig("Liqui")
if err != nil {
t.Error("Test Failed - liqui Setup() init error")
}
liquiConfig.AuthenticatedAPISupport = true
liquiConfig.APIKey = apiKey
liquiConfig.APISecret = apiSecret
l.Setup(liquiConfig)
}
func TestGetAvailablePairs(t *testing.T) {
t.Parallel()
v := l.GetAvailablePairs(false)
if len(v) != 0 {
t.Error("Test Failed - liqui GetFee() error")
}
}
func TestGetInfo(t *testing.T) {
t.Parallel()
_, err := l.GetInfo()
if err != nil {
t.Error("Test Failed - liqui GetInfo() error", err)
}
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := l.GetTicker("eth_btc")
if err != nil {
t.Error("Test Failed - liqui GetTicker() error", err)
}
}
func TestGetDepth(t *testing.T) {
t.Parallel()
_, err := l.GetDepth("eth_btc")
if err != nil {
t.Error("Test Failed - liqui GetDepth() error", err)
}
}
func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := l.GetTrades("eth_btc")
if err != nil {
t.Error("Test Failed - liqui GetTrades() error", err)
}
}
func TestAuthRequests(t *testing.T) {
if l.APIKey != "" && l.APISecret != "" {
_, err := l.GetAccountInfo()
if err == nil {
t.Error("Test Failed - liqui GetAccountInfo() error", err)
}
_, err = l.Trade("", "", 0, 1)
if err == nil {
t.Error("Test Failed - liqui Trade() error", err)
}
_, err = l.GetOpenOrders("eth_btc")
if err == nil {
t.Error("Test Failed - liqui GetActiveOrders() error", err)
}
_, err = l.GetOrderInfo(1337)
if err == nil {
t.Error("Test Failed - liqui GetOrderInfo() error", err)
}
err = l.CancelExistingOrder(1337)
if err == nil {
t.Error("Test Failed - liqui CancelExistingOrder() error", err)
}
_, err = l.GetTradeHistory(url.Values{}, "")
if err == nil {
t.Error("Test Failed - liqui GetTradeHistory() error", err)
}
_, err = l.WithdrawCoins("btc", 1337, "someaddr")
if err == nil {
t.Error("Test Failed - liqui WithdrawCoins() error", err)
}
}
}
func TestUpdateTicker(t *testing.T) {
p := pair.NewCurrencyPairDelimiter("ETH_BTC", "_")
_, err := l.UpdateTicker(p, "SPOT")
if err != nil {
t.Error("Test Failed - liqui UpdateTicker() error", err)
}
}
func TestUpdateOrderbook(t *testing.T) {
p := pair.NewCurrencyPairDelimiter("ETH_BTC", "_")
_, err := l.UpdateOrderbook(p, "SPOT")
if err != nil {
t.Error("Test Failed - liqui UpdateOrderbook() error", err)
}
}
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "-",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.LTC,
SecondCurrency: symbol.BTC,
IsMaker: false,
PurchasePrice: 1,
CurrencyItem: symbol.USD,
BankTransactionType: exchange.WireTransfer,
}
}
func TestGetFee(t *testing.T) {
l.SetDefaults()
var feeBuilder = setFeeBuilder()
// CryptocurrencyTradeFee Basic
if resp, err := l.GetFee(feeBuilder); resp != float64(0.0025) || err != nil {
t.Error(err)
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.0025), resp)
}
// CryptocurrencyTradeFee High quantity
feeBuilder = setFeeBuilder()
feeBuilder.Amount = 1000
feeBuilder.PurchasePrice = 1000
if resp, err := l.GetFee(feeBuilder); resp != float64(2500) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(2000), resp)
t.Error(err)
}
// CryptocurrencyTradeFee IsMaker
feeBuilder = setFeeBuilder()
feeBuilder.IsMaker = true
if resp, err := l.GetFee(feeBuilder); resp != float64(0.001) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.001), resp)
t.Error(err)
}
// CryptocurrencyTradeFee Negative purchase price
feeBuilder = setFeeBuilder()
feeBuilder.PurchasePrice = -1000
if resp, err := l.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
// CryptocurrencyWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
if resp, err := l.GetFee(feeBuilder); resp != float64(0.01) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.01), resp)
t.Error(err)
}
// CryptocurrencyWithdrawalFee Invalid currency
feeBuilder = setFeeBuilder()
feeBuilder.FirstCurrency = "hello"
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
if resp, err := l.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
// CyptocurrencyDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.CyptocurrencyDepositFee
if resp, err := l.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
if resp, err := l.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.USD
if resp, err := l.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
}
func TestFormatWithdrawPermissions(t *testing.T) {
l.SetDefaults()
expectedResult := exchange.WithdrawCryptoWithAPIPermissionText + " & " + exchange.NoFiatWithdrawalsText
withdrawPermissions := l.FormatWithdrawPermissions()
if withdrawPermissions != expectedResult {
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
}
}
func TestGetActiveOrders(t *testing.T) {
l.SetDefaults()
TestSetup(t)
var getOrdersRequest = exchange.GetOrdersRequest{
OrderType: exchange.AnyOrderType,
Currencies: []pair.CurrencyPair{pair.NewCurrencyPair(symbol.BTC, symbol.USDT)},
}
_, err := l.GetActiveOrders(getOrdersRequest)
if areTestAPIKeysSet() && err != nil {
t.Errorf("Could not get open orders: %s", err)
} else if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
}
}
func TestGetOrderHistory(t *testing.T) {
l.SetDefaults()
TestSetup(t)
var getOrdersRequest = exchange.GetOrdersRequest{
OrderType: exchange.AnyOrderType,
}
_, err := l.GetOrderHistory(getOrdersRequest)
if err != common.ErrFunctionNotSupported {
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
}
}
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
// ----------------------------------------------------------------------------------------------------------------------------
func areTestAPIKeysSet() bool {
if l.APIKey != "" && l.APIKey != "Key" &&
l.APISecret != "" && l.APISecret != "Secret" {
return true
}
return false
}
func TestSubmitOrder(t *testing.T) {
l.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "",
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.EUR,
}
response, err := l.SubmitOrder(p, exchange.BuyOrderSide, exchange.MarketOrderType, 1, 10, "hi")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
t.Errorf("Order failed to be placed: %v", err)
} else if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
}
}
func TestCancelExchangeOrder(t *testing.T) {
l.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
AccountID: "1",
CurrencyPair: currencyPair,
}
err := l.CancelOrder(orderCancellation)
if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
}
if areTestAPIKeysSet() && err != nil {
t.Errorf("Could not cancel orders: %v", err)
}
}
func TestCancelAllExchangeOrders(t *testing.T) {
l.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
AccountID: "1",
CurrencyPair: currencyPair,
}
resp, err := l.CancelAllOrders(orderCancellation)
if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
}
if areTestAPIKeysSet() && err != nil {
t.Errorf("Could not cancel orders: %v", err)
}
if len(resp.OrderStatus) > 0 {
t.Errorf("%v orders failed to cancel", len(resp.OrderStatus))
}
}
func TestModifyOrder(t *testing.T) {
_, err := l.ModifyOrder(exchange.ModifyOrder{})
if err == nil {
t.Error("Test failed - ModifyOrder() error")
}
}
func TestWithdraw(t *testing.T) {
l.SetDefaults()
TestSetup(t)
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.LTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
}
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
_, err := l.WithdrawCryptocurrencyFunds(withdrawCryptoRequest)
if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
}
if areTestAPIKeysSet() && err != nil {
t.Errorf("Withdraw failed to be placed: %v", err)
}
}
func TestWithdrawFiat(t *testing.T) {
l.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var withdrawFiatRequest = exchange.WithdrawRequest{}
_, err := l.WithdrawFiatFunds(withdrawFiatRequest)
if err != common.ErrFunctionNotSupported {
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
}
}
func TestWithdrawInternationalBank(t *testing.T) {
l.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var withdrawFiatRequest = exchange.WithdrawRequest{}
_, err := l.WithdrawFiatFundsToInternationalBank(withdrawFiatRequest)
if err != common.ErrFunctionNotSupported {
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
}
}

View File

@@ -1,225 +0,0 @@
package liqui
import "github.com/thrasher-/gocryptotrader/currency/symbol"
// Info holds the current pair information as well as server time
type Info struct {
ServerTime int64 `json:"server_time"`
Pairs map[string]PairData `json:"pairs"`
Success int `json:"success"`
Error string `json:"error"`
}
// PairData is a sub-type for Info
type PairData struct {
DecimalPlaces int `json:"decimal_places"`
MinPrice float64 `json:"min_price"`
MaxPrice float64 `json:"max_price"`
MinAmount float64 `json:"min_amount"`
Hidden int `json:"hidden"`
Fee float64 `json:"fee"`
}
// Ticker contains ticker information
type Ticker struct {
High float64
Low float64
Avg float64
Vol float64
VolumeCurrency float64
Last float64
Buy float64
Sell float64
Updated int64
}
// Orderbook references both ask and bid sides
type Orderbook struct {
Asks [][]float64 `json:"asks"`
Bids [][]float64 `json:"bids"`
}
// Trades contains trade information
type Trades struct {
Type string `json:"type"`
Price float64 `json:"bid"`
Amount float64 `json:"amount"`
TID int64 `json:"tid"`
Timestamp int64 `json:"timestamp"`
}
// AccountInfo contains full account details information
type AccountInfo struct {
Funds map[string]float64 `json:"funds"`
Rights struct {
Info bool `json:"info"`
Trade bool `json:"trade"`
Withdraw bool `json:"withdraw"`
} `json:"rights"`
ServerTime float64 `json:"server_time"`
TransactionCount int `json:"transaction_count"`
OpenOrders int `json:"open_orders"`
Success int `json:"success"`
Error string `json:"error"`
}
// ActiveOrders holds active order information
type ActiveOrders struct {
Pair string `json:"pair"`
Type string `json:"sell"`
Amount float64 `json:"amount"`
Rate float64 `json:"rate"`
TimestampCreated float64 `json:"time_created"`
Status int `json:"status"`
Success int `json:"success"`
Error string `json:"error"`
}
// OrderInfo holds specific order information
type OrderInfo struct {
Pair string `json:"pair"`
Type string `json:"sell"`
StartAmount float64 `json:"start_amount"`
Amount float64 `json:"amount"`
Rate float64 `json:"rate"`
TimestampCreated float64 `json:"time_created"`
Status int `json:"status"`
Success int `json:"success"`
Error string `json:"error"`
}
// CancelOrder holds cancelled order information
type CancelOrder struct {
OrderID float64 `json:"order_id"`
Funds map[string]float64 `json:"funds"`
Success int `json:"success"`
Error string `json:"error"`
}
// Trade holds trading information
type Trade struct {
Received float64 `json:"received"`
Remains float64 `json:"remains"`
OrderID float64 `json:"order_id"`
Funds map[string]float64 `json:"funds"`
Success int `json:"success"`
Error string `json:"error"`
}
// TradeHistory contains trade history data
type TradeHistory struct {
Pair string `json:"pair"`
Type string `json:"type"`
Amount float64 `json:"amount"`
Rate float64 `json:"rate"`
OrderID float64 `json:"order_id"`
MyOrder int `json:"is_your_order"`
Timestamp float64 `json:"timestamp"`
Success int `json:"success"`
Error string `json:"error"`
}
// Response is a generalized return type
type Response struct {
Return interface{} `json:"return"`
Success int `json:"success"`
Error string `json:"error"`
}
// WithdrawCoins shows the amount of coins withdrawn from liqui not yet available
type WithdrawCoins struct {
TID int64 `json:"tId"`
AmountSent float64 `json:"amountSent"`
Funds map[string]float64 `json:"funds"`
Success int `json:"success"`
Error string `json:"error"`
}
// WithdrawalFees the large list of predefined withdrawal fees
// Prone to change
var WithdrawalFees = map[string]float64{
symbol.ZRX: 5,
symbol.ADX: 10,
symbol.AE: 2,
symbol.AION: 5,
symbol.AST: 25,
symbol.ANT: 2,
symbol.REP: 0.15,
symbol.BNT: 1.5,
symbol.BAT: 20,
symbol.BTC: 0.001,
symbol.BCH: 0.007,
symbol.BMC: 7,
symbol.BCAP: 2,
symbol.TIME: 0.5,
symbol.CVC: 15,
symbol.CFI: 100,
symbol.CLN: 100,
symbol.DASH: 0.003,
symbol.MANA: 40,
symbol.DGD: 0.05,
symbol.DNT: 100,
symbol.EDG: 15,
symbol.ENG: 3,
symbol.ENJ: 50,
symbol.EOS: 0.5,
symbol.ETH: 0.01,
symbol.FIRST: 5,
symbol.GNO: 0.1,
symbol.GNT: 15,
symbol.GOLOS: 0.01,
symbol.GBG: 0.01,
symbol.HMQ: 20,
symbol.ICN: 7,
symbol.RLC: 5,
symbol.INCNT: 1,
symbol.IND: 70,
symbol.INS: 7,
symbol.KNC: 4,
symbol.LDC: 1000,
symbol.LTC: 0.01,
symbol.LUN: 0.5,
symbol.GUP: 40,
symbol.MLN: 0.2,
symbol.MGO: 20,
symbol.MCO: 0.7,
symbol.MYST: 20,
symbol.NEU: 7,
symbol.NET: 10,
symbol.OAX: 10,
symbol.OMG: 0.5,
symbol.PTOY: 50,
symbol.PLU: 0.5,
symbol.PRO: 7,
symbol.QTUM: 0.2,
symbol.QRL: 10,
symbol.REN: 100,
symbol.REQ: 50,
symbol.ROUND: 100,
symbol.SALT: 4,
symbol.SAN: 4,
symbol.SNGLS: 80,
symbol.AGI: 50,
symbol.SRN: 30,
symbol.SNM: 25,
symbol.XID: 50,
symbol.SNT: 50,
symbol.STEEM: 0.01,
symbol.SBD: 0.01,
symbol.STORJ: 7,
symbol.STX: 20,
symbol.TAAS: 2,
symbol.PAY: 5,
symbol.USDT: 20,
symbol.TNT: 100,
symbol.TKN: 5,
symbol.TRX: 100,
symbol.VEN: 3,
symbol.VSL: 30,
symbol.WAVES: 0.01,
symbol.WPR: 100,
symbol.TRST: 100,
symbol.WINGS: 20,
symbol.XXX: 0.01,
symbol.XZC: 0.01,
}

View File

@@ -1,307 +0,0 @@
package liqui
import (
"errors"
"fmt"
"strconv"
"strings"
"sync"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
log "github.com/thrasher-/gocryptotrader/logger"
)
// Start starts the Liqui go routine
func (l *Liqui) Start(wg *sync.WaitGroup) {
wg.Add(1)
go func() {
l.Run()
wg.Done()
}()
}
// Run implements the Liqui wrapper
func (l *Liqui) Run() {
if l.Verbose {
log.Debugf("%s polling delay: %ds.\n", l.GetName(), l.RESTPollingDelay)
log.Debugf("%s %d currencies enabled: %s.\n", l.GetName(), len(l.EnabledPairs), l.EnabledPairs)
}
var err error
l.Info, err = l.GetInfo()
if err != nil {
log.Errorf("%s Unable to fetch info.\n", l.GetName())
} else {
exchangeProducts := l.GetAvailablePairs(true)
err = l.UpdateCurrencies(exchangeProducts, false, false)
if err != nil {
log.Errorf("%s Failed to get config.\n", l.GetName())
}
}
}
// UpdateTicker updates and returns the ticker for a currency pair
func (l *Liqui) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
pairsString, err := exchange.GetAndFormatExchangeCurrencies(l.Name,
l.GetEnabledCurrencies())
if err != nil {
return tickerPrice, err
}
result, err := l.GetTicker(pairsString.String())
if err != nil {
return tickerPrice, err
}
for _, x := range l.GetEnabledCurrencies() {
currency := exchange.FormatExchangeCurrency(l.Name, x).String()
var tp ticker.Price
tp.Pair = x
tp.High = result[currency].High
tp.Last = result[currency].Last
tp.Ask = result[currency].Sell
tp.Bid = result[currency].Buy
tp.Last = result[currency].Last
tp.Low = result[currency].Low
tp.Volume = result[currency].Vol
ticker.ProcessTicker(l.Name, x, tp, assetType)
}
return ticker.GetTicker(l.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (l *Liqui) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
tickerNew, err := ticker.GetTicker(l.Name, p, assetType)
if err != nil {
return l.UpdateTicker(p, assetType)
}
return tickerNew, nil
}
// GetOrderbookEx returns orderbook base on the currency pair
func (l *Liqui) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(l.Name, p, assetType)
if err != nil {
return l.UpdateOrderbook(p, assetType)
}
return ob, nil
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (l *Liqui) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := l.GetDepth(exchange.FormatExchangeCurrency(l.Name, p).String())
if err != nil {
return orderBook, err
}
for x := range orderbookNew.Bids {
data := orderbookNew.Bids[x]
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data[1], Price: data[0]})
}
for x := range orderbookNew.Asks {
data := orderbookNew.Asks[x]
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data[1], Price: data[0]})
}
orderbook.ProcessOrderbook(l.Name, p, orderBook, assetType)
return orderbook.GetOrderbook(l.Name, p, assetType)
}
// GetAccountInfo retrieves balances for all enabled currencies for the
// Liqui exchange
func (l *Liqui) GetAccountInfo() (exchange.AccountInfo, error) {
var response exchange.AccountInfo
response.Exchange = l.GetName()
accountBalance, err := l.GetAccountInformation()
if err != nil {
return response, err
}
var currencies []exchange.AccountCurrencyInfo
for x, y := range accountBalance.Funds {
var exchangeCurrency exchange.AccountCurrencyInfo
exchangeCurrency.CurrencyName = common.StringToUpper(x)
exchangeCurrency.TotalValue = y
exchangeCurrency.Hold = 0
currencies = append(currencies, exchangeCurrency)
}
response.Accounts = append(response.Accounts, exchange.Account{
Currencies: currencies,
})
return response, nil
}
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (l *Liqui) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (l *Liqui) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
}
// SubmitOrder submits a new order
func (l *Liqui) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
response, err := l.Trade(p.Pair().String(), orderType.ToString(), amount, price)
if response > 0 {
submitOrderResponse.OrderID = fmt.Sprintf("%v", response)
}
if err == nil {
submitOrderResponse.IsOrderPlaced = true
}
return submitOrderResponse, err
}
// ModifyOrder will allow of changing orderbook placement and limit to
// market conversion
func (l *Liqui) ModifyOrder(action exchange.ModifyOrder) (string, error) {
return "", common.ErrFunctionNotSupported
}
// CancelOrder cancels an order by its corresponding ID number
func (l *Liqui) CancelOrder(order exchange.OrderCancellation) error {
orderIDInt, err := strconv.ParseInt(order.OrderID, 10, 64)
if err != nil {
return err
}
return l.CancelExistingOrder(orderIDInt)
}
// CancelAllOrders cancels all orders associated with a currency pair
func (l *Liqui) CancelAllOrders(orderCancellation exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) {
cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{
OrderStatus: make(map[string]string),
}
activeOrders, err := l.GetOpenOrders("")
if err != nil {
return cancelAllOrdersResponse, err
}
for activeOrder := range activeOrders {
orderIDInt, err := strconv.ParseInt(activeOrder, 10, 64)
if err != nil {
return cancelAllOrdersResponse, err
}
err = l.CancelExistingOrder(orderIDInt)
if err != nil {
cancelAllOrdersResponse.OrderStatus[activeOrder] = err.Error()
}
}
return cancelAllOrdersResponse, nil
}
// GetOrderInfo returns information on a current open order
func (l *Liqui) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
var orderDetail exchange.OrderDetail
return orderDetail, common.ErrNotYetImplemented
}
// GetDepositAddress returns a deposit address for a specified currency
func (l *Liqui) GetDepositAddress(cryptocurrency pair.CurrencyItem, accountID string) (string, error) {
return "", common.ErrFunctionNotSupported
}
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
// submitted
func (l *Liqui) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) {
resp, err := l.WithdrawCoins(withdrawRequest.Currency.String(), withdrawRequest.Amount, withdrawRequest.Address)
if err != nil {
return "", err
}
return fmt.Sprintf("%v", resp.TID), nil
}
// WithdrawFiatFunds returns a withdrawal ID when a
// withdrawal is submitted
func (l *Liqui) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) {
return "", common.ErrFunctionNotSupported
}
// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a
// withdrawal is submitted
func (l *Liqui) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) {
return "", common.ErrFunctionNotSupported
}
// GetWebsocket returns a pointer to the exchange websocket
func (l *Liqui) GetWebsocket() (*exchange.Websocket, error) {
return nil, common.ErrFunctionNotSupported
}
// GetFeeByType returns an estimate of fee based on type of transaction
func (l *Liqui) GetFeeByType(feeBuilder exchange.FeeBuilder) (float64, error) {
return l.GetFee(feeBuilder)
}
// GetWithdrawCapabilities returns the types of withdrawal methods permitted by the exchange
func (l *Liqui) GetWithdrawCapabilities() uint32 {
return l.GetWithdrawPermissions()
}
// GetActiveOrders retrieves any orders that are active/open
func (l *Liqui) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
if len(getOrdersRequest.Currencies) <= 0 {
return nil, errors.New("Currency must be supplied")
}
var orders []exchange.OrderDetail
for _, currency := range getOrdersRequest.Currencies {
resp, err := l.GetOpenOrders(exchange.FormatExchangeCurrency(l.Name, currency).String())
if err != nil {
return nil, err
}
for ID, order := range resp {
symbol := pair.NewCurrencyPairDelimiter(order.Pair, l.ConfigCurrencyPairFormat.Delimiter)
orderDate := time.Unix(int64(order.TimestampCreated), 0)
side := exchange.OrderSide(strings.ToUpper(order.Type))
orders = append(orders, exchange.OrderDetail{
Amount: order.Amount,
ID: ID,
Price: order.Rate,
OrderSide: side,
OrderDate: orderDate,
Exchange: l.Name,
CurrencyPair: symbol,
})
}
}
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
exchange.FilterOrdersBySide(&orders, getOrdersRequest.OrderSide)
return orders, nil
}
// GetOrderHistory retrieves account order information
// Can Limit response to specific order status
func (l *Liqui) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
return nil, common.ErrFunctionNotSupported
}

View File

@@ -998,48 +998,6 @@
}
]
},
{
"name": "Liqui",
"enabled": true,
"verbose": false,
"websocket": false,
"useSandbox": false,
"restPollingDelay": 10,
"httpTimeout": 15000000000,
"httpUserAgent": "",
"authenticatedApiSupport": false,
"apiKey": "Key",
"apiSecret": "Secret",
"apiUrl": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
"apiUrlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
"proxyAddress": "",
"websocketUrl": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API",
"availablePairs": "BMC_ETH,OAX_BTC,OMG_USDT,DGD_BTC,MANA_USDT,LTC_USDT,TRST_BTC,ETH_USDT,STORJ_BTC,KNC_BTC,STORJ_USDT,GNT_ETH,LTC_ETH,DASH_ETH,AST_BTC,WPR_BTC,PRO_USDT,ANT_USDT,SNGLS_USDT,OAX_ETH,MANA_ETH,IND_USDT,ENG_BTC,DASH_USDT,REP_BTC,BCHABC_ETH,MANA_BTC,WPR_ETH,GNO_ETH,DGD_USDT,BCHABC_BTC,BNT_BTC,HOT_ETH,CLN_USDT,HOT_USDT,GNO_BTC,KNC_ETH,AST_ETH,CLN_BTC,RLC_USDT,GUP_BTC,BNT_ETH,LDC_USDT,GNT_USDT,CVC_USDT,BMC_BTC,WPR_USDT,SALT_BTC,TTU_BTC,ANT_BTC,DGD_ETH,AION_USDT,GUP_USDT,ADX_USDT,AGI_BTC,GNT_BTC,IND_ETH,CLN_ETH,ENG_USDT,PRO_BTC,TRX_BTC,INS_ETH,LDC_ETH,RLC_ETH,SNT_BTC,TNT_ETH,SAN_USDT,PAY_USDT,REP_ETH,SNGLS_ETH,CVC_BTC,IND_BTC,HOT_BTC,LDC_BTC,AION_BTC,SAN_BTC,TNT_BTC,ENG_ETH,WINGS_ETH,SNT_ETH,ENJ_BTC,ENJ_ETH,SALT_USDT,SNT_USDT,WINGS_USDT,ENJ_USDT,SNGLS_BTC,SRN_ETH,BTC_USDT,ADX_ETH,BMC_USDT,TRX_USDT,OMG_BTC,TRST_USDT,TNT_USDT,BNT_USDT,REP_USDT,OMG_ETH,SAN_ETH,ADX_BTC,RLC_BTC,TTU_USDT,ANT_ETH,TRX_ETH,TTU_ETH,INS_USDT,AGI_USDT,GUP_ETH,PAY_ETH,ETH_BTC,KNC_USDT,CVC_ETH,BCHABC_USDT,INS_BTC,TRST_ETH,PAY_BTC,PRO_ETH,LTC_BTC,WINGS_BTC,STORJ_ETH,SALT_ETH,AION_ETH,AST_USDT,GNO_USDT,AGI_ETH,DASH_BTC,OAX_USDT",
"enabledPairs": "ETH_BTC,LTC_BTC,DASH_BTC",
"baseCurrencies": "USD",
"assetTypes": "SPOT",
"supportsAutoPairUpdates": true,
"configCurrencyPairFormat": {
"uppercase": true,
"delimiter": "_"
},
"requestCurrencyPairFormat": {
"uppercase": false,
"delimiter": "_",
"separator": "-"
},
"bankAccounts": [
{
"bankName": "",
"bankAddress": "",
"accountName": "",
"accountNumber": "",
"swiftCode": "",
"iban": "",
"supportedCurrencies": ""
}
]
},
{
"name": "LocalBitcoins",
"enabled": true,

View File

@@ -68,7 +68,6 @@ const (
itbit = "..%s..%sexchanges%sitbit%s"
kraken = "..%s..%sexchanges%skraken%s"
lakebtc = "..%s..%sexchanges%slakebtc%s"
liqui = "..%s..%sexchanges%sliqui%s"
localbitcoins = "..%s..%sexchanges%slocalbitcoins%s"
okcoin = "..%s..%sexchanges%sokcoin%s"
okex = "..%s..%sexchanges%sokex%s"
@@ -243,7 +242,6 @@ func addPaths() {
codebasePaths["exchanges itbit"] = fmt.Sprintf(itbit, path, path, path, path)
codebasePaths["exchanges kraken"] = fmt.Sprintf(kraken, path, path, path, path)
codebasePaths["exchanges lakebtc"] = fmt.Sprintf(lakebtc, path, path, path, path)
codebasePaths["exchanges liqui"] = fmt.Sprintf(liqui, path, path, path, path)
codebasePaths["exchanges localbitcoins"] = fmt.Sprintf(localbitcoins, path, path, path, path)
codebasePaths["exchanges okcoin"] = fmt.Sprintf(okcoin, path, path, path, path)
codebasePaths["exchanges okex"] = fmt.Sprintf(okex, path, path, path, path)

View File

@@ -1,98 +0,0 @@
{{define "exchanges liqui" -}}
{{template "header" .}}
## Liqui Exchange
### Current Features
+ REST Support
### How to enable
+ [Enable via configuration](https://github.com/thrasher-/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
+ Individual package example below:
```go
// Exchanges will be abstracted out in further updates and examples will be
// supplied then
```
### How to do REST public/private calls
+ If enabled via "configuration".json file the exchange will be added to the
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
the wrapper interface functions for accessing exchange data. View routines.go
for an example of integration usage with GoCryptoTrader. Rudimentary example
below:
main.go
```go
var l exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "Liqui" {
l = bot.exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := l.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := l.GetOrderbookEx()
if err != nil {
// Handle error
}
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
// set and AuthenticatedAPISupport is set to true
// Fetches current account information
accountInfo, err := l.GetAccountInfo()
if err != nil {
// Handle error
}
```
+ If enabled via individually importing package, rudimentary example below:
```go
// Public calls
// Fetches current ticker information
ticker, err := l.GetTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := l.GetOrderBook()
if err != nil {
// Handle error
}
// Private calls - make sure your APIKEY and APISECRET are set and
// AuthenticatedAPISupport is set to true
// GetUserInfo returns account info
accountInfo, err := l.GetUserInfo(...)
if err != nil {
// Handle error
}
// Submits an order and the exchange and returns its tradeID
tradeID, err := l.Trade(...)
if err != nil {
// Handle error
}
```
### Please click GoDocs chevron above to view current GoDoc information for this package
{{template "contributions"}}
{{template "donations"}}
{{end}}

View File

@@ -41,7 +41,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
| ItBit | Yes | NA | No |
| Kraken | Yes | NA | NA |
| LakeBTC | Yes | No | NA |
| Liqui | Yes | No | NA |
| LocalBitcoins | Yes | NA | NA |
| OKCoin China | Yes | Yes | No |
| OKCoin International | Yes | Yes | No |