Coinbene: Add swap endpoints and code cleanup/bugfixes (#403)

* Start Coinbene SWAP implementation

* Flesh out more API endpoints

* Code cleanup

* Add more endpoints, bug fixes and order validation checks

* More endpoints, tests and bugfixes

* Remove omitempty for enabled/available pairs
This commit is contained in:
Adrian Gallagher
2019-12-18 17:36:07 +11:00
committed by GitHub
parent edc07f7839
commit 467d8d91a2
9 changed files with 1797 additions and 502 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
)
@@ -15,7 +16,8 @@ const (
testAPIKey = ""
testAPISecret = ""
canManipulateRealOrders = false
btcusdt = "BTC/USDT"
spotTestPair = "BTC/USDT"
swapTestPair = "BTCUSDT"
)
var c Coinbene
@@ -48,30 +50,6 @@ func areTestAPIKeysSet() bool {
return c.AllowAuthenticatedRequest()
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := c.GetTicker(btcusdt)
if err != nil {
t.Error(err)
}
}
func TestGetOrderbook(t *testing.T) {
t.Parallel()
_, err := c.GetOrderbook(btcusdt, 100)
if err != nil {
t.Error(err)
}
}
func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := c.GetTrades(btcusdt)
if err != nil {
t.Error(err)
}
}
func TestGetAllPairs(t *testing.T) {
t.Parallel()
_, err := c.GetAllPairs()
@@ -82,18 +60,53 @@ func TestGetAllPairs(t *testing.T) {
func TestGetPairInfo(t *testing.T) {
t.Parallel()
_, err := c.GetPairInfo(btcusdt)
_, err := c.GetPairInfo(spotTestPair)
if err != nil {
t.Error(err)
}
}
func TestGetUserBalance(t *testing.T) {
func TestGetOrderbook(t *testing.T) {
t.Parallel()
_, err := c.GetOrderbook(spotTestPair, 100)
if err != nil {
t.Error(err)
}
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := c.GetTicker(spotTestPair)
if err != nil {
t.Error(err)
}
}
func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := c.GetTrades(spotTestPair)
if err != nil {
t.Error(err)
}
}
func TestGetAcounntBalances(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := c.GetUserBalance()
_, err := c.GetAccountBalances()
if err != nil {
t.Error(err)
}
}
func TestGetAccountAssetBalance(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := c.GetAccountAssetBalance(currency.BTC.String())
if err != nil {
t.Error(err)
}
@@ -104,29 +117,38 @@ func TestPlaceOrder(t *testing.T) {
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.PlaceOrder(1, 1, btcusdt, order.Buy.Lower(), "")
_, err := c.PlaceSpotOrder(
1,
1,
spotTestPair,
order.Buy.Lower(),
order.Limit.Lower(),
"Sup3rAw3s0m3Cl13ntiDH",
0,
)
if err != nil {
t.Error(err)
}
}
func TestFetchOrderInfo(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := c.FetchOrderInfo("adfjashjgsag")
if err != nil {
t.Error(err)
}
}
func TestRemoveOrder(t *testing.T) {
func TestPlaceOrders(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.RemoveOrder("adfjashjgsag")
_, err := c.PlaceSpotOrders(
[]PlaceOrderRequest{
{
1,
1,
spotTestPair,
order.Buy.Lower(),
order.Limit.Lower(),
"Sup3rAw3s0m3Cl13ntiDH",
0,
},
})
if err != nil {
t.Error(err)
}
@@ -137,7 +159,7 @@ func TestFetchOpenOrders(t *testing.T) {
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := c.FetchOpenOrders(btcusdt)
_, err := c.FetchOpenSpotOrders(spotTestPair)
if err != nil {
t.Error(err)
}
@@ -148,7 +170,52 @@ func TestFetchClosedOrders(t *testing.T) {
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := c.FetchClosedOrders(btcusdt, "")
_, err := c.FetchClosedOrders(spotTestPair, "")
if err != nil {
t.Error(err)
}
}
func TestFetchOrderInfo(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := c.FetchSpotOrderInfo("adfjashjgsag")
if err != nil {
t.Error(err)
}
}
func TestGetSpotOrderFills(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := c.GetSpotOrderFills("1912131427156307968")
if err != nil {
t.Error(err)
}
}
func TestCancelSpotOrder(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.CancelSpotOrder("adfjashjgsag")
if err != nil {
t.Error(err)
}
}
func TestCancelSpotOrders(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.CancelSpotOrders([]string{"578639816552972288", "578639902896914432"})
if err != nil {
t.Error(err)
}
@@ -157,7 +224,11 @@ func TestFetchClosedOrders(t *testing.T) {
func TestUpdateTicker(t *testing.T) {
t.Parallel()
cp := currency.NewPairWithDelimiter("BTC", "USDT", "/")
_, err := c.UpdateTicker(cp, "spot")
_, err := c.UpdateTicker(cp, asset.Spot)
if err != nil {
t.Error(err)
}
_, err = c.UpdateTicker(cp, asset.PerpetualSwap)
if err != nil {
t.Error(err)
}
@@ -177,7 +248,203 @@ func TestGetAccountInfo(t *testing.T) {
func TestUpdateOrderbook(t *testing.T) {
t.Parallel()
cp := currency.NewPairWithDelimiter("BTC", "USDT", "/")
_, err := c.UpdateOrderbook(cp, "spot")
_, err := c.UpdateOrderbook(cp, asset.Spot)
if err != nil {
t.Error(err)
}
_, err = c.UpdateOrderbook(cp, asset.PerpetualSwap)
if err != nil {
t.Error(err)
}
}
func TestGetSwapTickers(t *testing.T) {
t.Parallel()
_, err := c.GetSwapTickers()
if err != nil {
t.Error(err)
}
}
func TestGetSwapTicker(t *testing.T) {
t.Parallel()
_, err := c.GetSwapTicker(swapTestPair)
if err != nil {
t.Error(err)
}
}
func TestGetSwapOrderbook(t *testing.T) {
t.Parallel()
_, err := c.GetSwapOrderbook(swapTestPair, 100)
if err != nil {
t.Error(err)
}
}
func TestGetSwapKlines(t *testing.T) {
t.Parallel()
_, err := c.GetSwapKlines(swapTestPair,
"1573184608",
"1573184808",
"1")
if err != nil {
t.Error(err)
}
}
func TestGetSwapTrades(t *testing.T) {
t.Parallel()
_, err := c.GetSwapTrades(swapTestPair, 10)
if err != nil {
t.Error(err)
}
}
func TestGetSwapAccountInfo(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := c.GetSwapAccountInfo()
if err != nil {
t.Error(err)
}
}
func TestGetSwapPositions(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := c.GetSwapPositions(swapTestPair)
if err != nil {
t.Error(err)
}
}
func TestPlaceSwapOrder(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.PlaceSwapOrder(swapTestPair,
order.Buy.Lower(),
"limit",
"fixed",
"12345",
1,
1,
2)
if err != nil {
t.Error(err)
}
}
func TestCancelSwapOrder(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.CancelSwapOrder("1337")
if err != nil {
t.Error(err)
}
}
func TestGetOpenSwapOrders(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.GetSwapOpenOrders(swapTestPair, 0, 0)
if err != nil {
t.Error(err)
}
}
func TestGetSwapOpenOrdersByPage(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.GetSwapOpenOrdersByPage(swapTestPair, 0)
if err != nil {
t.Error(err)
}
}
func TestGetSwapOrderInfo(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.GetSwapOrderInfo("1337")
if err != nil {
t.Error(err)
}
}
func TestGetSwapOrderHistory(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.GetSwapOrderHistory("", "", swapTestPair, 1, 10, "", "")
if err != nil {
t.Error(err)
}
}
func TestGetSwapOrderHistoryByOrderID(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.GetSwapOrderHistoryByOrderID("", "", swapTestPair, "", 0)
if err != nil {
t.Error(err)
}
}
func TestCancelSwapOrders(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.CancelSwapOrders([]string{"578639816552972288", "578639902896914432"})
if err != nil {
t.Error(err)
}
}
func TestGetSwapOrderFills(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.GetSwapOrderFills(swapTestPair, "5807143157122003", 580714315825905664)
if err != nil {
t.Error(err)
}
}
func TestGetSwapFundingRates(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := c.GetSwapFundingRates(1, 2)
if err != nil {
t.Error(err)
}

View File

@@ -1,5 +1,11 @@
package coinbene
import (
"time"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
)
// TickerData stores ticker data
type TickerData struct {
Symbol string `json:"symbol"`
@@ -11,35 +17,35 @@ type TickerData struct {
DailyVolume float64 `json:"volume24h,string"`
}
// TickerResponse stores ticker response data
type TickerResponse struct {
Code int64 `json:"code"`
Message string `json:"message"`
TickerData `json:"data"`
// OrderbookItem stores an individual orderbook item
type OrderbookItem struct {
Price float64
Amount float64
Count int64
}
// Orderbook stores orderbook info
// Orderbook stores the orderbook data
type Orderbook struct {
Asks [][]string `json:"asks"`
Bids [][]string `json:"bids"`
Bids []OrderbookItem
Asks []OrderbookItem
Symbol string
Time time.Time
}
// OrderbookResponse stores data from fetched orderbooks
type OrderbookResponse struct {
Code int64 `json:"code"`
Message string `json:"message"`
Orderbook `json:"data"`
// TradeItem stores a single trade
type TradeItem struct {
CurrencyPair string
Price float64
Volume float64
Direction string
TradeTime time.Time
}
// TradeResponse stores trade data
type TradeResponse struct {
Code int64 `json:"code"`
Message string `json:"message"`
Trades [][]string `json:"data"`
}
// Trades stores trade data
type Trades []TradeItem
// AllPairData stores pair data
type AllPairData struct {
// PairData stores pair data
type PairData struct {
Symbol string `json:"symbol"`
BaseAsset string `json:"baseAsset"`
QuoteAsset string `json:"quoteAsset"`
@@ -52,20 +58,6 @@ type AllPairData struct {
PriceFluctuation float64 `json:"priceFluctuation,string"`
}
// AllPairResponse stores data for all pairs enabled on exchange
type AllPairResponse struct {
Code int64 `json:"code"`
Message string `json:"message"`
Data []AllPairData `json:"data"`
}
// PairResponse stores data for a single queried pair
type PairResponse struct {
Code int64 `json:"code"`
Message string `json:"message"`
Data AllPairData `json:"data"`
}
// UserBalanceData stores user balance data
type UserBalanceData struct {
Asset string `json:"asset"`
@@ -74,24 +66,25 @@ type UserBalanceData struct {
Total float64 `json:"total,string"`
}
// UserBalanceResponse stores user balance data
type UserBalanceResponse struct {
Code int64 `json:"code"`
Message string `json:"message"`
Data []UserBalanceData `json:"data"`
// PlaceOrderRequest places an order request
type PlaceOrderRequest struct {
Price float64
Quantity float64
Symbol string
Direction string
OrderType string
ClientID string
Notional int
}
// PlaceOrderResponse stores data for a placed order
type PlaceOrderResponse struct {
Code int64 `json:"code"`
Message string `json:"message"`
Status string `json:"status"`
Timestamp int64 `json:"timestamp"`
OrderID string `json:"orderid"`
// CancelOrdersResponse stores data for a cancelled order
type CancelOrdersResponse struct {
OrderID string `json:"orderId"`
Message string `json:"message"`
}
// OrderInfoData stores order info
type OrderInfoData struct {
// OrderInfo stores order info
type OrderInfo struct {
OrderID string `json:"orderId"`
BaseAsset string `json:"baseAsset"`
QuoteAsset string `json:"quoteAsset"`
@@ -100,7 +93,7 @@ type OrderInfoData struct {
Amount float64 `json:"amout,string"`
FilledAmount float64 `json:"filledAmount"`
TakerRate float64 `json:"takerFeeRate,string"`
MakerRate float64 `json:"makerRate,string"`
MakerRate float64 `json:"makerFeeRate,string"`
AvgPrice float64 `json:"avgPrice,string"`
OrderPrice float64 `json:"orderPrice,string"`
OrderStatus string `json:"orderStatus"`
@@ -108,33 +101,19 @@ type OrderInfoData struct {
TotalFee float64 `json:"totalFee"`
}
// OrderInfoResponse stores orderinfo data
type OrderInfoResponse struct {
Order OrderInfoData `json:"data"`
Code int64 `json:"code"`
Message string `json:"message"`
// OrderFills stores the fill info
type OrderFills struct {
Price float64 `json:"price,string"`
Quantity float64 `json:"quantity,string"`
Amount float64 `json:"amount,string"`
Fee float64 `json:"fee,string"`
Direction string `json:"direction"`
TradeTime time.Time `json:"tradeTime"`
FeeByConi float64 `json:"feeByConi,string"`
}
// RemoveOrderResponse stores data for the remove request
type RemoveOrderResponse struct {
Code int64 `json:"code"`
Message string `json:"message"`
OrderID string `json:"data"`
}
// OpenOrderResponse stores data for open orders
type OpenOrderResponse struct {
Code int64 `json:"code"`
Message string `json:"message"`
OpenOrders []OrderInfoData `json:"data"`
}
// ClosedOrderResponse stores data for closed orders
type ClosedOrderResponse struct {
Code int64 `json:"code"`
Message string `json:"message"`
Data []OrderInfoData `json:"data"`
}
// OrdersInfo stores a collection of orders
type OrdersInfo []OrderInfo
// WsSub stores subscription data
type WsSub struct {
@@ -144,17 +123,17 @@ type WsSub struct {
// WsTickerData stores websocket ticker data
type WsTickerData struct {
Symbol string `json:"symbol"`
LastPrice float64 `json:"lastPrice,string"`
MarkPrice float64 `json:"markPrice,string"`
BestAskPrice float64 `json:"bestAskPrice,string"`
BestBidPrice float64 `json:"bestBidPrice,string"`
BestAskVolume float64 `json:"bestAskVolume,string"`
BestBidVolume float64 `json:"bestBidVolume,string"`
High24h float64 `json:"high24h,string"`
Low24h float64 `json:"low24h,string"`
Volume24h float64 `json:"volume,string"`
Timestamp string `json:"timestamp"`
Symbol string `json:"symbol"`
LastPrice float64 `json:"lastPrice,string"`
MarkPrice float64 `json:"markPrice,string"`
BestAskPrice float64 `json:"bestAskPrice,string"`
BestBidPrice float64 `json:"bestBidPrice,string"`
BestAskVolume float64 `json:"bestAskVolume,string"`
BestBidVolume float64 `json:"bestBidVolume,string"`
High24h float64 `json:"high24h,string"`
Low24h float64 `json:"low24h,string"`
Volume24h float64 `json:"volume24h,string"`
Timestamp time.Time `json:"timestamp"`
}
// WsTicker stores websocket ticker
@@ -169,15 +148,6 @@ type WsTradeList struct {
Data [][]string `json:"data"`
}
// WsOrderbook stores websocket orderbook data
type WsOrderbook struct {
Topic string `json:"topic"`
Action string `json:"action"`
Data []Orderbook `json:"data"`
Version int64 `json:"version,string"`
Timestamp string `json:"timestamp"`
}
// WsKline stores websocket kline data
type WsKline struct {
Topic string `json:"topic"`
@@ -186,11 +156,11 @@ type WsKline struct {
// WsUserData stores websocket user data
type WsUserData struct {
Asset string `json:"string"`
Available float64 `json:"availableBalance"`
Locked float64 `json:"frozenBalance"`
Total float64 `json:"balance"`
Timestamp string `json:"timestamp"`
Asset string `json:"string"`
Available float64 `json:"availableBalance"`
Locked float64 `json:"frozenBalance"`
Total float64 `json:"balance"`
Timestamp time.Time `json:"timestamp"`
}
// WsUserInfo stores websocket user info
@@ -201,18 +171,18 @@ type WsUserInfo struct {
// WsPositionData stores websocket info on user's position
type WsPositionData struct {
AvailableQuantity float64 `json:"availableQuantity"`
AveragePrice float64 `json:"avgPrice"`
Leverage float64 `json:"leverage"`
LiquidationPrice float64 `json:"liquidationPrice"`
MarkPrice float64 `json:"markPrice"`
PositionMargin float64 `json:"positionMargin"`
Quantity float64 `json:"quantity"`
RealisedPNL float64 `json:"realisedPnl"`
Side string `json:"side"`
Symbol string `json:"symbol"`
MarginMode int64 `json:"marginMode"`
CreateTime string `json:"createTime"`
AvailableQuantity float64 `json:"availableQuantity"`
AveragePrice float64 `json:"avgPrice"`
Leverage float64 `json:"leverage"`
LiquidationPrice float64 `json:"liquidationPrice"`
MarkPrice float64 `json:"markPrice"`
PositionMargin float64 `json:"positionMargin"`
Quantity float64 `json:"quantity"`
RealisedPNL float64 `json:"realisedPnl"`
Side string `json:"side"`
Symbol string `json:"symbol"`
MarginMode int64 `json:"marginMode"`
CreateTime time.Time `json:"createTime"`
}
// WsPosition stores websocket info on user's positions
@@ -223,22 +193,22 @@ type WsPosition struct {
// WsOrderData stores websocket user order data
type WsOrderData struct {
OrderID string `json:"orderId"`
Direction string `json:"direction"`
Leverage float64 `json:"leverage"`
Symbol string `json:"symbol"`
OrderType string `json:"orderType"`
Quantity float64 `json:"quantity"`
OrderPrice float64 `json:"orderPrice"`
OrderValue float64 `json:"orderValue"`
Fee float64 `json:"fee"`
FilledQuantity float64 `json:"filledQuantity"`
AveragePrice float64 `json:"averagePrice"`
OrderTime string `json:"orderTime"`
Status string `json:"status"`
LastFillQuantity float64 `json:"lastFillQuantity"`
LastFillPrice float64 `json:"lastFillPrice"`
LastFillTime string `json:"lastFillTime"`
OrderID string `json:"orderId"`
Direction string `json:"direction"`
Leverage float64 `json:"leverage"`
Symbol string `json:"symbol"`
OrderType string `json:"orderType"`
Quantity float64 `json:"quantity"`
OrderPrice float64 `json:"orderPrice"`
OrderValue float64 `json:"orderValue"`
Fee float64 `json:"fee"`
FilledQuantity float64 `json:"filledQuantity"`
AveragePrice float64 `json:"averagePrice"`
OrderTime time.Time `json:"orderTime"`
Status string `json:"status"`
LastFillQuantity float64 `json:"lastFillQuantity"`
LastFillPrice float64 `json:"lastFillPrice"`
LastFillTime time.Time `json:"lastFillTime"`
}
// WsUserOrders stores websocket user orders' data
@@ -246,3 +216,141 @@ type WsUserOrders struct {
Topic string `json:"topic"`
Data []WsOrderData `json:"data"`
}
// SwapTicker stores the swap ticker info
type SwapTicker struct {
LastPrice float64 `json:"lastPrice,string"`
MarkPrice float64 `json:"markPrice,string"`
BestAskPrice float64 `json:"bestAskPrice,string"`
BestBidPrice float64 `json:"bestBidPrice,string"`
High24Hour float64 `json:"high24h,string"`
Low24Hour float64 `json:"low24h,string"`
Volume24Hour float64 `json:"volume24h,string"`
BestAskVolume float64 `json:"bestAskVolume,string"`
BestBidVolume float64 `json:"bestBidVolume,string"`
Turnover float64 `json:"turnover,string"`
Timestamp time.Time `json:"timeStamp"`
}
// SwapTickers stores a map of swap tickers
type SwapTickers map[string]SwapTicker
// SwapKlineItem stores an individual kline data item
type SwapKlineItem struct {
Time time.Time
Open float64
Close float64
High float64
Low float64
Volume float64
Turnover float64
BuyVolume float64
BuyTurnover float64
}
// SwapKlines stores an array of kline data
type SwapKlines []SwapKlineItem
// SwapTrade stores an individual trade
type SwapTrade struct {
Price float64
Side order.Side
Volume float64
Time time.Time
}
// SwapTrades stores an array of swap trades
type SwapTrades []SwapTrade
// SwapAccountInfo returns the swap account balance info
type SwapAccountInfo struct {
AvailableBalance float64 `json:"availableBalance,string"`
FrozenBalance float64 `json:"frozenBalance,string"`
MarginBalance float64 `json:"marginBalance,string"`
MarginRate float64 `json:"marginRate,string"`
Balance float64 `json:"balance,string"`
UnrealisedPNL float64 `json:"unrealisedPnl,string"`
}
// SwapPosition stores a single swap position's data
type SwapPosition struct {
AvailableQuantity float64 `json:"availableQuantity,string"`
AveragePrice float64 `json:"averagePrice,string"`
CreateTime time.Time `json:"createTime"`
DeleveragePercentile int `json:"deleveragePercentile,string"`
Leverage int `json:"leverage,string"`
LiquidationPrice float64 `json:"liquidationPrice,string"`
MarkPrice float64 `json:"markPrice,string"`
PositionMargin float64 `json:"positionMargin,string"`
PositionValue float64 `json:"positionValue,string"`
Quantity float64 `json:"quantity,string"`
RateOfReturn float64 `json:"roe,string"`
Side string `json:"side"`
Symbol string `json:"symbol"`
UnrealisedProfitAndLoss float64 `json:"UnrealisedPnl,string"`
}
// SwapPositions stores a collection of swap positions
type SwapPositions []SwapPosition
// SwapPlaceOrderResponse stores the response data for placing a swap order
type SwapPlaceOrderResponse struct {
OrderID string `json:"orderId"`
ClientID string `json:"clientId"`
}
// SwapOrder stores the swap order data
type SwapOrder struct {
OrderID string `json:"orderId"`
Direction string `json:"direction"`
Leverage int `json:"leverage,string"`
OrderType string `json:"orderType"`
Quantitity float64 `json:"quantity,string"`
OrderPrice float64 `json:"orderPrice,string"`
OrderValue float64 `json:"orderValue,string"`
Fee float64 `json:"fee"`
FilledQuantity float64 `json:"filledQuantity,string"`
AveragePrice float64 `json:"averagePrice,string"`
OrderTime time.Time `json:"orderTime"`
Status string `json:"status"`
}
// SwapOrders stores a collection of swap orders
type SwapOrders []SwapOrder
// OrderCancellationResponse returns a list of cancel order status
type OrderCancellationResponse struct {
OrderID string `json:"orderId"`
Code int `json:"code,string"`
Message string `json:"message"`
}
// OrderPlacementResponse stores the order placement data
type OrderPlacementResponse OrderCancellationResponse
// SwapOrderFill stores a swap orders fill info
type SwapOrderFill struct {
Symbol string `json:"symbol"`
TradeTime time.Time `json:"tradeTime"`
TradeID int64 `json:"tradeId,string"`
OrderID int64 `json:"orderId,string"`
Price float64 `json:"price,string"`
Fee float64 `json:"fee,string"`
ExecType string `json:"execType"`
Side string `json:"side"`
Quantity float64 `json:"quantity,string"`
}
// SwapOrderFills stores a collection of swap order fills
type SwapOrderFills []SwapOrderFill
// SwapFundingRate stores a collection of funding rates
type SwapFundingRate struct {
Symbol string `json:"symbol"`
Side string `json:"side"`
MarkPrice float64 `json:"markPrice,string"`
PositionValue float64 `json:"positionValue,string"`
Fee float64 `json:"fee,string"`
FeeRate float64 `json:"feeRate,string"`
Leverage int64 `json:"leverage"`
}

View File

@@ -138,11 +138,14 @@ func (c *Coinbene) WsDataHandler() {
Last: ticker.Data[x].LastPrice,
High: ticker.Data[x].High24h,
Low: ticker.Data[x].Low24h,
Bid: ticker.Data[x].BestBidPrice,
Ask: ticker.Data[x].BestAskPrice,
Pair: currency.NewPairFromFormattedPairs(ticker.Data[x].Symbol,
c.GetEnabledPairs(asset.PerpetualSwap),
c.GetPairFormat(asset.PerpetualSwap, true)),
Exchange: c.Name,
AssetType: asset.PerpetualSwap,
Timestamp: ticker.Data[x].Timestamp,
}
}
case strings.Contains(result[topic].(string), "tradeList"):
@@ -182,13 +185,22 @@ func (c *Coinbene) WsDataHandler() {
Side: tradeList.Data[0][1],
}
case strings.Contains(result[topic].(string), "orderBook"):
var orderBook WsOrderbook
orderBook := struct {
Topic string `json:"topic"`
Action string `json:"action"`
Data []struct {
Bids [][]string `json:"bids"`
Asks [][]string `json:"asks"`
Version int64 `json:"version"`
Timestamp time.Time `json:"timestamp"`
} `json:"data"`
}{}
err = json.Unmarshal(stream.Raw, &orderBook)
if err != nil {
c.Websocket.DataHandler <- err
continue
}
p := strings.Replace(orderBook.Topic, "tradeList.", "", 1)
p := strings.Replace(orderBook.Topic, "orderBook.", "", 1)
cp := currency.NewPairFromFormattedPairs(p,
c.GetEnabledPairs(asset.PerpetualSwap),
c.GetPairFormat(asset.PerpetualSwap, true))
@@ -233,6 +245,7 @@ func (c *Coinbene) WsDataHandler() {
newOB.AssetType = asset.PerpetualSwap
newOB.Pair = cp
newOB.ExchangeName = c.Name
newOB.LastUpdated = orderBook.Data[0].Timestamp
err = c.Websocket.Orderbook.LoadSnapshot(&newOB)
if err != nil {
c.Websocket.DataHandler <- err
@@ -244,11 +257,12 @@ func (c *Coinbene) WsDataHandler() {
}
} else if orderBook.Action == "update" {
newOB := wsorderbook.WebsocketOrderbookUpdate{
Asks: asks,
Bids: bids,
Asset: asset.PerpetualSwap,
Pair: cp,
UpdateID: orderBook.Version,
Asks: asks,
Bids: bids,
Asset: asset.PerpetualSwap,
Pair: cp,
UpdateID: orderBook.Data[0].Version,
UpdateTime: orderBook.Data[0].Timestamp,
}
err = c.Websocket.Orderbook.Update(&newOB)
if err != nil {

View File

@@ -2,7 +2,6 @@ package coinbene
import (
"fmt"
"strconv"
"strings"
"sync"
"time"
@@ -56,8 +55,11 @@ func (c *Coinbene) SetDefaults() {
c.CurrencyPairs = currency.PairsManager{
AssetTypes: asset.Items{
asset.Spot,
asset.PerpetualSwap,
},
UseGlobalFormat: true,
}
c.CurrencyPairs.Store(asset.Spot, currency.PairStore{
RequestFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: "/",
@@ -66,12 +68,22 @@ func (c *Coinbene) SetDefaults() {
Uppercase: true,
Delimiter: "/",
},
}
})
c.CurrencyPairs.Store(asset.PerpetualSwap, currency.PairStore{
RequestFormat: &currency.PairFormat{
Uppercase: true,
},
ConfigFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: "/",
},
})
c.Features = exchange.Features{
Supports: exchange.FeaturesSupported{
REST: true,
Websocket: false, // Purposely disabled until SWAP is supported
Websocket: true,
RESTCapabilities: protocol.Features{
TickerFetching: true,
TradeFetching: true,
@@ -129,15 +141,6 @@ func (c *Coinbene) Setup(exch *config.ExchangeConfig) error {
return err
}
// TO-DO: Remove this once SWAP is supported
if exch.Features.Enabled.Websocket {
log.Warnf(log.ExchangeSys,
"%s websocket only supports SWAP which GoCryptoTrader currently "+
"does not. Disabling.\n",
c.Name)
exch.Features.Enabled.Websocket = false
}
err = c.Websocket.Setup(
&wshandler.WebsocketSetup{
Enabled: exch.Features.Enabled.Websocket,
@@ -150,6 +153,7 @@ func (c *Coinbene) Setup(exch *config.ExchangeConfig) error {
Connector: c.WsConnect,
Subscriber: c.Subscribe,
UnSubscriber: c.Unsubscribe,
Features: &c.Features.Supports.WebsocketCapabilities,
})
if err != nil {
return err
@@ -211,14 +215,34 @@ func (c *Coinbene) Run() {
// FetchTradablePairs returns a list of exchange tradable pairs
func (c *Coinbene) FetchTradablePairs(a asset.Item) ([]string, error) {
pairs, err := c.GetAllPairs()
if err != nil {
return nil, err
if !c.SupportsAsset(a) {
return nil, fmt.Errorf("%s does not support asset type %s", c.Name, a)
}
var currencies []string
for x := range pairs.Data {
currencies = append(currencies, pairs.Data[x].Symbol)
switch a {
case asset.Spot:
pairs, err := c.GetAllPairs()
if err != nil {
return nil, err
}
for x := range pairs {
currencies = append(currencies, pairs[x].Symbol)
}
case asset.PerpetualSwap:
tickers, err := c.GetSwapTickers()
if err != nil {
return nil, err
}
for t := range tickers {
idx := strings.Index(t, currency.USDT.String())
if idx == 0 {
return nil, fmt.Errorf("%s SWAP currency does not contain USDT", c.Name)
}
currencies = append(currencies,
t[0:idx]+c.GetPairFormat(a, false).Delimiter+t[idx:])
}
}
return currencies, nil
}
@@ -226,38 +250,78 @@ func (c *Coinbene) FetchTradablePairs(a asset.Item) ([]string, error) {
// UpdateTradablePairs updates the exchanges available pairs and stores
// them
func (c *Coinbene) UpdateTradablePairs(forceUpdate bool) error {
pairs, err := c.FetchTradablePairs(asset.Spot)
if err != nil {
return err
assets := c.GetAssetTypes()
for x := range assets {
pairs, err := c.FetchTradablePairs(assets[x])
if err != nil {
return err
}
err = c.UpdatePairs(currency.NewPairsFromStrings(pairs),
assets[x], false, forceUpdate)
if err != nil {
return err
}
}
return c.UpdatePairs(currency.NewPairsFromStrings(pairs),
asset.Spot,
false,
forceUpdate)
return nil
}
// UpdateTicker updates and returns the ticker for a currency pair
func (c *Coinbene) UpdateTicker(p currency.Pair, assetType asset.Item) (*ticker.Price, error) {
tickerPrice := new(ticker.Price)
allPairs := c.GetEnabledPairs(assetType)
for x := range allPairs {
tempResp, err := c.GetTicker(c.FormatExchangeCurrency(allPairs[x],
assetType).String())
if err != nil {
return tickerPrice, err
resp := new(ticker.Price)
if !c.SupportsAsset(assetType) {
return nil,
fmt.Errorf("%s does not support asset type %s", c.Name, assetType)
}
switch assetType {
case asset.Spot:
allPairs := c.GetEnabledPairs(assetType)
for x := range allPairs {
tempResp, err := c.GetTicker(c.FormatExchangeCurrency(allPairs[x],
assetType).String())
if err != nil {
return nil, err
}
resp.Pair = allPairs[x]
resp.Last = tempResp.LatestPrice
resp.High = tempResp.DailyHigh
resp.Low = tempResp.DailyLow
resp.Bid = tempResp.BestBid
resp.Ask = tempResp.BestAsk
resp.Volume = tempResp.DailyVolume
resp.LastUpdated = time.Now()
err = ticker.ProcessTicker(c.Name, resp, assetType)
if err != nil {
return nil, err
}
}
tickerPrice.Pair = allPairs[x]
tickerPrice.Last = tempResp.TickerData.LatestPrice
tickerPrice.High = tempResp.TickerData.DailyHigh
tickerPrice.Low = tempResp.TickerData.DailyLow
tickerPrice.Bid = tempResp.TickerData.BestBid
tickerPrice.Ask = tempResp.TickerData.BestAsk
tickerPrice.Volume = tempResp.TickerData.DailyVolume
tickerPrice.LastUpdated = time.Now()
err = ticker.ProcessTicker(c.Name, tickerPrice, assetType)
case asset.PerpetualSwap:
tickers, err := c.GetSwapTickers()
if err != nil {
return tickerPrice, err
return nil, err
}
allPairs := c.GetEnabledPairs(assetType)
for x := range allPairs {
tick, ok := tickers[c.FormatExchangeCurrency(allPairs[x],
assetType).String()]
if !ok {
log.Warnf(log.ExchangeSys,
"%s SWAP ticker item was not found", c.Name)
continue
}
resp.Pair = allPairs[x]
resp.Last = tick.LastPrice
resp.High = tick.High24Hour
resp.Low = tick.Low24Hour
resp.Bid = tick.BestBidPrice
resp.Ask = tick.BestAskPrice
resp.Volume = tick.Volume24Hour
resp.LastUpdated = tick.Timestamp
err = ticker.ProcessTicker(c.Name, resp, assetType)
if err != nil {
return nil, err
}
}
}
return ticker.GetTicker(c.Name, p, assetType)
@@ -265,6 +329,11 @@ func (c *Coinbene) UpdateTicker(p currency.Pair, assetType asset.Item) (*ticker.
// FetchTicker returns the ticker for a currency pair
func (c *Coinbene) FetchTicker(p currency.Pair, assetType asset.Item) (*ticker.Price, error) {
if !c.SupportsAsset(assetType) {
return nil,
fmt.Errorf("%s does not support asset type %s", c.Name, assetType)
}
tickerNew, err := ticker.GetTicker(c.Name, p, assetType)
if err != nil {
return c.UpdateTicker(p, assetType)
@@ -274,6 +343,11 @@ func (c *Coinbene) FetchTicker(p currency.Pair, assetType asset.Item) (*ticker.P
// FetchOrderbook returns orderbook base on the currency pair
func (c *Coinbene) FetchOrderbook(currency currency.Pair, assetType asset.Item) (*orderbook.Base, error) {
if !c.SupportsAsset(assetType) {
return nil,
fmt.Errorf("%s does not support asset type %s", c.Name, assetType)
}
ob, err := orderbook.Get(c.Name, currency, assetType)
if err != nil {
return c.UpdateOrderbook(currency, assetType)
@@ -283,47 +357,56 @@ func (c *Coinbene) FetchOrderbook(currency currency.Pair, assetType asset.Item)
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (c *Coinbene) UpdateOrderbook(p currency.Pair, assetType asset.Item) (*orderbook.Base, error) {
orderBook := new(orderbook.Base)
tempResp, err := c.GetOrderbook(
c.FormatExchangeCurrency(p, assetType).String(),
100,
)
resp := new(orderbook.Base)
if !c.SupportsAsset(assetType) {
return nil,
fmt.Errorf("%s does not support asset type %s", c.Name, assetType)
}
var tempResp Orderbook
var err error
switch assetType {
case asset.Spot:
tempResp, err = c.GetOrderbook(
c.FormatExchangeCurrency(p, assetType).String(),
100, // TO-DO: Update this once we support configurable orderbook depth
)
case asset.PerpetualSwap:
tempResp, err = c.GetSwapOrderbook(
c.FormatExchangeCurrency(p, assetType).String(),
100, // TO-DO: Update this once we support configurable orderbook depth
)
}
if err != nil {
return orderBook, err
return nil, err
}
orderBook.ExchangeName = c.Name
orderBook.Pair = p
orderBook.AssetType = assetType
var amount, price float64
for i := range tempResp.Orderbook.Asks {
amount, err = strconv.ParseFloat(tempResp.Orderbook.Asks[i][1], 64)
if err != nil {
return orderBook, err
resp.ExchangeName = c.Name
resp.Pair = p
resp.AssetType = assetType
for x := range tempResp.Asks {
item := orderbook.Item{
Price: tempResp.Asks[x].Price,
Amount: tempResp.Asks[x].Amount,
}
price, err = strconv.ParseFloat(tempResp.Orderbook.Asks[i][0], 64)
if err != nil {
return orderBook, err
if assetType == asset.PerpetualSwap {
item.OrderCount = tempResp.Asks[x].Count
}
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
Price: price,
Amount: amount})
resp.Asks = append(resp.Asks, item)
}
for j := range tempResp.Orderbook.Bids {
amount, err = strconv.ParseFloat(tempResp.Orderbook.Bids[j][1], 64)
if err != nil {
return orderBook, err
for x := range tempResp.Bids {
item := orderbook.Item{
Price: tempResp.Bids[x].Price,
Amount: tempResp.Bids[x].Amount,
}
price, err = strconv.ParseFloat(tempResp.Orderbook.Bids[j][0], 64)
if err != nil {
return orderBook, err
if assetType == asset.PerpetualSwap {
item.OrderCount = tempResp.Bids[x].Count
}
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
Price: price,
Amount: amount})
resp.Bids = append(resp.Bids, item)
}
err = orderBook.Process()
err = resp.Process()
if err != nil {
return orderBook, err
return nil, err
}
return orderbook.Get(c.Name, p, assetType)
}
@@ -332,15 +415,15 @@ func (c *Coinbene) UpdateOrderbook(p currency.Pair, assetType asset.Item) (*orde
// Coinbene exchange
func (c *Coinbene) GetAccountInfo() (exchange.AccountInfo, error) {
var info exchange.AccountInfo
data, err := c.GetUserBalance()
balance, err := c.GetAccountBalances()
if err != nil {
return info, err
}
var account exchange.Account
for key := range data.Data {
c := currency.NewCode(data.Data[key].Asset)
hold := data.Data[key].Reserved
available := data.Data[key].Available
for key := range balance {
c := currency.NewCode(balance[key].Asset)
hold := balance[key].Reserved
available := balance[key].Available
account.Currencies = append(account.Currencies,
exchange.AccountCurrencyInfo{CurrencyName: c,
TotalValue: hold + available,
@@ -374,15 +457,17 @@ func (c *Coinbene) SubmitOrder(s *order.Submit) (order.SubmitResponse, error) {
fmt.Errorf("%s orderside is not supported by this exchange",
s.OrderSide)
}
if s.OrderType != order.Limit {
return resp, fmt.Errorf("only limit order is supported by this exchange")
}
tempResp, err := c.PlaceOrder(s.Price,
tempResp, err := c.PlaceSpotOrder(s.Price,
s.Amount,
c.FormatExchangeCurrency(s.Pair, asset.Spot).String(),
s.OrderSide.String(),
s.OrderType.String(),
s.ClientID)
s.ClientID,
0)
if err != nil {
return resp, err
}
@@ -399,27 +484,27 @@ func (c *Coinbene) ModifyOrder(action *order.Modify) (string, error) {
// CancelOrder cancels an order by its corresponding ID number
func (c *Coinbene) CancelOrder(order *order.Cancel) error {
_, err := c.RemoveOrder(order.OrderID)
_, err := c.CancelSpotOrder(order.OrderID)
return err
}
// CancelAllOrders cancels all orders associated with a currency pair
func (c *Coinbene) CancelAllOrders(orderCancellation *order.Cancel) (order.CancelAllResponse, error) {
var resp order.CancelAllResponse
tempMap := make(map[string]string)
orders, err := c.FetchOpenOrders(
orders, err := c.FetchOpenSpotOrders(
c.FormatExchangeCurrency(orderCancellation.CurrencyPair,
asset.Spot).String(),
)
if err != nil {
return resp, err
}
for x := range orders.OpenOrders {
_, err := c.RemoveOrder(orders.OpenOrders[x].OrderID)
tempMap := make(map[string]string)
for x := range orders {
_, err := c.CancelSpotOrder(orders[x].OrderID)
if err != nil {
tempMap[orders.OpenOrders[x].OrderID] = "Failed"
tempMap[orders[x].OrderID] = "Failed"
} else {
tempMap[orders.OpenOrders[x].OrderID] = "Success"
tempMap[orders[x].OrderID] = "Success"
}
}
resp.Status = tempMap
@@ -429,24 +514,24 @@ func (c *Coinbene) CancelAllOrders(orderCancellation *order.Cancel) (order.Cance
// GetOrderInfo returns information on a current open order
func (c *Coinbene) GetOrderInfo(orderID string) (order.Detail, error) {
var resp order.Detail
tempResp, err := c.FetchOrderInfo(orderID)
tempResp, err := c.FetchSpotOrderInfo(orderID)
if err != nil {
return resp, err
}
var t time.Time
resp.Exchange = c.Name
resp.ID = orderID
resp.CurrencyPair = currency.NewPairWithDelimiter(tempResp.Order.BaseAsset,
resp.CurrencyPair = currency.NewPairWithDelimiter(tempResp.BaseAsset,
"/",
tempResp.Order.QuoteAsset)
t, err = time.Parse(time.RFC3339, tempResp.Order.OrderTime)
tempResp.QuoteAsset)
t, err = time.Parse(time.RFC3339, tempResp.OrderTime)
if err != nil {
return resp, err
}
resp.Price = tempResp.Order.OrderPrice
resp.Price = tempResp.OrderPrice
resp.OrderDate = t
resp.ExecutedAmount = tempResp.Order.FilledAmount
resp.Fee = tempResp.Order.TotalFee
resp.ExecutedAmount = tempResp.FilledAmount
resp.Fee = tempResp.TotalFee
return resp, nil
}
@@ -480,47 +565,53 @@ func (c *Coinbene) GetWebsocket() (*wshandler.Websocket, error) {
// GetActiveOrders retrieves any orders that are active/open
func (c *Coinbene) GetActiveOrders(getOrdersRequest *order.GetOrdersRequest) ([]order.Detail, error) {
var resp []order.Detail
var tempResp order.Detail
var tempData OpenOrderResponse
if len(getOrdersRequest.Currencies) == 0 {
allPairs, err := c.GetAllPairs()
if err != nil {
return resp, err
return nil, err
}
for a := range allPairs.Data {
getOrdersRequest.Currencies = append(getOrdersRequest.Currencies, currency.NewPairFromString(allPairs.Data[a].Symbol))
for a := range allPairs {
getOrdersRequest.Currencies = append(getOrdersRequest.Currencies,
currency.NewPairFromString(allPairs[a].Symbol))
}
}
var err error
var resp []order.Detail
for x := range getOrdersRequest.Currencies {
tempData, err = c.FetchOpenOrders(
var tempData OrdersInfo
tempData, err = c.FetchOpenSpotOrders(
c.FormatExchangeCurrency(
getOrdersRequest.Currencies[x],
asset.Spot).String(),
)
if err != nil {
return resp, err
return nil, err
}
var t time.Time
for y := range tempData.OpenOrders {
for y := range tempData {
var tempResp order.Detail
tempResp.Exchange = c.Name
tempResp.CurrencyPair = getOrdersRequest.Currencies[x]
tempResp.OrderSide = order.Buy
if strings.EqualFold(tempData.OpenOrders[y].OrderType, order.Sell.String()) {
if strings.EqualFold(tempData[y].OrderType, order.Sell.String()) {
tempResp.OrderSide = order.Sell
}
t, err = time.Parse(time.RFC3339, tempData.OpenOrders[y].OrderTime)
var t time.Time
t, err = time.Parse(time.RFC3339, tempData[y].OrderTime)
if err != nil {
return resp, err
return nil, err
}
tempResp.OrderDate = t
tempResp.Status = order.Status(tempData.OpenOrders[y].OrderStatus)
tempResp.Price = tempData.OpenOrders[y].OrderPrice
tempResp.Amount = tempData.OpenOrders[y].Amount
tempResp.ExecutedAmount = tempData.OpenOrders[y].FilledAmount
tempResp.RemainingAmount = tempData.OpenOrders[y].Amount - tempData.OpenOrders[y].FilledAmount
tempResp.Fee = tempData.OpenOrders[y].TotalFee
tempResp.Status = order.Status(tempData[y].OrderStatus)
tempResp.Price = tempData[y].OrderPrice
tempResp.Amount = tempData[y].Amount
tempResp.ExecutedAmount = tempData[y].FilledAmount
tempResp.RemainingAmount = tempData[y].Amount - tempData[y].FilledAmount
tempResp.Fee = tempData[y].TotalFee
resp = append(resp, tempResp)
}
}
@@ -530,19 +621,21 @@ func (c *Coinbene) GetActiveOrders(getOrdersRequest *order.GetOrdersRequest) ([]
// GetOrderHistory retrieves account order information
// Can Limit response to specific order status
func (c *Coinbene) GetOrderHistory(getOrdersRequest *order.GetOrdersRequest) ([]order.Detail, error) {
var resp []order.Detail
var tempResp order.Detail
var tempData ClosedOrderResponse
if len(getOrdersRequest.Currencies) == 0 {
allPairs, err := c.GetAllPairs()
if err != nil {
return resp, err
return nil, err
}
for a := range allPairs.Data {
getOrdersRequest.Currencies = append(getOrdersRequest.Currencies, currency.NewPairFromString(allPairs.Data[a].Symbol))
for a := range allPairs {
getOrdersRequest.Currencies = append(getOrdersRequest.Currencies,
currency.NewPairFromString(allPairs[a].Symbol))
}
}
var resp []order.Detail
var tempData OrdersInfo
var err error
for x := range getOrdersRequest.Currencies {
tempData, err = c.FetchClosedOrders(
c.FormatExchangeCurrency(
@@ -551,27 +644,31 @@ func (c *Coinbene) GetOrderHistory(getOrdersRequest *order.GetOrdersRequest) ([]
"",
)
if err != nil {
return resp, err
return nil, err
}
var t time.Time
for y := range tempData.Data {
for y := range tempData {
var tempResp order.Detail
tempResp.Exchange = c.Name
tempResp.CurrencyPair = getOrdersRequest.Currencies[x]
tempResp.OrderSide = order.Buy
if strings.EqualFold(tempData.Data[y].OrderType, order.Sell.String()) {
if strings.EqualFold(tempData[y].OrderType, order.Sell.String()) {
tempResp.OrderSide = order.Sell
}
t, err = time.Parse(time.RFC3339, tempData.Data[y].OrderTime)
var t time.Time
t, err = time.Parse(time.RFC3339, tempData[y].OrderTime)
if err != nil {
return resp, err
return nil, err
}
tempResp.OrderDate = t
tempResp.Status = order.Status(tempData.Data[y].OrderStatus)
tempResp.Price = tempData.Data[y].OrderPrice
tempResp.Amount = tempData.Data[y].Amount
tempResp.ExecutedAmount = tempData.Data[y].FilledAmount
tempResp.RemainingAmount = tempData.Data[y].Amount - tempData.Data[y].FilledAmount
tempResp.Fee = tempData.Data[y].TotalFee
tempResp.Status = order.Status(tempData[y].OrderStatus)
tempResp.Price = tempData[y].OrderPrice
tempResp.Amount = tempData[y].Amount
tempResp.ExecutedAmount = tempData[y].FilledAmount
tempResp.RemainingAmount = tempData[y].Amount - tempData[y].FilledAmount
tempResp.Fee = tempData[y].TotalFee
resp = append(resp, tempResp)
}
}
@@ -590,9 +687,9 @@ func (c *Coinbene) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error
}
switch feeBuilder.IsMaker {
case true:
fee = feeBuilder.PurchasePrice * feeBuilder.Amount * tempData.Data.MakerFeeRate
fee = feeBuilder.PurchasePrice * feeBuilder.Amount * tempData.MakerFeeRate
case false:
fee = feeBuilder.PurchasePrice * feeBuilder.Amount * tempData.Data.TakerFeeRate
fee = feeBuilder.PurchasePrice * feeBuilder.Amount * tempData.TakerFeeRate
}
return fee, nil
}