Engine QA (#381)

* 1) Update Dockerfile/docker-compose.yml
2) Remove inline strings for buy/sell/test pairs
3) Remove dangerous order submission values
4) Fix consistency with audit_events (all other spec files use
CamelCase)
5) Update web websocket endpoint
6) Fix main param set (and induce dryrun mode on specific command line
params)

* Engine QA

Link up exchange syncer to cmd params, disarm market selling bombs and fix OKEX endpoints

* Fix linter issue after merge

* Engine QA changes

Template updates
Wrapper code cleanup
Disarmed order bombs
Documentation updates

* Daily engine QA

Bitstamp improvements
Spelling mistakes
Add Coinbene exchange to support list
Protect API authenticated calls for Coinbene/LBank

* Engine QA changes

Fix exchange_wrapper_coverage tool
Add SupportsAsset to exchange interface
Fix inline string usage and add BCH withdrawal support

* Engine QA

Fix Bitstamp types
Inform user of errors when parsing time accross the codebase
Change time parsing warnings to errors (as they are)
Update markdown docs [with linter fixes]

* Engine QA changes

1) Add test for dryrunParamInteraction
2) Disarm OKCoin/OKEX bombs if someone accidently sets canManipulateRealOrders to true and runs all package tests
3) Actually check exchange setup errors for BTSE and Coinbene, plus address this in the wrapper template
4) Hardcode missing/non-retrievable contributors and bump the contributors
5) Convert numbers/strings to meaningful types in Bitstamp and OKEX
6) If WS is supported for the exchange wrapper template, preset authWebsocketSupport var

* Fix the shadow people

* Link the SyncContinuously paramerino

* Also show SyncContinuously in engine.PrintSettings

* Address nitterinos and use correct filepath for logs

* Bitstamp: Extract ALL THE APM

* Fix additional nitterinos

* Fix time parsing error for Bittrex
This commit is contained in:
Adrian Gallagher
2019-11-22 16:07:30 +11:00
committed by GitHub
parent 52e2686b9e
commit 63191ce3ec
102 changed files with 3447 additions and 1714 deletions

View File

@@ -153,15 +153,17 @@ func (a *Alphapoint) UpdateOrderbook(p currency.Pair, assetType asset.Item) (ord
}
for x := range orderbookNew.Bids {
data := orderbookNew.Bids[x]
orderBook.Bids = append(orderBook.Bids,
orderbook.Item{Amount: data.Quantity, Price: data.Price})
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
Amount: orderbookNew.Bids[x].Quantity,
Price: orderbookNew.Bids[x].Price,
})
}
for x := range orderbookNew.Asks {
data := orderbookNew.Asks[x]
orderBook.Asks = append(orderBook.Asks,
orderbook.Item{Amount: data.Quantity, Price: data.Price})
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
Amount: orderbookNew.Asks[x].Quantity,
Price: orderbookNew.Asks[x].Price,
})
}
orderBook.Pair = p
@@ -188,9 +190,8 @@ func (a *Alphapoint) FetchOrderbook(p currency.Pair, assetType asset.Item) (orde
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (a *Alphapoint) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
// https://alphapoint.github.io/slate/#generatetreasuryactivityreport
return fundHistory, common.ErrNotYetImplemented
return nil, common.ErrNotYetImplemented
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -233,7 +233,7 @@ func TestSubmitOrder(t *testing.T) {
Quote: currency.USD,
},
OrderSide: order.Buy,
OrderType: order.Market,
OrderType: order.Limit,
Price: 1,
Amount: 1,
ClientID: "meowOrder",

View File

@@ -310,8 +310,7 @@ func (a *ANX) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (a *ANX) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -87,8 +87,7 @@ func (b *Binance) GetExchangeInfo() (ExchangeInfo, error) {
// symbol: string of currency pair
// limit: returned limit amount
func (b *Binance) GetOrderBook(obd OrderBookDataRequestParams) (OrderBook, error) {
orderbook, resp := OrderBook{}, OrderBookData{}
var orderbook OrderBook
if err := b.CheckLimit(obd.Limit); err != nil {
return orderbook, err
}
@@ -97,42 +96,44 @@ func (b *Binance) GetOrderBook(obd OrderBookDataRequestParams) (OrderBook, error
params.Set("symbol", strings.ToUpper(obd.Symbol))
params.Set("limit", fmt.Sprintf("%d", obd.Limit))
path := fmt.Sprintf("%s%s?%s", b.API.Endpoints.URL, orderBookDepth, params.Encode())
var resp OrderBookData
path := common.EncodeURLValues(b.API.Endpoints.URL+orderBookDepth, params)
if err := b.SendHTTPRequest(path, &resp); err != nil {
return orderbook, err
}
for _, asks := range resp.Asks {
var ASK struct {
Price float64
Quantity float64
for x := range resp.Bids {
price, err := strconv.ParseFloat(resp.Bids[x][0], 64)
if err != nil {
return orderbook, err
}
for i, ask := range asks.([]interface{}) {
switch i {
case 0:
ASK.Price, _ = strconv.ParseFloat(ask.(string), 64)
case 1:
ASK.Quantity, _ = strconv.ParseFloat(ask.(string), 64)
orderbook.Asks = append(orderbook.Asks, ASK)
}
amount, err := strconv.ParseFloat(resp.Bids[x][1], 64)
if err != nil {
return orderbook, err
}
orderbook.Bids = append(orderbook.Bids, OrderbookItem{
Price: price,
Quantity: amount,
})
}
for _, bids := range resp.Bids {
var BID struct {
Price float64
Quantity float64
for x := range resp.Asks {
price, err := strconv.ParseFloat(resp.Asks[x][0], 64)
if err != nil {
return orderbook, err
}
for i, bid := range bids.([]interface{}) {
switch i {
case 0:
BID.Price, _ = strconv.ParseFloat(bid.(string), 64)
case 1:
BID.Quantity, _ = strconv.ParseFloat(bid.(string), 64)
orderbook.Bids = append(orderbook.Bids, BID)
}
amount, err := strconv.ParseFloat(resp.Asks[x][1], 64)
if err != nil {
return orderbook, err
}
orderbook.Asks = append(orderbook.Asks, OrderbookItem{
Price: price,
Quantity: amount,
})
}
orderbook.LastUpdateID = resp.LastUpdateID

View File

@@ -359,7 +359,7 @@ func TestSubmitOrder(t *testing.T) {
Quote: currency.BTC,
},
OrderSide: order.Buy,
OrderType: order.Market,
OrderType: order.Limit,
Price: 1,
Amount: 1000000000,
ClientID: "meowOrder",

View File

@@ -59,13 +59,19 @@ type OrderBookDataRequestParams struct {
Limit int `json:"limit"` // Default 100; max 1000. Valid limits:[5, 10, 20, 50, 100, 500, 1000]
}
// OrderbookItem stores an individual orderbook item
type OrderbookItem struct {
Price float64
Quantity float64
}
// OrderBookData is resp data from orderbook endpoint
type OrderBookData struct {
Code int `json:"code"`
Msg string `json:"msg"`
LastUpdateID int64 `json:"lastUpdateId"`
Bids []interface{} `json:"bids"`
Asks []interface{} `json:"asks"`
Code int `json:"code"`
Msg string `json:"msg"`
LastUpdateID int64 `json:"lastUpdateId"`
Bids [][]string `json:"bids"`
Asks [][]string `json:"asks"`
}
// OrderBook actual structured data that can be used for orderbook
@@ -73,14 +79,8 @@ type OrderBook struct {
LastUpdateID int64
Code int
Msg string
Bids []struct {
Price float64
Quantity float64
}
Asks []struct {
Price float64
Quantity float64
}
Bids []OrderbookItem
Asks []OrderbookItem
}
// DepthUpdateParams is used as an embedded type for WebsocketDepthStream

View File

@@ -383,8 +383,7 @@ func (b *Binance) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (b *Binance) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -14,6 +14,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wsorderbook"
@@ -433,10 +434,10 @@ func (b *Bitfinex) WsDataHandler() {
}
if len(trades) > 0 {
side := "BUY"
side := order.Buy
newAmount := trades[0].Amount
if newAmount < 0 {
side = "SELL"
side = order.Sell
newAmount *= -1
}
@@ -447,7 +448,7 @@ func (b *Bitfinex) WsDataHandler() {
Amount: newAmount,
Exchange: b.Name,
AssetType: asset.Spot,
Side: side,
Side: side.String(),
}
}
}

View File

@@ -349,8 +349,7 @@ func (b *Bitfinex) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (b *Bitfinex) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -15,6 +15,7 @@ const (
apiKey = ""
apiSecret = ""
canManipulateRealOrders = false
testCurrency = "btc"
)
var b Bithumb
@@ -54,7 +55,7 @@ func TestGetTradablePairs(t *testing.T) {
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := b.GetTicker("btc")
_, err := b.GetTicker(testCurrency)
if err != nil {
t.Error("Bithumb GetTicker() error", err)
}
@@ -70,7 +71,7 @@ func TestGetAllTickers(t *testing.T) {
func TestGetOrderBook(t *testing.T) {
t.Parallel()
_, err := b.GetOrderBook("btc")
_, err := b.GetOrderBook(testCurrency)
if err != nil {
t.Error("Bithumb GetOrderBook() error", err)
}
@@ -78,7 +79,7 @@ func TestGetOrderBook(t *testing.T) {
func TestGetTransactionHistory(t *testing.T) {
t.Parallel()
_, err := b.GetTransactionHistory("btc")
_, err := b.GetTransactionHistory(testCurrency)
if err != nil {
t.Error("Bithumb GetTransactionHistory() error", err)
}
@@ -90,7 +91,7 @@ func TestGetAccountBalance(t *testing.T) {
t.Skip()
}
_, err := b.GetAccountBalance("BTC")
_, err := b.GetAccountBalance(testCurrency)
if err == nil {
t.Error("Bithumb GetAccountBalance() Expected error")
}
@@ -118,7 +119,7 @@ func TestGetLastTransaction(t *testing.T) {
func TestGetOrders(t *testing.T) {
t.Parallel()
_, err := b.GetOrders("1337", "bid", "100", "", "BTC")
_, err := b.GetOrders("1337", order.Bid.Lower(), "100", "", testCurrency)
if err == nil {
t.Error("Bithumb GetOrders() Expected error")
}
@@ -134,7 +135,7 @@ func TestGetUserTransactions(t *testing.T) {
func TestPlaceTrade(t *testing.T) {
t.Parallel()
_, err := b.PlaceTrade("btc", "bid", 0, 0)
_, err := b.PlaceTrade(testCurrency, order.Bid.Lower(), 0, 0)
if err == nil {
t.Error("Bithumb PlaceTrade() Expected error")
}
@@ -142,7 +143,7 @@ func TestPlaceTrade(t *testing.T) {
func TestGetOrderDetails(t *testing.T) {
t.Parallel()
_, err := b.GetOrderDetails("1337", "bid", "btc")
_, err := b.GetOrderDetails("1337", order.Bid.Lower(), testCurrency)
if err == nil {
t.Error("Bithumb GetOrderDetails() Expected error")
}
@@ -185,7 +186,7 @@ func TestRequestKRWWithdraw(t *testing.T) {
func TestMarketBuyOrder(t *testing.T) {
t.Parallel()
_, err := b.MarketBuyOrder("btc", 0)
_, err := b.MarketBuyOrder(testCurrency, 0)
if err == nil {
t.Error("Bithumb MarketBuyOrder() Expected error")
}
@@ -193,7 +194,7 @@ func TestMarketBuyOrder(t *testing.T) {
func TestMarketSellOrder(t *testing.T) {
t.Parallel()
_, err := b.MarketSellOrder("btc", 0)
_, err := b.MarketSellOrder(testCurrency, 0)
if err == nil {
t.Error("Bithumb MarketSellOrder() Expected error")
}

View File

@@ -291,8 +291,7 @@ func (b *Bithumb) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (b *Bithumb) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -347,29 +347,21 @@ func (b *Bitmex) processOrderbook(data []OrderBookL2, action string, currencyPai
switch action {
case bitmexActionInitialData:
var newOrderBook orderbook.Base
var bids, asks []orderbook.Item
for i := range data {
if strings.EqualFold(data[i].Side, order.Sell.String()) {
asks = append(asks, orderbook.Item{
newOrderBook.Asks = append(newOrderBook.Asks, orderbook.Item{
Price: data[i].Price,
Amount: float64(data[i].Size),
ID: data[i].ID,
})
continue
}
bids = append(bids, orderbook.Item{
newOrderBook.Bids = append(newOrderBook.Bids, orderbook.Item{
Price: data[i].Price,
Amount: float64(data[i].Size),
ID: data[i].ID,
})
}
if len(bids) == 0 || len(asks) == 0 {
return errors.New("bitmex_websocket.go error - snapshot not initialised correctly")
}
newOrderBook.Asks = asks
newOrderBook.Bids = bids
newOrderBook.AssetType = assetType
newOrderBook.Pair = currencyPair
newOrderBook.ExchangeName = b.Name

View File

@@ -7,9 +7,9 @@ import (
"fmt"
"net/http"
"net/url"
"reflect"
"strconv"
"strings"
"time"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
@@ -40,6 +40,7 @@ const (
bitstampAPIBitcoinWithdrawal = "bitcoin_withdrawal"
bitstampAPILTCWithdrawal = "ltc_withdrawal"
bitstampAPIETHWithdrawal = "eth_withdrawal"
bitstampAPIBCHWithdrawal = "bch_withdrawal"
bitstampAPIBitcoinDeposit = "bitcoin_deposit_address"
bitstampAPILitecoinDeposit = "ltc_address"
bitstampAPIEthereumDeposit = "eth_address"
@@ -54,6 +55,7 @@ const (
bitstampAuthRate = 8000
bitstampUnauthRate = 8000
bitstampTimeLayout = "2006-1-2 15:04:05"
)
// Bitstamp is the overarching type across the bitstamp package
@@ -121,22 +123,17 @@ func getInternationalBankDepositFee(amount float64) float64 {
}
// CalculateTradingFee returns fee on a currency pair
func (b *Bitstamp) CalculateTradingFee(base, quote currency.Code, purchasePrice, amount float64, balances *Balances) float64 {
func (b *Bitstamp) CalculateTradingFee(base, quote currency.Code, purchasePrice, amount float64, balances Balances) float64 {
var fee float64
switch base.String() + quote.String() {
case currency.BTC.String() + currency.USD.String():
fee = balances.BTCUSDFee
case currency.BTC.String() + currency.EUR.String():
fee = balances.BTCEURFee
case currency.XRP.String() + currency.EUR.String():
fee = balances.XRPEURFee
case currency.XRP.String() + currency.USD.String():
fee = balances.XRPUSDFee
case currency.EUR.String() + currency.USD.String():
fee = balances.EURUSDFee
default:
fee = 0
if v, ok := balances[base.String()]; ok {
switch quote {
case currency.BTC:
fee = v.BTCFee
case currency.USD:
fee = v.USDFee
case currency.EUR:
fee = v.EURFee
}
}
return fee * purchasePrice * amount
}
@@ -259,25 +256,62 @@ func (b *Bitstamp) GetEURUSDConversionRate() (EURUSDConversionRate, error) {
}
// GetBalance returns full balance of currency held on the exchange
func (b *Bitstamp) GetBalance() (*Balances, error) {
var balance Balances
return &balance,
b.SendAuthenticatedHTTPRequest(bitstampAPIBalance, true, nil, &balance)
func (b *Bitstamp) GetBalance() (Balances, error) {
var balance map[string]string
err := b.SendAuthenticatedHTTPRequest(bitstampAPIBalance, true, nil, &balance)
if err != nil {
return nil, err
}
balances := make(map[string]Balance)
for k := range balance {
curr := k[0:3]
_, ok := balances[strings.ToUpper(curr)]
if !ok {
avail, _ := strconv.ParseFloat(balance[curr+"_available"], 64)
bal, _ := strconv.ParseFloat(balance[curr+"_balance"], 64)
reserved, _ := strconv.ParseFloat(balance[curr+"_reserved"], 64)
withdrawalFee, _ := strconv.ParseFloat(balance[curr+"_withdrawal_fee"], 64)
currBalance := Balance{
Available: avail,
Balance: bal,
Reserved: reserved,
WithdrawalFee: withdrawalFee,
}
switch strings.ToUpper(curr) {
case currency.USD.String():
eurFee, _ := strconv.ParseFloat(balance[curr+"eur_fee"], 64)
currBalance.EURFee = eurFee
case currency.EUR.String():
usdFee, _ := strconv.ParseFloat(balance[curr+"usd_fee"], 64)
currBalance.USDFee = usdFee
default:
btcFee, _ := strconv.ParseFloat(balance[curr+"btc_fee"], 64)
currBalance.BTCFee = btcFee
eurFee, _ := strconv.ParseFloat(balance[curr+"eur_fee"], 64)
currBalance.EURFee = eurFee
usdFee, _ := strconv.ParseFloat(balance[curr+"usd_fee"], 64)
currBalance.USDFee = usdFee
}
balances[strings.ToUpper(curr)] = currBalance
}
}
return balances, nil
}
// GetUserTransactions returns an array of transactions
func (b *Bitstamp) GetUserTransactions(currencyPair string) ([]UserTransactions, error) {
type Response struct {
Date string `json:"datetime"`
TransID int64 `json:"id"`
Type int `json:"type,string"`
USD interface{} `json:"usd"`
EUR float64 `json:"eur"`
XRP float64 `json:"xrp"`
BTC interface{} `json:"btc"`
BTCUSD interface{} `json:"btc_usd"`
Fee float64 `json:"fee,string"`
OrderID int64 `json:"order_id"`
Date string `json:"datetime"`
TransactionID int64 `json:"id"`
Type int `json:"type,string"`
USD interface{} `json:"usd"`
EUR interface{} `json:"eur"`
XRP interface{} `json:"xrp"`
BTC interface{} `json:"btc"`
BTCUSD interface{} `json:"btc_usd"`
Fee float64 `json:"fee,string"`
OrderID int64 `json:"order_id"`
}
var response []Response
@@ -297,41 +331,31 @@ func (b *Bitstamp) GetUserTransactions(currencyPair string) ([]UserTransactions,
}
}
processNumber := func(i interface{}) float64 {
switch t := i.(type) {
case float64:
return t
case string:
amt, _ := strconv.ParseFloat(t, 64)
return amt
default:
return 0
}
}
var transactions []UserTransactions
for _, y := range response {
for x := range response {
tx := UserTransactions{}
tx.Date = y.Date
tx.TransID = y.TransID
tx.Type = y.Type
/* Hack due to inconsistent JSON values... */
varType := reflect.TypeOf(y.USD).String()
if varType == bitstampAPIReturnType {
tx.USD, _ = strconv.ParseFloat(y.USD.(string), 64)
} else {
tx.USD = y.USD.(float64)
}
tx.EUR = y.EUR
tx.XRP = y.XRP
varType = reflect.TypeOf(y.BTC).String()
if varType == bitstampAPIReturnType {
tx.BTC, _ = strconv.ParseFloat(y.BTC.(string), 64)
} else {
tx.BTC = y.BTC.(float64)
}
varType = reflect.TypeOf(y.BTCUSD).String()
if varType == bitstampAPIReturnType {
tx.BTCUSD, _ = strconv.ParseFloat(y.BTCUSD.(string), 64)
} else {
tx.BTCUSD = y.BTCUSD.(float64)
}
tx.Fee = y.Fee
tx.OrderID = y.OrderID
tx.Date = response[x].Date
tx.TransactionID = response[x].TransactionID
tx.Type = response[x].Type
tx.EUR = processNumber(response[x].EUR)
tx.XRP = processNumber(response[x].XRP)
tx.USD = processNumber(response[x].USD)
tx.BTC = processNumber(response[x].BTC)
tx.BTCUSD = processNumber(response[x].BTCUSD)
tx.Fee = response[x].Fee
tx.OrderID = response[x].OrderID
transactions = append(transactions, tx)
}
@@ -359,13 +383,17 @@ func (b *Bitstamp) GetOrderStatus(orderID int64) (OrderStatus, error) {
}
// CancelExistingOrder cancels order by ID
func (b *Bitstamp) CancelExistingOrder(orderID int64) (bool, error) {
result := false
func (b *Bitstamp) CancelExistingOrder(orderID int64) (CancelOrder, error) {
var req = url.Values{}
req.Add("id", strconv.FormatInt(orderID, 10))
return result,
b.SendAuthenticatedHTTPRequest(bitstampAPICancelOrder, true, req, &result)
var result CancelOrder
err := b.SendAuthenticatedHTTPRequest(bitstampAPICancelOrder, true, req, &result)
if err != nil {
return result, err
}
return result, nil
}
// CancelAllExistingOrders cancels all open orders on the exchange
@@ -433,22 +461,24 @@ func (b *Bitstamp) CryptoWithdrawal(amount float64, address, symbol, destTag str
var endpoint string
switch strings.ToLower(symbol) {
case "btc":
case currency.BTC.Lower().String():
if instant {
req.Add("instant", "1")
} else {
req.Add("instant", "0")
}
endpoint = bitstampAPIBitcoinWithdrawal
case "ltc":
case currency.LTC.Lower().String():
endpoint = bitstampAPILTCWithdrawal
case "eth":
case currency.ETH.Lower().String():
endpoint = bitstampAPIETHWithdrawal
case "xrp":
case currency.XRP.Lower().String():
if destTag != "" {
req.Add("destination_tag", destTag)
}
endpoint = bitstampAPIXrpWithdrawal
case currency.BCH.Lower().String():
endpoint = bitstampAPIBCHWithdrawal
default:
return resp, errors.New("incorrect symbol")
}
@@ -669,3 +699,7 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url
return common.JSONDecode(interim, result)
}
func parseTime(dateTime string) (time.Time, error) {
return time.Parse(bitstampTimeLayout, dateTime)
}

View File

@@ -143,9 +143,11 @@ func TestGetFee(t *testing.T) {
func TestCalculateTradingFee(t *testing.T) {
t.Parallel()
var newBalance = new(Balances)
newBalance.BTCUSDFee = 1
newBalance.BTCEURFee = 0
newBalance := make(Balances)
newBalance["BTC"] = Balance{
USDFee: 1,
EURFee: 0,
}
if resp := b.CalculateTradingFee(currency.BTC, currency.USD, 0, 0, newBalance); resp != 0 {
t.Error("GetFee() error")
@@ -401,15 +403,9 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = &order.Cancel{
OrderID: "1",
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
AccountID: "1",
CurrencyPair: currencyPair,
orderCancellation := &order.Cancel{
OrderID: "1234",
}
err := b.CancelOrder(orderCancellation)
switch {
case !areTestAPIKeysSet() && err == nil && !mockTests:
@@ -428,16 +424,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = &order.Cancel{
OrderID: "1",
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
AccountID: "1",
CurrencyPair: currencyPair,
}
resp, err := b.CancelAllOrders(orderCancellation)
resp, err := b.CancelAllOrders(&order.Cancel{})
switch {
case !areTestAPIKeysSet() && err == nil && !mockTests:
t.Error("Expecting an error when no keys are set")
@@ -583,3 +570,21 @@ func TestGetDepositAddress(t *testing.T) {
t.Error("GetDepositAddress error", err)
}
}
func TestParseTime(t *testing.T) {
t.Parallel()
tm, err := parseTime("2019-10-18 01:55:14")
if err != nil {
t.Error(err)
}
if tm.Year() != 2019 ||
tm.Month() != 10 ||
tm.Day() != 18 ||
tm.Hour() != 1 ||
tm.Minute() != 55 ||
tm.Second() != 14 {
t.Error("invalid time values")
}
}

View File

@@ -1,5 +1,19 @@
package bitstamp
// Transaction types
const (
Deposit = iota
Withdrawal
MarketTrade
SubAccountTransfer = 14
)
// Order side type
const (
BuyOrder = iota
SellOrder
)
// Ticker holds ticker information
type Ticker struct {
Last float64 `json:"last,string"`
@@ -52,55 +66,51 @@ type EURUSDConversionRate struct {
Sell float64 `json:"sell,string"`
}
// Balances holds full balance information with the supplied APIKEYS
type Balances struct {
USDBalance float64 `json:"usd_balance,string"`
BTCBalance float64 `json:"btc_balance,string"`
EURBalance float64 `json:"eur_balance,string"`
XRPBalance float64 `json:"xrp_balance,string"`
USDReserved float64 `json:"usd_reserved,string"`
BTCReserved float64 `json:"btc_reserved,string"`
EURReserved float64 `json:"eur_reserved,string"`
XRPReserved float64 `json:"xrp_reserved,string"`
USDAvailable float64 `json:"usd_available,string"`
BTCAvailable float64 `json:"btc_available,string"`
EURAvailable float64 `json:"eur_available,string"`
XRPAvailable float64 `json:"xrp_available,string"`
BTCUSDFee float64 `json:"btcusd_fee,string"`
BTCEURFee float64 `json:"btceur_fee,string"`
EURUSDFee float64 `json:"eurusd_fee,string"`
XRPUSDFee float64 `json:"xrpusd_fee,string"`
XRPEURFee float64 `json:"xrpeur_fee,string"`
XRPBTCFee float64 `json:"xrpbtc_fee,string"`
Fee float64 `json:"fee,string"`
// Balance stores the balance info
type Balance struct {
Available float64
Balance float64
Reserved float64
WithdrawalFee float64
BTCFee float64 // for cryptocurrency pairs
USDFee float64
EURFee float64
}
// Balances holds full balance information with the supplied APIKEYS
type Balances map[string]Balance
// UserTransactions holds user transaction information
type UserTransactions struct {
Date string `json:"datetime"`
TransID int64 `json:"id"`
Type int `json:"type,string"`
USD float64 `json:"usd"`
EUR float64 `json:"eur"`
BTC float64 `json:"btc"`
XRP float64 `json:"xrp"`
BTCUSD float64 `json:"btc_usd"`
Fee float64 `json:"fee,string"`
OrderID int64 `json:"order_id"`
Date string `json:"datetime"`
TransactionID int64 `json:"id"`
Type int `json:"type,string"`
USD float64 `json:"usd"`
EUR float64 `json:"eur"`
BTC float64 `json:"btc"`
XRP float64 `json:"xrp"`
BTCUSD float64 `json:"btc_usd"`
Fee float64 `json:"fee,string"`
OrderID int64 `json:"order_id"`
}
// Order holds current open order data
type Order struct {
ID int64 `json:"id"`
Date int64 `json:"datetime"`
Type int `json:"type"`
Price float64 `json:"price"`
Amount float64 `json:"amount"`
ID int64 `json:"id,string"`
DateTime string `json:"datetime"`
Type int `json:"type,string"`
Price float64 `json:"price,string"`
Amount float64 `json:"amount,string"`
Currency string `json:"currency_pair"`
}
// OrderStatus holds order status information
type OrderStatus struct {
Price float64 `json:"price,string"`
Amount float64 `json:"amount,string"`
Type int `json:"type"`
ID int64 `json:"id,string"`
DateTime string `json:"datetime"`
Status string
Transactions []struct {
TradeID int64 `json:"tid"`
@@ -111,6 +121,14 @@ type OrderStatus struct {
}
}
// CancelOrder holds the order cancellation info
type CancelOrder struct {
Price float64 `json:"price"`
Amount float64 `json:"amount"`
Type int `json:"type"`
ID int64 `json:"id"`
}
// WithdrawalRequests holds request information on withdrawals
type WithdrawalRequests struct {
OrderID int64 `json:"id"`

View File

@@ -225,24 +225,18 @@ func (b *Bitstamp) seedOrderBook() error {
}
var newOrderBook orderbook.Base
var asks, bids []orderbook.Item
for i := range orderbookSeed.Asks {
var item orderbook.Item
item.Amount = orderbookSeed.Asks[i].Amount
item.Price = orderbookSeed.Asks[i].Price
asks = append(asks, item)
newOrderBook.Asks = append(newOrderBook.Asks, orderbook.Item{
Price: orderbookSeed.Asks[i].Price,
Amount: orderbookSeed.Asks[i].Amount,
})
}
for i := range orderbookSeed.Bids {
var item orderbook.Item
item.Amount = orderbookSeed.Bids[i].Amount
item.Price = orderbookSeed.Bids[i].Price
bids = append(bids, item)
newOrderBook.Bids = append(newOrderBook.Bids, orderbook.Item{
Price: orderbookSeed.Bids[i].Price,
Amount: orderbookSeed.Bids[i].Amount,
})
}
newOrderBook.Asks = asks
newOrderBook.Bids = bids
newOrderBook.Pair = p[x]
newOrderBook.AssetType = asset.Spot
newOrderBook.ExchangeName = b.Name

View File

@@ -289,13 +289,17 @@ func (b *Bitstamp) UpdateOrderbook(p currency.Pair, assetType asset.Item) (order
}
for x := range orderbookNew.Bids {
data := orderbookNew.Bids[x]
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data.Amount, Price: data.Price})
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
Amount: orderbookNew.Bids[x].Amount,
Price: orderbookNew.Bids[x].Price,
})
}
for x := range orderbookNew.Asks {
data := orderbookNew.Asks[x]
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data.Amount, Price: data.Price})
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
Amount: orderbookNew.Asks[x].Amount,
Price: orderbookNew.Asks[x].Price,
})
}
orderBook.Pair = p
@@ -320,27 +324,13 @@ func (b *Bitstamp) GetAccountInfo() (exchange.AccountInfo, error) {
return response, err
}
var currencies = []exchange.AccountCurrencyInfo{
{
CurrencyName: currency.BTC,
TotalValue: accountBalance.BTCAvailable,
Hold: accountBalance.BTCReserved,
},
{
CurrencyName: currency.XRP,
TotalValue: accountBalance.XRPAvailable,
Hold: accountBalance.XRPReserved,
},
{
CurrencyName: currency.USD,
TotalValue: accountBalance.USDAvailable,
Hold: accountBalance.USDReserved,
},
{
CurrencyName: currency.EUR,
TotalValue: accountBalance.EURAvailable,
Hold: accountBalance.EURReserved,
},
var currencies []exchange.AccountCurrencyInfo
for k, v := range accountBalance {
currencies = append(currencies, exchange.AccountCurrencyInfo{
CurrencyName: currency.NewCode(k),
TotalValue: v.Available,
Hold: v.Reserved,
})
}
response.Accounts = append(response.Accounts, exchange.Account{
Currencies: currencies,
@@ -352,8 +342,7 @@ func (b *Bitstamp) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (b *Bitstamp) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.
@@ -518,7 +507,6 @@ func (b *Bitstamp) GetWebsocket() (*wshandler.Websocket, error) {
// GetActiveOrders retrieves any orders that are active/open
func (b *Bitstamp) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail, error) {
var orders []order.Detail
var currPair string
if len(req.Currencies) != 1 {
currPair = "all"
@@ -531,16 +519,28 @@ func (b *Bitstamp) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail,
return nil, err
}
var orders []order.Detail
for i := range resp {
orderDate := time.Unix(resp[i].Date, 0)
orderSide := order.Buy
if resp[i].Type == SellOrder {
orderSide = order.Sell
}
tm, err := parseTime(resp[i].DateTime)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s GetActiveOrders unable to parse time: %s\n", b.Name, err)
}
orders = append(orders, order.Detail{
Amount: resp[i].Amount,
ID: strconv.FormatInt(resp[i].ID, 10),
Price: resp[i].Price,
OrderDate: orderDate,
CurrencyPair: currency.NewPairFromStrings(resp[i].Currency[0:3],
resp[i].Currency[len(resp[i].Currency)-3:]),
Exchange: b.Name,
Amount: resp[i].Amount,
ID: strconv.FormatInt(resp[i].ID, 10),
Price: resp[i].Price,
OrderType: order.Limit,
OrderSide: orderSide,
OrderDate: tm,
CurrencyPair: currency.NewPairFromString(resp[i].Currency),
Exchange: b.Name,
})
}
@@ -563,7 +563,7 @@ func (b *Bitstamp) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail,
var orders []order.Detail
for i := range resp {
if resp[i].Type != 2 {
if resp[i].Type != MarketTrade {
continue
}
var quoteCurrency, baseCurrency currency.Code
@@ -575,7 +575,8 @@ func (b *Bitstamp) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail,
baseCurrency = currency.XRP
default:
log.Warnf(log.ExchangeSys,
"no base currency found for OrderID '%d'",
"%s No base currency found for OrderID '%d'\n",
b.Name,
resp[i].OrderID)
}
@@ -586,7 +587,8 @@ func (b *Bitstamp) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail,
quoteCurrency = currency.EUR
default:
log.Warnf(log.ExchangeSys,
"no quote currency found for orderID '%d'",
"%s No quote currency found for orderID '%d'\n",
b.Name,
resp[i].OrderID)
}
@@ -597,14 +599,15 @@ func (b *Bitstamp) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail,
b.GetPairFormat(asset.Spot, false).Delimiter)
}
orderDate, err := time.Parse("2006-01-02 15:04:05", resp[i].Date)
tm, err := parseTime(resp[i].Date)
if err != nil {
return nil, err
log.Errorf(log.ExchangeSys,
"%s GetOrderHistory unable to parse time: %s\n", b.Name, err)
}
orders = append(orders, order.Detail{
ID: strconv.FormatInt(resp[i].OrderID, 10),
OrderDate: orderDate,
OrderDate: tm,
Exchange: b.Name,
CurrencyPair: currPair,
})

View File

@@ -7,6 +7,7 @@ import (
"net/url"
"strconv"
"strings"
"time"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/currency"
@@ -53,6 +54,7 @@ const (
bittrexAuthRate = 0
bittrexUnauthRate = 0
bittrexTimeLayout = "2006-01-02T15:04:05"
)
// Bittrex is the overaching type across the bittrex methods
@@ -508,3 +510,7 @@ func (b *Bittrex) GetWithdrawalFee(c currency.Code) (float64, error) {
func calculateTradingFee(price, amount float64) float64 {
return 0.0025 * price * amount
}
func parseTime(t string) (time.Time, error) {
return time.Parse(bittrexTimeLayout, t)
}

View File

@@ -534,3 +534,21 @@ func TestGetDepositAddress(t *testing.T) {
}
}
}
func TestParseTime(t *testing.T) {
t.Parallel()
tm, err := parseTime("2019-11-21T02:08:34.87")
if err != nil {
t.Fatal(err)
}
if tm.Year() != 2019 ||
tm.Month() != 11 ||
tm.Day() != 21 ||
tm.Hour() != 2 ||
tm.Minute() != 8 ||
tm.Second() != 34 {
t.Error("invalid time values")
}
}

View File

@@ -227,7 +227,11 @@ func (b *Bittrex) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Pr
if !strings.EqualFold(ticks.Result[j].MarketName, pairs[i].String()) {
continue
}
tickerTime, _ := time.Parse(time.RFC3339, ticks.Result[j].TimeStamp)
tickerTime, err := parseTime(ticks.Result[j].TimeStamp)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s UpdateTicker unable to parse time: %s\n", b.Name, err)
}
tickerPrice = ticker.Price{
Last: ticks.Result[j].Last,
High: ticks.Result[j].High,
@@ -309,8 +313,7 @@ func (b *Bittrex) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderb
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (b *Bittrex) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.
@@ -451,9 +454,9 @@ func (b *Bittrex) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail,
var orders []order.Detail
for i := range resp.Result {
orderDate, err := time.Parse(time.RFC3339, resp.Result[i].Opened)
orderDate, err := parseTime(resp.Result[i].Opened)
if err != nil {
log.Warnf(log.ExchangeSys,
log.Errorf(log.ExchangeSys,
"Exchange %v Func %v Order %v Could not parse date to unix with value of %v",
b.Name,
"GetActiveOrders",
@@ -498,9 +501,9 @@ func (b *Bittrex) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail,
var orders []order.Detail
for i := range resp.Result {
orderDate, err := time.Parse(time.RFC3339, resp.Result[i].TimeStamp)
orderDate, err := parseTime(resp.Result[i].TimeStamp)
if err != nil {
log.Warnf(log.ExchangeSys,
log.Errorf(log.ExchangeSys,
"Exchange %v Func %v Order %v Could not parse date to unix with value of %v",
b.Name,
"GetActiveOrders",

View File

@@ -193,6 +193,7 @@ type WsOrderbook struct {
MessageType string `json:"messageType"`
}
// WsError message received for orderbook errors
type WsError struct {
MessageType string `json:"messageType"`
Code int64 `json:"code"`

View File

@@ -279,13 +279,17 @@ func (b *BTCMarkets) UpdateOrderbook(p currency.Pair, assetType asset.Item) (ord
}
for x := range orderbookNew.Bids {
data := orderbookNew.Bids[x]
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data[1], Price: data[0]})
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
Amount: orderbookNew.Bids[x][1],
Price: orderbookNew.Bids[x][0],
})
}
for x := range orderbookNew.Asks {
data := orderbookNew.Asks[x]
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data[1], Price: data[0]})
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
Amount: orderbookNew.Asks[x][1],
Price: orderbookNew.Asks[x][0],
})
}
orderBook.Pair = p
@@ -331,8 +335,7 @@ func (b *BTCMarkets) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (b *BTCMarkets) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -42,6 +42,7 @@ const (
btsePendingOrders = "pending"
btseDeleteOrder = "deleteOrder"
btseFills = "fills"
btseTimeLayout = "2006-01-02 15:04:04"
)
// GetMarketsSummary stores market summary data
@@ -238,7 +239,7 @@ func (b *BTSE) SendAuthenticatedHTTPRequest(method, endpoint string, req map[str
b.Name, method, path, string(payload))
}
return b.SendPayload(method,
btseAPIURL+path,
b.API.Endpoints.URL+path,
headers,
body,
&result,
@@ -320,7 +321,6 @@ func calculateTradingFee(isMaker bool) float64 {
return fee
}
func parseOrderTime(timeStr string) time.Time {
t, _ := time.Parse("2006-01-02 15:04:04", timeStr)
return t
func parseOrderTime(timeStr string) (time.Time, error) {
return time.Parse(btseTimeLayout, timeStr)
}

View File

@@ -17,6 +17,7 @@ const (
apiKey = ""
apiSecret = ""
canManipulateRealOrders = false
testPair = "BTC-USD"
)
var b BTSE
@@ -37,7 +38,11 @@ func TestMain(m *testing.M) {
btseConfig.API.Credentials.Key = apiKey
btseConfig.API.Credentials.Secret = apiSecret
b.Setup(btseConfig)
err = b.Setup(btseConfig)
if err != nil {
log.Fatal(err)
}
os.Exit(m.Run())
}
@@ -63,7 +68,7 @@ func TestGetMarkets(t *testing.T) {
func TestFetchOrderBook(t *testing.T) {
t.Parallel()
_, err := b.FetchOrderBook("BTC-USD")
_, err := b.FetchOrderBook(testPair)
if err != nil {
t.Error(err)
}
@@ -71,7 +76,7 @@ func TestFetchOrderBook(t *testing.T) {
func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := b.GetTrades("BTC-USD")
_, err := b.GetTrades(testPair)
if err != nil {
t.Error(err)
}
@@ -79,7 +84,7 @@ func TestGetTrades(t *testing.T) {
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := b.GetTicker("BTC-USD")
_, err := b.GetTicker(testPair)
if err != nil {
t.Error(err)
}
@@ -87,7 +92,7 @@ func TestGetTicker(t *testing.T) {
func TestGetMarketStatistics(t *testing.T) {
t.Parallel()
_, err := b.GetMarketStatistics("BTC-USD")
_, err := b.GetMarketStatistics(testPair)
if err != nil {
t.Error(err)
}
@@ -117,7 +122,7 @@ func TestGetFills(t *testing.T) {
if !areTestAPIKeysSet() {
t.Skip("API keys not set, skipping test")
}
_, err := b.GetFills("", "BTC-USD", "", "", "", "")
_, err := b.GetFills("", testPair, "", "", "", "")
if err != nil {
t.Error(err)
}
@@ -128,7 +133,13 @@ func TestCreateOrder(t *testing.T) {
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := b.CreateOrder(0.1, 10000, "sell", "limit", "BTC-USD", "", "")
_, err := b.CreateOrder(0.1,
10000,
order.Sell.String(),
order.Limit.String(),
testPair,
"",
"")
if err != nil {
t.Error(err)
}
@@ -266,9 +277,12 @@ func TestGetFee(t *testing.T) {
func TestParseOrderTime(t *testing.T) {
expected := int64(1534794360)
actual := parseOrderTime("2018-08-20 19:20:46").Unix()
if expected != actual {
t.Errorf("TestParseOrderTime expected: %d, got %d", expected, actual)
actual, err := parseOrderTime("2018-08-20 19:20:46")
if err != nil {
t.Fatal(err)
}
if expected != actual.Unix() {
t.Errorf("TestParseOrderTime expected: %d, got %d", expected, actual.Unix())
}
}

View File

@@ -103,8 +103,8 @@ func (b *BTSE) WsHandleData() {
b.Websocket.DataHandler <- err
continue
}
var newOB orderbook.Base
var price, amount float64
var asks, bids []orderbook.Item
for i := range t.Data.SellQuote {
p := strings.Replace(t.Data.SellQuote[i].Price, ",", "", -1)
price, err = strconv.ParseFloat(p, 64)
@@ -118,7 +118,10 @@ func (b *BTSE) WsHandleData() {
b.Websocket.DataHandler <- err
continue
}
asks = append(asks, orderbook.Item{Price: price, Amount: amount})
newOB.Asks = append(newOB.Asks, orderbook.Item{
Price: price,
Amount: amount,
})
}
for j := range t.Data.BuyQuote {
p := strings.Replace(t.Data.BuyQuote[j].Price, ",", "", -1)
@@ -133,11 +136,11 @@ func (b *BTSE) WsHandleData() {
b.Websocket.DataHandler <- err
continue
}
bids = append(bids, orderbook.Item{Price: price, Amount: amount})
newOB.Bids = append(newOB.Bids, orderbook.Item{
Price: price,
Amount: amount,
})
}
var newOB orderbook.Base
newOB.Asks = asks
newOB.Bids = bids
newOB.AssetType = asset.Spot
newOB.Pair = currency.NewPairFromString(t.Topic[strings.Index(t.Topic, ":")+1 : strings.Index(t.Topic, "_")])
newOB.ExchangeName = b.Name

View File

@@ -450,7 +450,11 @@ func (b *BTSE) GetOrderInfo(orderID string) (order.Detail, error) {
od.Exchange = b.Name
od.Amount = o[i].Amount
od.ID = o[i].ID
od.OrderDate = parseOrderTime(o[i].CreatedAt)
od.OrderDate, err = parseOrderTime(o[i].CreatedAt)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s GetOrderInfo unable to parse time: %s\n", b.Name, err)
}
od.OrderSide = side
od.OrderType = order.Type(strings.ToUpper(o[i].Type))
od.Price = o[i].Price
@@ -464,7 +468,11 @@ func (b *BTSE) GetOrderInfo(orderID string) (order.Detail, error) {
}
for i := range fills {
createdAt, _ := time.Parse(time.RFC3339, fills[i].CreatedAt)
createdAt, err := parseOrderTime(fills[i].CreatedAt)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s GetOrderInfo unable to parse time: %s\n", b.Name, err)
}
od.Trades = append(od.Trades, order.TradeHistory{
Timestamp: createdAt,
TID: fills[i].ID,
@@ -521,13 +529,21 @@ func (b *BTSE) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail, err
side = order.Sell
}
tm, err := parseOrderTime(resp[i].CreatedAt)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s GetActiveOrders unable to parse time: %s\n",
b.Name,
err)
}
openOrder := order.Detail{
CurrencyPair: currency.NewPairDelimiter(resp[i].Symbol,
b.GetPairFormat(asset.Spot, false).Delimiter),
Exchange: b.Name,
Amount: resp[i].Amount,
ID: resp[i].ID,
OrderDate: parseOrderTime(resp[i].CreatedAt),
OrderDate: tm,
OrderSide: side,
OrderType: order.Type(strings.ToUpper(resp[i].Type)),
Price: resp[i].Price,
@@ -544,7 +560,13 @@ func (b *BTSE) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail, err
}
for i := range fills {
createdAt, _ := time.Parse(time.RFC3339, fills[i].CreatedAt)
createdAt, err := parseOrderTime(fills[i].CreatedAt)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s GetActiveOrders unable to parse time: %s\n",
b.Name,
err)
}
openOrder.Trades = append(openOrder.Trades, order.TradeHistory{
Timestamp: createdAt,
TID: fills[i].ID,

View File

@@ -22,6 +22,7 @@ const (
apiSecret = ""
clientID = "" // passphrase you made at API CREATION
canManipulateRealOrders = false
testPair = "BTC-USD"
)
func TestSetDefaults(t *testing.T) {
@@ -58,28 +59,28 @@ func TestGetProducts(t *testing.T) {
}
func TestGetTicker(t *testing.T) {
_, err := c.GetTicker("BTC-USD")
_, err := c.GetTicker(testPair)
if err != nil {
t.Error("GetTicker() error", err)
}
}
func TestGetTrades(t *testing.T) {
_, err := c.GetTrades("BTC-USD")
_, err := c.GetTrades(testPair)
if err != nil {
t.Error("GetTrades() error", err)
}
}
func TestGetHistoricRates(t *testing.T) {
_, err := c.GetHistoricRates("BTC-USD", 0, 0, 0)
_, err := c.GetHistoricRates(testPair, 0, 0, 0)
if err != nil {
t.Error("GetHistoricRates() error", err)
}
}
func TestGetStats(t *testing.T) {
_, err := c.GetStats("BTC-USD")
_, err := c.GetStats(testPair)
if err != nil {
t.Error("GetStats() error", err)
}
@@ -128,21 +129,23 @@ func TestAuthRequests(t *testing.T) {
if err == nil {
t.Error("Expecting error")
}
orderResponse, err := c.PlaceLimitOrder("", 0.001, 0.001, "buy", "", "", "BTC-USD", "", false)
orderResponse, err := c.PlaceLimitOrder("", 0.001, 0.001,
order.Buy.Lower(), "", "", testPair, "", false)
if orderResponse != "" {
t.Error("Expecting no data returned")
}
if err == nil {
t.Error("Expecting error")
}
marketOrderResponse, err := c.PlaceMarketOrder("", 1, 0, "buy", "BTC-USD", "")
marketOrderResponse, err := c.PlaceMarketOrder("", 1, 0,
order.Buy.Lower(), testPair, "")
if marketOrderResponse != "" {
t.Error("Expecting no data returned")
}
if err == nil {
t.Error("Expecting error")
}
fillsResponse, err := c.GetFills("1337", "BTC-USD")
fillsResponse, err := c.GetFills("1337", testPair)
if len(fillsResponse) > 0 {
t.Error("Expecting no data returned")
}
@@ -616,7 +619,7 @@ func TestWsAuth(t *testing.T) {
go c.WsHandleData()
err = c.Subscribe(wshandler.WebsocketChannelSubscription{
Channel: "user",
Currency: currency.NewPairFromString("BTC-USD"),
Currency: currency.NewPairFromString(testPair),
})
if err != nil {
t.Error(err)

View File

@@ -515,7 +515,7 @@ func (c *CoinbasePro) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Deta
orderType := order.Type(strings.ToUpper(respOrders[i].Type))
orderDate, err := time.Parse(time.RFC3339, respOrders[i].CreatedAt)
if err != nil {
log.Warnf(log.ExchangeSys,
log.Errorf(log.ExchangeSys,
"Exchange %v Func %v Order %v Could not parse date to unix with value of %v",
c.Name,
"GetActiveOrders",
@@ -562,7 +562,7 @@ func (c *CoinbasePro) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Deta
orderType := order.Type(strings.ToUpper(respOrders[i].Type))
orderDate, err := time.Parse(time.RFC3339, respOrders[i].CreatedAt)
if err != nil {
log.Warnf(log.ExchangeSys,
log.Errorf(log.ExchangeSys,
"Exchange %v Func %v Order %v Could not parse date to unix with value of %v",
c.Name,
"GetActiveOrders",

View File

@@ -48,22 +48,22 @@ main.go
```go
var c exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "Coinbene" {
c = bot.exchanges[i]
for i := range Bot.Exchanges {
if Bot.Exchanges[i].GetName() == "Coinbene" {
c = Bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := c.GetTickerPrice()
tick, err := c.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := c.GetOrderbookEx()
ob, err := c.FetchOrderbook()
if err != nil {
// Handle error
}

View File

@@ -247,9 +247,14 @@ func (c *Coinbene) SendHTTPRequest(path string, result interface{}) error {
// SendAuthHTTPRequest sends an authenticated HTTP request
func (c *Coinbene) SendAuthHTTPRequest(method, path, epPath string, params url.Values, result interface{}) error {
if !c.AllowAuthenticatedRequest() {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, c.Name)
}
if params == nil {
params = url.Values{}
}
timestamp := time.Now().UTC().Format("2006-01-02T15:04:05.999Z")
var finalBody io.Reader
var preSign string

View File

@@ -34,7 +34,11 @@ func TestMain(m *testing.M) {
coinbeneConfig.API.AuthenticatedSupport = true
coinbeneConfig.API.Credentials.Secret = testAPISecret
coinbeneConfig.API.Credentials.Key = testAPIKey
c.Setup(coinbeneConfig)
err = c.Setup(coinbeneConfig)
if err != nil {
log.Fatal(err)
}
os.Exit(m.Run())
}

View File

@@ -421,9 +421,7 @@ func (c *COINUT) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderbo
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (c *COINUT) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -755,10 +755,10 @@ func (e *Base) FormatWithdrawPermissions() string {
return NoAPIWithdrawalMethodsText
}
// IsAssetTypeSupported whether or not the supplied asset is supported
// SupportsAsset whether or not the supplied asset is supported
// by the exchange
func (e *Base) IsAssetTypeSupported(asset asset.Item) bool {
return e.CurrencyPairs.AssetTypes.Contains(asset)
func (e *Base) SupportsAsset(a asset.Item) bool {
return e.CurrencyPairs.AssetTypes.Contains(a)
}
// PrintEnabledPairs prints the exchanges enabled asset pairs

View File

@@ -550,7 +550,7 @@ func TestGetEnabledPairs(t *testing.T) {
}
b.CurrencyPairs.StorePairs(asset.Spot,
currency.NewPairsFromStrings([]string{"BTC-USD"}), true)
currency.NewPairsFromStrings([]string{defaultTestCurrencyPair}), true)
format := currency.PairFormat{
Delimiter: "-",
Index: "",
@@ -1321,18 +1321,16 @@ func TestFormatWithdrawPermissions(t *testing.T) {
}
}
func TestIsAssetTypeSupported(t *testing.T) {
func TestSupportsAsset(t *testing.T) {
t.Parallel()
var b Base
b.CurrencyPairs.AssetTypes = asset.Items{
asset.Spot,
}
if !b.IsAssetTypeSupported(asset.Spot) {
if !b.SupportsAsset(asset.Spot) {
t.Error("spot should be supported")
}
if b.IsAssetTypeSupported(asset.Index) {
if b.SupportsAsset(asset.Index) {
t.Error("index shouldn't be supported")
}
}

View File

@@ -313,8 +313,7 @@ func (e *EXMO) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (e *EXMO) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -277,13 +277,17 @@ func (g *Gateio) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderbo
}
for x := range orderbookNew.Bids {
data := orderbookNew.Bids[x]
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data.Amount, Price: data.Price})
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
Amount: orderbookNew.Bids[x].Amount,
Price: orderbookNew.Bids[x].Price,
})
}
for x := range orderbookNew.Asks {
data := orderbookNew.Asks[x]
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data.Amount, Price: data.Price})
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
Amount: orderbookNew.Asks[x].Amount,
Price: orderbookNew.Asks[x].Price,
})
}
orderBook.Pair = p
@@ -366,8 +370,7 @@ func (g *Gateio) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (g *Gateio) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -91,7 +91,11 @@ func TestGetAuctionHistory(t *testing.T) {
func TestNewOrder(t *testing.T) {
t.Parallel()
_, err := g.NewOrder(testCurrency, 1, 9000, "buy", "exchange limit")
_, err := g.NewOrder(testCurrency,
1,
9000000,
order.Sell.Lower(),
"exchange limit")
if err != nil && mockTests {
t.Error("NewOrder() error", err)
} else if err == nil && !mockTests {

View File

@@ -307,8 +307,7 @@ func (g *Gemini) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderbo
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (g *Gemini) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -232,22 +232,23 @@ func (h *HitBTC) WsProcessOrderbookSnapshot(ob WsOrderbook) error {
return errors.New("hitbtc.go error - no orderbooks to process")
}
var bids []orderbook.Item
var newOrderBook orderbook.Base
for i := range ob.Params.Bid {
bids = append(bids, orderbook.Item{Amount: ob.Params.Bid[i].Size, Price: ob.Params.Bid[i].Price})
newOrderBook.Bids = append(newOrderBook.Bids, orderbook.Item{
Amount: ob.Params.Bid[i].Size,
Price: ob.Params.Bid[i].Price,
})
}
var asks []orderbook.Item
for i := range ob.Params.Ask {
asks = append(asks, orderbook.Item{Amount: ob.Params.Ask[i].Size, Price: ob.Params.Ask[i].Price})
newOrderBook.Asks = append(newOrderBook.Asks, orderbook.Item{
Amount: ob.Params.Ask[i].Size,
Price: ob.Params.Ask[i].Price,
})
}
p := currency.NewPairFromFormattedPairs(ob.Params.Symbol,
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true))
var newOrderBook orderbook.Base
newOrderBook.Asks = asks
newOrderBook.Bids = bids
newOrderBook.AssetType = asset.Spot
newOrderBook.Pair = p
newOrderBook.ExchangeName = h.Name
@@ -274,11 +275,17 @@ func (h *HitBTC) WsProcessOrderbookUpdate(update WsOrderbook) error {
var bids, asks []orderbook.Item
for i := range update.Params.Bid {
bids = append(bids, orderbook.Item{Price: update.Params.Bid[i].Price, Amount: update.Params.Bid[i].Size})
bids = append(bids, orderbook.Item{
Price: update.Params.Bid[i].Price,
Amount: update.Params.Bid[i].Size,
})
}
for i := range update.Params.Ask {
asks = append(asks, orderbook.Item{Price: update.Params.Ask[i].Price, Amount: update.Params.Ask[i].Size})
asks = append(asks, orderbook.Item{
Price: update.Params.Ask[i].Price,
Amount: update.Params.Ask[i].Size,
})
}
p := currency.NewPairFromFormattedPairs(update.Params.Symbol,

View File

@@ -309,13 +309,17 @@ func (h *HitBTC) UpdateOrderbook(currencyPair currency.Pair, assetType asset.Ite
}
for x := range orderbookNew.Bids {
data := orderbookNew.Bids[x]
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data.Amount, Price: data.Price})
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
Amount: orderbookNew.Bids[x].Amount,
Price: orderbookNew.Bids[x].Price,
})
}
for x := range orderbookNew.Asks {
data := orderbookNew.Asks[x]
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data.Amount, Price: data.Price})
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
Amount: orderbookNew.Asks[x].Amount,
Price: orderbookNew.Asks[x].Price,
})
}
orderBook.Pair = currencyPair
@@ -360,8 +364,7 @@ func (h *HitBTC) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (h *HitBTC) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.
@@ -379,8 +382,8 @@ func (h *HitBTC) SubmitOrder(s *order.Submit) (order.SubmitResponse, error) {
response, err := h.PlaceOrder(s.Pair.String(),
s.Price,
s.Amount,
strings.ToLower(s.OrderType.String()),
strings.ToLower(s.OrderSide.String()))
s.OrderType.Lower(),
s.OrderSide.Lower())
if response.OrderNumber > 0 {
submitOrderResponse.OrderID = strconv.FormatInt(response.OrderNumber, 10)
}

View File

@@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"strconv"
"strings"
"sync"
"time"
@@ -350,13 +349,17 @@ func (h *HUOBI) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderboo
}
for x := range orderbookNew.Bids {
data := orderbookNew.Bids[x]
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data[1], Price: data[0]})
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
Amount: orderbookNew.Bids[x][1],
Price: orderbookNew.Bids[x][0],
})
}
for x := range orderbookNew.Asks {
data := orderbookNew.Asks[x]
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data[1], Price: data[0]})
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
Amount: orderbookNew.Asks[x][1],
Price: orderbookNew.Asks[x][0],
})
}
orderBook.Pair = p
@@ -452,8 +455,7 @@ func (h *HUOBI) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (h *HUOBI) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.
@@ -600,7 +602,7 @@ func (h *HUOBI) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail, er
if req.OrderSide == order.AnySide || req.OrderSide == "" {
side = ""
} else if req.OrderSide == order.Sell {
side = strings.ToLower(string(req.OrderSide))
side = req.OrderSide.Lower()
}
var orders []order.Detail

View File

@@ -66,4 +66,5 @@ type IBotExchange interface {
GetSubscriptions() ([]wshandler.WebsocketChannelSubscription, error)
GetDefaultConfig() (*config.ExchangeConfig, error)
GetBase() *Base
SupportsAsset(assetType asset.Item) bool
}

View File

@@ -193,13 +193,12 @@ func (i *ItBit) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderboo
}
for x := range orderbookNew.Bids {
data := orderbookNew.Bids[x]
var price, amount float64
price, err = strconv.ParseFloat(data[0], 64)
price, err = strconv.ParseFloat(orderbookNew.Bids[x][0], 64)
if err != nil {
return orderBook, err
}
amount, err = strconv.ParseFloat(data[1], 64)
amount, err = strconv.ParseFloat(orderbookNew.Bids[x][1], 64)
if err != nil {
return orderBook, err
}
@@ -211,13 +210,12 @@ func (i *ItBit) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderboo
}
for x := range orderbookNew.Asks {
data := orderbookNew.Asks[x]
var price, amount float64
price, err = strconv.ParseFloat(data[0], 64)
price, err = strconv.ParseFloat(orderbookNew.Asks[x][0], 64)
if err != nil {
return orderBook, err
}
amount, err = strconv.ParseFloat(data[1], 64)
amount, err = strconv.ParseFloat(orderbookNew.Asks[x][1], 64)
if err != nil {
return orderBook, err
}
@@ -287,8 +285,7 @@ func (i *ItBit) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (i *ItBit) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.
@@ -444,7 +441,7 @@ func (i *ItBit) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail, er
side := order.Side(strings.ToUpper(allOrders[j].Side))
orderDate, err := time.Parse(time.RFC3339, allOrders[j].CreatedTime)
if err != nil {
log.Warnf(log.ExchangeSys,
log.Errorf(log.ExchangeSys,
"Exchange %v Func %v Order %v Could not parse date to unix with value of %v",
i.Name,
"GetActiveOrders",
@@ -498,7 +495,7 @@ func (i *ItBit) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail, er
side := order.Side(strings.ToUpper(allOrders[j].Side))
orderDate, err := time.Parse(time.RFC3339, allOrders[j].CreatedTime)
if err != nil {
log.Warnf(log.ExchangeSys,
log.Errorf(log.ExchangeSys,
"Exchange %v Func %v Order %v Could not parse date to unix with value of %v",
i.Name,
"GetActiveOrders",

View File

@@ -386,8 +386,7 @@ func (k *Kraken) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (k *Kraken) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -10,6 +10,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
log "github.com/thrasher-corp/gocryptotrader/logger"
@@ -21,11 +22,9 @@ const (
marketGlobalEndpoint = "market-global"
marketSubstring = "market-"
globalSubstring = "-global"
tickerBuyString = "buy"
tickerHighString = "high"
tickerLastString = "last"
tickerLowString = "low"
tickerSellString = "sell"
tickerVolumeString = "volume"
wssSchem = "wss"
)
@@ -270,11 +269,11 @@ func (l *LakeBTC) processTicker(ticker string) error {
l.Websocket.DataHandler <- wshandler.TickerData{
Exchange: l.Name,
Bid: processTickerItem(tickerData, tickerBuyString),
Bid: processTickerItem(tickerData, order.Buy.Lower()),
High: processTickerItem(tickerData, tickerHighString),
Last: processTickerItem(tickerData, tickerLastString),
Low: processTickerItem(tickerData, tickerLowString),
Ask: processTickerItem(tickerData, tickerSellString),
Ask: processTickerItem(tickerData, order.Sell.Lower()),
Volume: processTickerItem(tickerData, tickerVolumeString),
AssetType: asset.Spot,
Pair: returnCurrency,

View File

@@ -316,8 +316,7 @@ func (l *LakeBTC) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (l *LakeBTC) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -47,22 +47,22 @@ main.go
```go
var l exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "Lbank" {
l = bot.exchanges[i]
for i := range Bot.Exchanges {
if Bot.Exchanges[i].GetName() == "Lbank" {
l = Bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := l.GetTickerPrice()
tick, err := l.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := l.GetOrderbookEx()
ob, err := l.FetchOrderbook()
if err != nil {
// Handle error
}

View File

@@ -17,6 +17,7 @@ import (
gctcrypto "github.com/thrasher-corp/gocryptotrader/common/crypto"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
)
@@ -195,7 +196,8 @@ func (l *Lbank) GetUserInfo() (InfoFinalResponse, error) {
// CreateOrder creates an order
func (l *Lbank) CreateOrder(pair, side string, amount, price float64) (CreateOrderResponse, error) {
var resp CreateOrderResponse
if !strings.EqualFold(side, "buy") && !strings.EqualFold(side, "sell") {
if !strings.EqualFold(side, order.Buy.String()) &&
!strings.EqualFold(side, order.Sell.String()) {
return resp, errors.New("side type invalid can only be 'buy' or 'sell'")
}
if amount <= 0 {
@@ -546,6 +548,10 @@ func (l *Lbank) sign(data string) (string, error) {
// SendAuthHTTPRequest sends an authenticated request
func (l *Lbank) SendAuthHTTPRequest(method, endpoint string, vals url.Values, result interface{}) error {
if !l.AllowAuthenticatedRequest() {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, l.Name)
}
if vals == nil {
vals = url.Values{}
}

View File

@@ -407,7 +407,7 @@ func (l *Lbank) GetOrderInfo(orderID string) (order.Detail, error) {
}
resp.Exchange = l.Name
resp.CurrencyPair = currency.NewPairFromString(key)
if strings.EqualFold(tempResp.Orders[0].Type, "buy") {
if strings.EqualFold(tempResp.Orders[0].Type, order.Buy.String()) {
resp.OrderSide = order.Buy
} else {
resp.OrderSide = order.Sell
@@ -491,7 +491,7 @@ func (l *Lbank) GetActiveOrders(getOrdersRequest *order.GetOrdersRequest) ([]ord
}
resp.Exchange = l.Name
resp.CurrencyPair = currency.NewPairFromString(key)
if strings.EqualFold(tempResp.Orders[0].Type, "buy") {
if strings.EqualFold(tempResp.Orders[0].Type, order.Buy.String()) {
resp.OrderSide = order.Buy
} else {
resp.OrderSide = order.Sell
@@ -567,7 +567,7 @@ func (l *Lbank) GetOrderHistory(getOrdersRequest *order.GetOrdersRequest) ([]ord
for x := 0; x < len(tempResp.Orders); x++ {
resp.Exchange = l.Name
resp.CurrencyPair = currency.NewPairFromString(tempResp.Orders[x].Symbol)
if strings.EqualFold(tempResp.Orders[x].Type, "buy") {
if strings.EqualFold(tempResp.Orders[x].Type, order.Buy.String()) {
resp.OrderSide = order.Buy
} else {
resp.OrderSide = order.Sell

View File

@@ -218,13 +218,17 @@ func (l *LocalBitcoins) UpdateOrderbook(p currency.Pair, assetType asset.Item) (
}
for x := range orderbookNew.Bids {
data := orderbookNew.Bids[x]
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data.Amount / data.Price, Price: data.Price})
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
Amount: orderbookNew.Bids[x].Amount / orderbookNew.Bids[x].Price,
Price: orderbookNew.Bids[x].Price,
})
}
for x := range orderbookNew.Asks {
data := orderbookNew.Asks[x]
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data.Amount / data.Price, Price: data.Price})
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
Amount: orderbookNew.Asks[x].Amount / orderbookNew.Asks[x].Price,
Price: orderbookNew.Asks[x].Price,
})
}
orderBook.Pair = p
@@ -261,8 +265,7 @@ func (l *LocalBitcoins) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (l *LocalBitcoins) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.
@@ -434,7 +437,7 @@ func (l *LocalBitcoins) GetActiveOrders(getOrdersRequest *order.GetOrdersRequest
for i := range resp {
orderDate, err := time.Parse(time.RFC3339, resp[i].Data.CreatedAt)
if err != nil {
log.Warnf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v",
log.Errorf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v",
l.Name,
"GetActiveOrders",
resp[i].Data.Advertisement.ID,
@@ -495,7 +498,7 @@ func (l *LocalBitcoins) GetOrderHistory(getOrdersRequest *order.GetOrdersRequest
for i := range allTrades {
orderDate, err := time.Parse(time.RFC3339, allTrades[i].Data.CreatedAt)
if err != nil {
log.Warnf(log.ExchangeSys,
log.Errorf(log.ExchangeSys,
"Exchange %v Func %v Order %v Could not parse date to unix with value of %v",
l.Name,
"GetActiveOrders",

View File

@@ -146,7 +146,7 @@ func TestGetAccountWalletInformationForCurrency(t *testing.T) {
func TestTransferAccountFunds(t *testing.T) {
TestSetRealOrderDefaults(t)
request := okgroup.TransferAccountFundsRequest{
Amount: 10,
Amount: -10,
Currency: currency.BTC.String(),
From: 6,
To: 1,
@@ -159,7 +159,7 @@ func TestTransferAccountFunds(t *testing.T) {
func TestAccountWithdrawRequest(t *testing.T) {
TestSetRealOrderDefaults(t)
request := okgroup.AccountWithdrawRequest{
Amount: 10,
Amount: -10,
Currency: currency.BTC.String(),
TradePwd: "1234",
Destination: 4,
@@ -285,13 +285,12 @@ func TestGetSpotBillDetailsForCurrencyBadLimit(t *testing.T) {
// TestPlaceSpotOrderLimit API endpoint test
func TestPlaceSpotOrderLimit(t *testing.T) {
TestSetRealOrderDefaults(t)
request := okgroup.PlaceSpotOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Price: "100",
Size: "100",
request := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
Price: "-100",
Size: "100",
}
_, err := o.PlaceSpotOrder(&request)
@@ -301,13 +300,12 @@ func TestPlaceSpotOrderLimit(t *testing.T) {
// TestPlaceSpotOrderMarket API endpoint test
func TestPlaceSpotOrderMarket(t *testing.T) {
TestSetRealOrderDefaults(t)
request := okgroup.PlaceSpotOrderRequest{
InstrumentID: spotCurrency,
Type: order.Market.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "-100",
Notional: "100",
request := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Market.Lower(),
Side: order.Buy.Lower(),
Size: "-100",
Notional: "100",
}
_, err := o.PlaceSpotOrder(&request)
@@ -317,16 +315,15 @@ func TestPlaceSpotOrderMarket(t *testing.T) {
// TestPlaceMultipleSpotOrders API endpoint test
func TestPlaceMultipleSpotOrders(t *testing.T) {
TestSetRealOrderDefaults(t)
order := okgroup.PlaceSpotOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Notional: "100",
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
Size: "-100",
Price: "1",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
}
@@ -339,16 +336,15 @@ func TestPlaceMultipleSpotOrders(t *testing.T) {
// TestPlaceMultipleSpotOrdersOverCurrencyLimits API logic test
func TestPlaceMultipleSpotOrdersOverCurrencyLimits(t *testing.T) {
TestSetDefaults(t)
order := okgroup.PlaceSpotOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Notional: "100",
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
Size: "-100",
Price: "1",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
order,
order,
@@ -365,27 +361,29 @@ func TestPlaceMultipleSpotOrdersOverCurrencyLimits(t *testing.T) {
// TestPlaceMultipleSpotOrdersOverPairLimits API logic test
func TestPlaceMultipleSpotOrdersOverPairLimits(t *testing.T) {
TestSetDefaults(t)
order := okgroup.PlaceSpotOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Notional: "100",
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
Size: "-100",
Price: "1",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
}
order.InstrumentID = currency.NewPairWithDelimiter(currency.LTC.String(), currency.USD.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.DOGE.String(), currency.USD.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.XMR.String(), currency.USD.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.BCH.String(), currency.USD.String(), "-").Lower().String()
request = append(request, order)
pairs := currency.Pairs{
currency.NewPair(currency.LTC, currency.USDT),
currency.NewPair(currency.ETH, currency.USDT),
currency.NewPair(currency.BCH, currency.USDT),
currency.NewPair(currency.XMR, currency.USDT),
}
for x := range pairs {
order.InstrumentID = pairs[x].Format("-", false).String()
request = append(request, order)
}
_, errs := o.PlaceMultipleSpotOrders(request)
if errs[0].Error() != "up to 4 trading pairs" {
@@ -574,7 +572,7 @@ func TestGetMarginAccountSettingsForCurrency(t *testing.T) {
func TestOpenMarginLoan(t *testing.T) {
TestSetRealOrderDefaults(t)
request := okgroup.OpenMarginLoanRequest{
Amount: 100,
Amount: -100,
InstrumentID: spotCurrency,
QuoteCurrency: currency.USD.String(),
}
@@ -587,7 +585,7 @@ func TestOpenMarginLoan(t *testing.T) {
func TestRepayMarginLoan(t *testing.T) {
TestSetRealOrderDefaults(t)
request := okgroup.RepayMarginLoanRequest{
Amount: 100,
Amount: -100,
InstrumentID: spotCurrency,
QuoteCurrency: currency.USD.String(),
BorrowID: 1,
@@ -600,12 +598,12 @@ func TestRepayMarginLoan(t *testing.T) {
// TestPlaceMarginOrderLimit API endpoint test
func TestPlaceMarginOrderLimit(t *testing.T) {
TestSetRealOrderDefaults(t)
request := okgroup.PlaceSpotOrderRequest{
request := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "2",
Price: "100",
Price: "-100",
Size: "100",
}
@@ -616,7 +614,7 @@ func TestPlaceMarginOrderLimit(t *testing.T) {
// TestPlaceMarginOrderMarket API endpoint test
func TestPlaceMarginOrderMarket(t *testing.T) {
TestSetRealOrderDefaults(t)
request := okgroup.PlaceSpotOrderRequest{
request := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Market.Lower(),
Side: order.Buy.Lower(),
@@ -632,16 +630,16 @@ func TestPlaceMarginOrderMarket(t *testing.T) {
// TestPlaceMultipleMarginOrders API endpoint test
func TestPlaceMultipleMarginOrders(t *testing.T) {
TestSetRealOrderDefaults(t)
order := okgroup.PlaceSpotOrderRequest{
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Size: "-100",
Notional: "100",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
}
@@ -654,16 +652,16 @@ func TestPlaceMultipleMarginOrders(t *testing.T) {
// TestPlaceMultipleMarginOrdersOverCurrencyLimits API logic test
func TestPlaceMultipleMarginOrdersOverCurrencyLimits(t *testing.T) {
TestSetDefaults(t)
order := okgroup.PlaceSpotOrderRequest{
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Size: "-100",
Notional: "100",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
order,
order,
@@ -680,27 +678,30 @@ func TestPlaceMultipleMarginOrdersOverCurrencyLimits(t *testing.T) {
// TestPlaceMultipleMarginOrdersOverPairLimits API logic test
func TestPlaceMultipleMarginOrdersOverPairLimits(t *testing.T) {
TestSetDefaults(t)
order := okgroup.PlaceSpotOrderRequest{
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Size: "-100",
Notional: "100",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
}
order.InstrumentID = currency.NewPairWithDelimiter(currency.LTC.String(), currency.USD.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.DOGE.String(), currency.USD.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.XMR.String(), currency.USD.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.BCH.String(), currency.USD.String(), "-").Lower().String()
request = append(request, order)
pairs := currency.Pairs{
currency.NewPair(currency.LTC, currency.USDT),
currency.NewPair(currency.ETH, currency.USDT),
currency.NewPair(currency.BCH, currency.USDT),
currency.NewPair(currency.XMR, currency.USDT),
}
for x := range pairs {
order.InstrumentID = pairs[x].Format("-", false).String()
request = append(request, order)
}
_, errs := o.PlaceMultipleMarginOrders(request)
if errs[0].Error() != "up to 4 trading pairs" {
@@ -1049,7 +1050,7 @@ func TestSubmitOrder(t *testing.T) {
},
OrderSide: order.Buy,
OrderType: order.Limit,
Price: 1,
Price: -1,
Amount: 1,
ClientID: "meowOrder",
}

View File

@@ -3,6 +3,7 @@ package okex
import (
"fmt"
"net/http"
"strconv"
"strings"
"sync"
"testing"
@@ -154,7 +155,7 @@ func TestTransferAccountFunds(t *testing.T) {
Amount: 10,
Currency: currency.BTC.String(),
From: 6,
To: 1,
To: -1,
}
_, err := o.TransferAccountFunds(request)
@@ -166,7 +167,7 @@ func TestAccountWithdrawRequest(t *testing.T) {
TestSetRealOrderDefaults(t)
t.Parallel()
request := okgroup.AccountWithdrawRequest{
Amount: 10,
Amount: -1,
Currency: currency.BTC.String(),
TradePwd: "1234",
Destination: 4,
@@ -306,13 +307,12 @@ func TestGetSpotBillDetailsForCurrencyBadLimit(t *testing.T) {
func TestPlaceSpotOrderLimit(t *testing.T) {
TestSetRealOrderDefaults(t)
t.Parallel()
request := okgroup.PlaceSpotOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Price: "100",
Size: "100",
request := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
Price: "-1",
Size: "0.001",
}
_, err := o.PlaceSpotOrder(&request)
@@ -323,13 +323,12 @@ func TestPlaceSpotOrderLimit(t *testing.T) {
func TestPlaceSpotOrderMarket(t *testing.T) {
TestSetRealOrderDefaults(t)
t.Parallel()
request := okgroup.PlaceSpotOrderRequest{
InstrumentID: spotCurrency,
Type: order.Market.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "-100",
Notional: "100",
request := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Market.Lower(),
Side: order.Buy.Lower(),
Size: "-100",
Notional: "100",
}
_, err := o.PlaceSpotOrder(&request)
@@ -340,16 +339,15 @@ func TestPlaceSpotOrderMarket(t *testing.T) {
func TestPlaceMultipleSpotOrders(t *testing.T) {
TestSetRealOrderDefaults(t)
t.Parallel()
order := okgroup.PlaceSpotOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Notional: "100",
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
Size: "-100",
Price: "1",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
}
@@ -363,16 +361,15 @@ func TestPlaceMultipleSpotOrders(t *testing.T) {
func TestPlaceMultipleSpotOrdersOverCurrencyLimits(t *testing.T) {
TestSetDefaults(t)
t.Parallel()
order := okgroup.PlaceSpotOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Notional: "100",
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
Size: "-100",
Price: "1",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
order,
order,
@@ -390,27 +387,29 @@ func TestPlaceMultipleSpotOrdersOverCurrencyLimits(t *testing.T) {
func TestPlaceMultipleSpotOrdersOverPairLimits(t *testing.T) {
TestSetDefaults(t)
t.Parallel()
order := okgroup.PlaceSpotOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Notional: "100",
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
Size: "-1",
Price: "1",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
}
order.InstrumentID = currency.NewPairWithDelimiter(currency.LTC.String(), currency.USDT.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.DOGE.String(), currency.USDT.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.XMR.String(), currency.USDT.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.BCH.String(), currency.USDT.String(), "-").Lower().String()
request = append(request, order)
pairs := currency.Pairs{
currency.NewPair(currency.LTC, currency.USDT),
currency.NewPair(currency.ETH, currency.USDT),
currency.NewPair(currency.BCH, currency.USDT),
currency.NewPair(currency.XMR, currency.USDT),
}
for x := range pairs {
order.InstrumentID = pairs[x].Format("-", false).String()
request = append(request, order)
}
_, errs := o.PlaceMultipleSpotOrders(request)
if errs[0].Error() != "up to 4 trading pairs" {
@@ -619,7 +618,7 @@ func TestOpenMarginLoan(t *testing.T) {
TestSetRealOrderDefaults(t)
t.Parallel()
request := okgroup.OpenMarginLoanRequest{
Amount: 100,
Amount: -100,
InstrumentID: spotCurrency,
QuoteCurrency: currency.USDT.String(),
}
@@ -633,7 +632,7 @@ func TestRepayMarginLoan(t *testing.T) {
TestSetRealOrderDefaults(t)
t.Parallel()
request := okgroup.RepayMarginLoanRequest{
Amount: 100,
Amount: -100,
InstrumentID: spotCurrency,
QuoteCurrency: currency.USDT.String(),
BorrowID: 1,
@@ -647,13 +646,13 @@ func TestRepayMarginLoan(t *testing.T) {
func TestPlaceMarginOrderLimit(t *testing.T) {
TestSetRealOrderDefaults(t)
t.Parallel()
request := okgroup.PlaceSpotOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "2",
Price: "100",
Size: "100",
request := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
OrderType: strconv.Itoa(okgroup.NormalOrder),
Price: "-100",
Size: "100",
}
_, err := o.PlaceMarginOrder(&request)
@@ -664,7 +663,7 @@ func TestPlaceMarginOrderLimit(t *testing.T) {
func TestPlaceMarginOrderMarket(t *testing.T) {
TestSetRealOrderDefaults(t)
t.Parallel()
request := okgroup.PlaceSpotOrderRequest{
request := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Market.Lower(),
Side: order.Buy.Lower(),
@@ -681,16 +680,16 @@ func TestPlaceMarginOrderMarket(t *testing.T) {
func TestPlaceMultipleMarginOrders(t *testing.T) {
TestSetRealOrderDefaults(t)
t.Parallel()
order := okgroup.PlaceSpotOrderRequest{
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Size: "-100",
Notional: "100",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
}
@@ -704,16 +703,16 @@ func TestPlaceMultipleMarginOrders(t *testing.T) {
func TestPlaceMultipleMarginOrdersOverCurrencyLimits(t *testing.T) {
TestSetDefaults(t)
t.Parallel()
order := okgroup.PlaceSpotOrderRequest{
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Size: "-100",
Notional: "100",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
order,
order,
@@ -731,27 +730,30 @@ func TestPlaceMultipleMarginOrdersOverCurrencyLimits(t *testing.T) {
func TestPlaceMultipleMarginOrdersOverPairLimits(t *testing.T) {
TestSetDefaults(t)
t.Parallel()
order := okgroup.PlaceSpotOrderRequest{
order := okgroup.PlaceOrderRequest{
InstrumentID: spotCurrency,
Type: order.Limit.Lower(),
Side: order.Buy.Lower(),
MarginTrading: "1",
Size: "100",
Size: "-100",
Notional: "100",
}
request := []okgroup.PlaceSpotOrderRequest{
request := []okgroup.PlaceOrderRequest{
order,
}
order.InstrumentID = currency.NewPairWithDelimiter(currency.LTC.String(), currency.USDT.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.DOGE.String(), currency.USDT.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.XMR.String(), currency.USDT.String(), "-").Lower().String()
request = append(request, order)
order.InstrumentID = currency.NewPairWithDelimiter(currency.BCH.String(), currency.USDT.String(), "-").Lower().String()
request = append(request, order)
pairs := currency.Pairs{
currency.NewPair(currency.LTC, currency.USDT),
currency.NewPair(currency.ETH, currency.USDT),
currency.NewPair(currency.BCH, currency.USDT),
currency.NewPair(currency.XMR, currency.USDT),
}
for x := range pairs {
order.InstrumentID = pairs[x].Format("-", false).String()
request = append(request, order)
}
_, errs := o.PlaceMultipleMarginOrders(request)
if errs[0].Error() != "up to 4 trading pairs" {
@@ -935,7 +937,7 @@ func TestPlaceFuturesOrder(t *testing.T) {
Leverage: 10,
Type: 1,
Size: 2,
Price: 432.11,
Price: -432.11,
ClientOid: "12233456",
})
testStandardErrorHandling(t, err)
@@ -951,7 +953,7 @@ func TestPlaceFuturesOrderBatch(t *testing.T) {
{
ClientOid: "1",
MatchPrice: "0",
Price: "100",
Price: "-100",
Size: "100",
Type: "1",
},
@@ -1212,13 +1214,13 @@ func TestPlaceMultipleSwapOrders(t *testing.T) {
ClientOID: "hello",
MatchPrice: "0",
Price: "10",
Size: "1",
Size: "-1",
Type: "1",
}, {
ClientOID: "hello2",
MatchPrice: "0",
Price: "10",
Size: "1",
Size: "-1",
Type: "1",
}},
})
@@ -1463,7 +1465,7 @@ func TestPlaceETTOrder(t *testing.T) {
QuoteCurrency: spotCurrency,
Type: 0,
Size: "100",
Amount: 1,
Amount: -1,
ETT: "OK06",
}

View File

@@ -47,22 +47,22 @@ main.go
```go
var o exchange.IBotExchange
for i := range bot.exchanges {
if bot.exchanges[i].GetName() == "OKex" {
y = bot.exchanges[i]
for i := range Bot.Exchanges {
if Bot.Exchanges[i].GetName() == "OKex" {
y = Bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
tick, err := o.GetTickerPrice()
tick, err := o.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := o.GetOrderbookEx()
ob, err := o.FetchOrderbook()
if err != nil {
// Handle error
}

View File

@@ -103,7 +103,7 @@ type OKGroup struct {
// GetAccountCurrencies returns a list of tradable spot instruments and their properties
func (o *OKGroup) GetAccountCurrencies() (resp []GetAccountCurrenciesResponse, _ error) {
return resp, o.SendHTTPRequest(http.MethodGet, okGroupAccountSubsection, okGroupGetAccountCurrencies, nil, &resp, false)
return resp, o.SendHTTPRequest(http.MethodGet, okGroupAccountSubsection, okGroupGetAccountCurrencies, nil, &resp, true)
}
// GetAccountWalletInformation returns a list of wallets and their properties
@@ -173,7 +173,7 @@ func (o *OKGroup) GetAccountDepositHistory(currency string) (resp []GetAccountDe
if currency != "" {
requestURL = fmt.Sprintf("%v/%v", OKGroupGetAccountDepositHistory, currency)
} else {
requestURL = okGroupGetWithdrawalHistory
requestURL = OKGroupGetAccountDepositHistory
}
return resp, o.SendHTTPRequest(http.MethodGet, okGroupAccountSubsection, requestURL, nil, &resp, true)
}
@@ -198,17 +198,23 @@ func (o *OKGroup) GetSpotBillDetailsForCurrency(request GetSpotBillDetailsForCur
// PlaceSpotOrder token trading only supports limit and market orders (more order types will become available in the future).
// You can place an order only if you have enough funds.
// Once your order is placed, the amount will be put on hold.
func (o *OKGroup) PlaceSpotOrder(request *PlaceSpotOrderRequest) (resp PlaceSpotOrderResponse, _ error) {
func (o *OKGroup) PlaceSpotOrder(request *PlaceOrderRequest) (resp PlaceOrderResponse, _ error) {
if request.OrderType == "" {
request.OrderType = strconv.Itoa(NormalOrder)
}
return resp, o.SendHTTPRequest(http.MethodPost, okGroupTokenSubsection, OKGroupOrders, request, &resp, true)
}
// PlaceMultipleSpotOrders supports placing multiple orders for specific trading pairs
// up to 4 trading pairs, maximum 4 orders for each pair
func (o *OKGroup) PlaceMultipleSpotOrders(request []PlaceSpotOrderRequest) (map[string][]PlaceSpotOrderResponse, []error) {
func (o *OKGroup) PlaceMultipleSpotOrders(request []PlaceOrderRequest) (map[string][]PlaceOrderResponse, []error) {
currencyPairOrders := make(map[string]int)
resp := make(map[string][]PlaceSpotOrderResponse)
resp := make(map[string][]PlaceOrderResponse)
for i := range request {
if request[i].OrderType == "" {
request[i].OrderType = strconv.Itoa(NormalOrder)
}
currencyPairOrders[request[i].InstrumentID]++
}
@@ -422,14 +428,14 @@ func (o *OKGroup) RepayMarginLoan(request RepayMarginLoanRequest) (resp RepayMar
// PlaceMarginOrder OKEx API only supports limit and market orders (more orders will become available in the future).
// You can place an order only if you have enough funds. Once your order is placed, the amount will be put on hold.
func (o *OKGroup) PlaceMarginOrder(request *PlaceSpotOrderRequest) (resp PlaceSpotOrderResponse, _ error) {
func (o *OKGroup) PlaceMarginOrder(request *PlaceOrderRequest) (resp PlaceOrderResponse, _ error) {
return resp, o.SendHTTPRequest(http.MethodPost, okGroupMarginTradingSubsection, OKGroupOrders, request, &resp, true)
}
// PlaceMultipleMarginOrders Place multiple orders for specific trading pairs (up to 4 trading pairs, maximum 4 orders each)
func (o *OKGroup) PlaceMultipleMarginOrders(request []PlaceSpotOrderRequest) (map[string][]PlaceSpotOrderResponse, []error) {
func (o *OKGroup) PlaceMultipleMarginOrders(request []PlaceOrderRequest) (map[string][]PlaceOrderResponse, []error) {
currencyPairOrders := make(map[string]int)
resp := make(map[string][]PlaceSpotOrderResponse)
resp := make(map[string][]PlaceOrderResponse)
for i := range request {
currencyPairOrders[request[i].InstrumentID]++
}
@@ -556,10 +562,7 @@ func (o *OKGroup) SendHTTPRequest(httpMethod, requestType, requestPath string, d
o.Name)
}
utcTime := time.Now().UTC()
iso := utcTime.String()
isoBytes := []byte(iso)
iso = string(isoBytes[:10]) + "T" + string(isoBytes[11:23]) + "Z"
utcTime := time.Now().UTC().Format(time.RFC3339)
payload := []byte("")
if data != nil {
@@ -584,11 +587,11 @@ func (o *OKGroup) SendHTTPRequest(httpMethod, requestType, requestPath string, d
signPath := fmt.Sprintf("/%v%v%v%v", OKGroupAPIPath,
requestType, o.APIVersion, requestPath)
hmac := crypto.GetHMAC(crypto.HashSHA256,
[]byte(iso+httpMethod+signPath+string(payload)),
[]byte(utcTime+httpMethod+signPath+string(payload)),
[]byte(o.API.Credentials.Secret))
headers["OK-ACCESS-KEY"] = o.API.Credentials.Key
headers["OK-ACCESS-SIGN"] = crypto.Base64Encode(hmac)
headers["OK-ACCESS-TIMESTAMP"] = iso
headers["OK-ACCESS-TIMESTAMP"] = utcTime
headers["OK-ACCESS-PASSPHRASE"] = o.API.Credentials.ClientID
}

View File

@@ -6,13 +6,21 @@ import (
"github.com/thrasher-corp/gocryptotrader/currency"
)
// Order types
const (
NormalOrder = iota
PostOnlyOrder
FillOrKillOrder
ImmediateOrCancelOrder
)
// GetAccountCurrenciesResponse response data for GetAccountCurrencies
type GetAccountCurrenciesResponse struct {
CanDeposit int64 `json:"can_deposit"`
CanWithdraw int64 `json:"can_withdraw"`
Currency string `json:"currency"`
MinWithdrawal float64 `json:"min_withdrawal"`
Name string `json:"name"`
Currency string `json:"currency"`
CanDeposit int `json:"can_deposit,string"`
CanWithdraw int `json:"can_withdraw,string"`
MinWithdrawal float64 `json:"min_withdrawal,string"`
}
// WalletInformationResponse response data for WalletInformation
@@ -64,22 +72,22 @@ type AccountWithdrawResponse struct {
// GetAccountWithdrawalFeeResponse response data for GetAccountWithdrawalFee
type GetAccountWithdrawalFeeResponse struct {
Currency string `json:"currency"`
MinFee float64 `json:"min_fee"`
MaxFee float64 `json:"max_fee"`
MinFee float64 `json:"min_fee,string"`
MaxFee float64 `json:"max_fee,string"`
}
// WithdrawalHistoryResponse response data for WithdrawalHistoryResponse
type WithdrawalHistoryResponse struct {
Amount float64 `json:"amount"`
Currency string `json:"currency"`
Fee string `json:"fee"`
From string `json:"from"`
Status int64 `json:"status"`
Timestamp time.Time `json:"timestamp"`
To string `json:"to"`
Txid string `json:"txid"`
PaymentID string `json:"payment_id"`
Tag string `json:"tag"`
Amount float64 `json:"amount,string"`
Currency string `json:"currency"`
Fee string `json:"fee"`
From string `json:"from"`
Status int64 `json:"status,string"`
Timestamp time.Time `json:"timestamp"`
To string `json:"to"`
TransactionID string `json:"txid"`
PaymentID string `json:"payment_id"`
Tag string `json:"tag"`
}
// GetAccountBillDetailsRequest request data for GetAccountBillDetailsRequest
@@ -112,11 +120,12 @@ type GetDepositAddressResponse struct {
// GetAccountDepositHistoryResponse response data for GetAccountDepositHistory
type GetAccountDepositHistoryResponse struct {
Amount float64 `json:"amount"`
Amount float64 `json:"amount,string"`
Currency string `json:"currency"`
Status int64 `json:"status"`
Timestamp time.Time `json:"timestamp"`
From string `json:"from"`
To string `json:"to"`
Timestamp time.Time `json:"timestamp"`
Status int64 `json:"status,string"`
TransactionID string `json:"txid"`
}
@@ -156,20 +165,21 @@ type SpotBillDetails struct {
InstrumentID string `json:"instrument_id"`
}
// PlaceSpotOrderRequest request data for PlaceSpotOrder
type PlaceSpotOrderRequest struct {
// PlaceOrderRequest request data for placing an order
type PlaceOrderRequest struct {
ClientOID string `json:"client_oid,omitempty"` // the order ID customized by yourself
Type string `json:"type"` // limit / market(default: limit)
Side string `json:"side"` // buy or sell
InstrumentID string `json:"instrument_id"` // trading pair
MarginTrading string `json:"margin_trading"` // order type (The request value is 1)
MarginTrading string `json:"margin_trading"` // margin trading
OrderType string `json:"order_type"` // order type (0: Normal order (Unfilled and 0 imply normal limit order) 1: Post only 2: Fill or Kill 3: Immediate Or Cancel
Size string `json:"size"`
Notional string `json:"notional,omitempty"` //
Price string `json:"price,omitempty"` // price (Limit order only)
}
// PlaceSpotOrderResponse response data for PlaceSpotOrder
type PlaceSpotOrderResponse struct {
// PlaceOrderResponse response data for PlaceSpotOrder
type PlaceOrderResponse struct {
ClientOid string `json:"client_oid"`
OrderID string `json:"order_id"`
Result bool `json:"result"`
@@ -1497,7 +1507,7 @@ type WebsocketSpotOrderResponse struct {
Notional float64 `json:"notional,string"`
Size float64 `json:"size,string"`
Status string `json:"status"`
MarginTrading int64 `json:"margin_trading"`
MarginTrading int64 `json:"margin_trading,omitempty"`
Type string `json:"type"`
// Price A member, but part already exists as part of WebsocketDataResponse
// InstrumentID A member, but part already exists as part of WebsocketDataResponse

View File

@@ -267,19 +267,21 @@ func (o *OKGroup) WsHandleData(wg *sync.WaitGroup) {
// WsLogin sends a login request to websocket to enable access to authenticated endpoints
func (o *OKGroup) WsLogin() error {
o.Websocket.SetCanUseAuthenticatedEndpoints(true)
utcTime := time.Now().UTC()
unixTime := utcTime.Unix()
unixTime := time.Now().UTC().Unix()
signPath := "/users/self/verify"
hmac := crypto.GetHMAC(crypto.HashSHA256,
[]byte(fmt.Sprintf("%v", unixTime)+http.MethodGet+signPath),
[]byte(o.API.Credentials.Secret))
[]byte(strconv.FormatInt(unixTime, 10)+http.MethodGet+signPath),
[]byte(o.API.Credentials.Secret),
)
base64 := crypto.Base64Encode(hmac)
request := WebsocketEventRequest{
Operation: "login",
Arguments: []string{o.API.Credentials.Key,
Arguments: []string{
o.API.Credentials.Key,
o.API.Credentials.ClientID,
fmt.Sprintf("%v", unixTime),
base64},
strconv.FormatInt(unixTime, 10),
base64,
},
}
err := o.WebsocketConn.SendMessage(request)
if err != nil {
@@ -470,7 +472,7 @@ func (o *OKGroup) wsProcessCandles(response *WebsocketDataResponse) {
timeData, err := time.Parse(time.RFC3339Nano,
response.Data[i].WebsocketCandleResponse.Candle[0])
if err != nil {
log.Warnf(log.ExchangeSys,
log.Errorf(log.ExchangeSys,
"%v Time data could not be parsed: %v",
o.Name,
response.Data[i].Candle[0])

View File

@@ -236,7 +236,7 @@ func (o *OKGroup) GetFundingHistory() (resp []exchange.FundHistory, err error) {
ExchangeName: o.Name,
Status: OrderStatus[accountWithdrawlHistory[i].Status],
Timestamp: accountWithdrawlHistory[i].Timestamp,
TransferID: accountWithdrawlHistory[i].Txid,
TransferID: accountWithdrawlHistory[i].TransactionID,
TransferType: "withdrawal",
})
}
@@ -255,11 +255,11 @@ func (o *OKGroup) SubmitOrder(s *order.Submit) (resp order.SubmitResponse, err e
return resp, err
}
request := PlaceSpotOrderRequest{
request := PlaceOrderRequest{
ClientOID: s.ClientID,
InstrumentID: o.FormatExchangeCurrency(s.Pair, asset.Spot).String(),
Side: strings.ToLower(s.OrderSide.String()),
Type: strings.ToLower(s.OrderType.String()),
Side: s.OrderSide.Lower(),
Type: s.OrderType.Lower(),
Size: strconv.FormatFloat(s.Amount, 'f', -1, 64),
}
if s.OrderType == order.Limit {

View File

@@ -129,25 +129,27 @@ func (p *Poloniex) GetOrderbook(currencyPair string, depth int) (OrderbookAll, e
return oba, err
}
for currency, orderbook := range resp.Data {
ob := Orderbook{}
var ob Orderbook
for x := range orderbook.Asks {
data := orderbook.Asks[x]
price, err := strconv.ParseFloat(data[0].(string), 64)
price, err := strconv.ParseFloat(orderbook.Asks[x][0].(string), 64)
if err != nil {
return oba, err
}
amount := data[1].(float64)
ob.Asks = append(ob.Asks, OrderbookItem{Price: price, Amount: amount})
ob.Asks = append(ob.Asks, OrderbookItem{
Price: price,
Amount: orderbook.Asks[x][1].(float64),
})
}
for x := range orderbook.Bids {
data := orderbook.Bids[x]
price, err := strconv.ParseFloat(data[0].(string), 64)
price, err := strconv.ParseFloat(orderbook.Bids[x][0].(string), 64)
if err != nil {
return oba, err
}
amount := data[1].(float64)
ob.Bids = append(ob.Bids, OrderbookItem{Price: price, Amount: amount})
ob.Asks = append(ob.Asks, OrderbookItem{
Price: price,
Amount: orderbook.Bids[x][1].(float64),
})
}
oba.Data[currency] = Orderbook{Bids: ob.Bids, Asks: ob.Asks}
}

View File

@@ -14,6 +14,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wsorderbook"
@@ -186,11 +187,11 @@ func (p *Poloniex) WsHandleData() {
trade.Symbol = currencyIDMap[chanID]
trade.TradeID, _ = strconv.ParseInt(dataL3[1].(string), 10, 64)
// 1 for buy 0 for sell
side := "buy"
side := order.Buy
if dataL3[2].(float64) != 1 {
side = "sell"
side = order.Sell
}
trade.Side = side
trade.Side = side.Lower()
trade.Volume, err = strconv.ParseFloat(dataL3[3].(string), 64)
if err != nil {
p.Websocket.DataHandler <- err

View File

@@ -296,21 +296,18 @@ func (p *Poloniex) UpdateOrderbook(currencyPair currency.Pair, assetType asset.I
var obItems []orderbook.Item
for y := range data.Bids {
obData := data.Bids[y]
obItems = append(obItems,
orderbook.Item{Amount: obData.Amount, Price: obData.Price})
obItems = append(obItems, orderbook.Item{
Amount: data.Bids[y].Amount, Price: data.Bids[y].Price})
}
orderBook.Bids = obItems
obItems = []orderbook.Item{}
for y := range data.Asks {
obData := data.Asks[y]
obItems = append(obItems,
orderbook.Item{Amount: obData.Amount, Price: obData.Price})
obItems = append(obItems, orderbook.Item{
Amount: data.Asks[y].Amount, Price: data.Asks[y].Price})
}
orderBook.Pair = x
orderBook.Asks = obItems
orderBook.Pair = x
orderBook.ExchangeName = p.Name
orderBook.AssetType = assetType
@@ -350,8 +347,7 @@ func (p *Poloniex) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (p *Poloniex) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.
@@ -507,7 +503,7 @@ func (p *Poloniex) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail,
orderSide := order.Side(strings.ToUpper(resp.Data[key][i].Type))
orderDate, err := time.Parse(poloniexDateLayout, resp.Data[key][i].Date)
if err != nil {
log.Warnf(log.ExchangeSys,
log.Errorf(log.ExchangeSys,
"Exchange %v Func %v Order %v Could not parse date to unix with value of %v",
p.Name,
"GetActiveOrders",
@@ -554,7 +550,7 @@ func (p *Poloniex) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail,
orderDate, err := time.Parse(poloniexDateLayout,
resp.Data[key][i].Date)
if err != nil {
log.Warnf(log.ExchangeSys,
log.Errorf(log.ExchangeSys,
"Exchange %v Func %v Order %v Could not parse date to unix with value of %v",
p.Name,
"GetActiveOrders",

View File

@@ -25,6 +25,7 @@ var Exchanges = []string{
"btc markets",
"btse",
"coinbasepro",
"coinbene",
"coinut",
"exmo",
"gateio",

View File

@@ -299,8 +299,7 @@ func (y *Yobit) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (y *Yobit) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.

View File

@@ -268,23 +268,24 @@ func (z *ZB) FetchOrderbook(p currency.Pair, assetType asset.Item) (orderbook.Ba
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (z *ZB) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderbook.Base, error) {
var orderBook orderbook.Base
currency := z.FormatExchangeCurrency(p, assetType).String()
orderbookNew, err := z.GetOrderbook(currency)
orderbookNew, err := z.GetOrderbook(z.FormatExchangeCurrency(p,
assetType).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]})
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
Amount: orderbookNew.Bids[x][1],
Price: orderbookNew.Bids[x][0],
})
}
for x := range orderbookNew.Asks {
data := orderbookNew.Asks[x]
orderBook.Asks = append(orderBook.Asks,
orderbook.Item{Amount: data[1], Price: data[0]})
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
Amount: orderbookNew.Asks[x][1],
Price: orderbookNew.Asks[x][0],
})
}
orderBook.Pair = p
@@ -338,8 +339,7 @@ func (z *ZB) GetAccountInfo() (exchange.AccountInfo, error) {
// GetFundingHistory returns funding history, deposits and
// withdrawals
func (z *ZB) GetFundingHistory() ([]exchange.FundHistory, error) {
var fundHistory []exchange.FundHistory
return fundHistory, common.ErrFunctionNotSupported
return nil, common.ErrFunctionNotSupported
}
// GetExchangeHistory returns historic trade data since exchange opening.