Engine: BTC Markets V3 Updates (#385)

* Broken WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

* Errors Fixed

* PR Changes

* PR Changes

* PR Changes

* PR Changes

* PR Changes

* PR Changes

* PR Changes

* PR Changes

* PR Changes

* Offline Fees Fixed

* MarketCandles fixed and constants added

* t.log deleted

* Broken WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

WIP

* Errors Fixed

* PR Changes

* PR Changes

* PR Changes

* MarketCandles fixed and constants added

* t.log deleted

* Added BSB and Order Status

* WIP

* Websocket and BatchPlaceCancelOrder and other minor nits fixed

* Linter Issues Fixed

* Function Name Change

* Replacing b.GetMarkets with b.GetEnabledPairs

* Pagination param changes and PlaceCancelBatch changes

* Merge Conflicts WIP

* Linter Issue Fixed

* optional params fixed
This commit is contained in:
Adam
2019-12-04 11:53:35 +11:00
committed by Adrian Gallagher
parent 49b9eced66
commit a33ddcfa0a
13 changed files with 1710 additions and 1129 deletions

View File

@@ -73,7 +73,7 @@ type EndpointResponse struct {
// Bank contains all required data for a wrapper withdrawal request
type Bank struct {
BankAccountName string `json:"bankAccountName"`
BankAccountNumber float64 `json:"bankAccountNumber"`
BankAccountNumber string `json:"bankAccountNumber"`
BankAddress string `json:"bankAddress"`
BankCity string `json:"bankCity"`
BankCountry string `json:"bankCountry"`

View File

@@ -548,7 +548,7 @@ func (b *Bitfinex) WithdrawFIAT(withdrawalType, walletType string, withdrawReque
req["walletselected"] = walletType
req["amount"] = strconv.FormatFloat(withdrawRequest.Amount, 'f', -1, 64)
req["account_name"] = withdrawRequest.BankAccountName
req["account_number"] = strconv.FormatFloat(withdrawRequest.BankAccountNumber, 'f', -1, 64)
req["account_number"] = withdrawRequest.BankAccountNumber
req["bank_name"] = withdrawRequest.BankName
req["bank_address"] = withdrawRequest.BankAddress
req["bank_city"] = withdrawRequest.BankCity

View File

@@ -917,7 +917,7 @@ func TestWithdrawFiat(t *testing.T) {
Description: "WITHDRAW IT ALL",
},
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
BankAccountNumber: "12345",
BankAddress: "123 Fake St",
BankCity: "Tarry Town",
BankCountry: "Hyrule",
@@ -952,7 +952,7 @@ func TestWithdrawInternationalBank(t *testing.T) {
Description: "WITHDRAW IT ALL",
},
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
BankAccountNumber: "12345",
BankAddress: "123 Fake St",
BankCity: "Tarry Town",
BankCountry: "Hyrule",

View File

@@ -497,7 +497,7 @@ func TestWithdrawFiat(t *testing.T) {
Description: "WITHDRAW IT ALL",
},
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
BankAccountNumber: "12345",
BankCode: 123,
BankAddress: "123 Fake St",
BankCity: "Tarry Town",

View File

@@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"math"
"strconv"
"sync"
"time"
@@ -419,9 +418,7 @@ func (b *Bithumb) WithdrawFiatFunds(withdrawRequest *exchange.FiatWithdrawReques
return "", errors.New("only KRW is supported")
}
bankDetails := fmt.Sprintf("%v_%v", withdrawRequest.BankCode, withdrawRequest.BankName)
bankAccountNumber := strconv.FormatFloat(withdrawRequest.BankAccountNumber, 'f', -1, 64)
withdrawAmountInt := int64(withdrawRequest.Amount)
resp, err := b.RequestKRWWithdraw(bankDetails, bankAccountNumber, withdrawAmountInt)
resp, err := b.RequestKRWWithdraw(bankDetails, withdrawRequest.BankAccountNumber, int64(withdrawRequest.Amount))
if err != nil {
return "", err
}

View File

@@ -489,7 +489,7 @@ func TestWithdrawFiat(t *testing.T) {
Description: "WITHDRAW IT ALL",
},
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
BankAccountNumber: "12345",
BankAddress: "123 Fake St",
BankCity: "Tarry Town",
BankCountry: "AU",
@@ -527,7 +527,7 @@ func TestWithdrawInternationalBank(t *testing.T) {
Description: "WITHDRAW IT ALL",
},
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
BankAccountNumber: "12345",
BankAddress: "123 Fake St",
BankCity: "Tarry Town",
BankCountry: "AU",

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,13 @@
package btcmarkets
import (
"net/url"
"log"
"os"
"testing"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/config"
"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"
)
@@ -18,21 +18,23 @@ const (
apiKey = ""
apiSecret = ""
canManipulateRealOrders = false
BTCAUD = "BTC-AUD"
LTCAUD = "LTC-AUD"
ETHAUD = "ETH-AUD"
fakePair = "Fake-USDT"
bid = "bid"
)
func TestSetDefaults(t *testing.T) {
func TestMain(m *testing.M) {
b.SetDefaults()
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
err := cfg.LoadConfig("../../testdata/configtest.json", true)
if err != nil {
t.Fatal("BTC Markets load config error", err)
log.Fatal(err)
}
bConfig, err := cfg.GetExchangeConfig("BTC Markets")
if err != nil {
t.Error("BTC Markets Setup() init error")
log.Fatal(err)
}
bConfig.API.Credentials.Key = apiKey
bConfig.API.Credentials.Secret = apiSecret
@@ -40,29 +42,27 @@ func TestSetup(t *testing.T) {
err = b.Setup(bConfig)
if err != nil {
t.Fatal("BTC Markets setup error", err)
log.Fatal(err)
}
os.Exit(m.Run())
}
func areTestAPIKeysSet() bool {
return b.AllowAuthenticatedRequest()
}
func TestGetMarkets(t *testing.T) {
t.Parallel()
_, err := b.GetMarkets()
if err != nil {
t.Error("GetMarkets() error", err)
t.Error("GetTicker() error", err)
}
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := b.GetTicker("BTC", "AUD")
if err != nil {
t.Error("GetTicker() error", err)
}
}
func TestGetOrderbook(t *testing.T) {
t.Parallel()
_, err := b.GetOrderbook("BTC", "AUD")
_, err := b.GetTicker(BTCAUD)
if err != nil {
t.Error("GetOrderbook() error", err)
}
@@ -70,437 +70,412 @@ func TestGetOrderbook(t *testing.T) {
func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := b.GetTrades("BTC", "AUD", nil)
if err != nil {
t.Error("GetTrades() error", err)
}
val := url.Values{}
val.Set("since", "0")
_, err = b.GetTrades("BTC", "AUD", val)
_, err := b.GetTrades(BTCAUD, 0, 0, 5)
if err != nil {
t.Error("GetTrades() error", err)
}
}
func TestNewOrder(t *testing.T) {
func TestGetOrderbook(t *testing.T) {
t.Parallel()
_, err := b.NewOrder("AUD", "BTC", 0, 0, "Bid",
order.Limit.Lower(), "testTest")
if err == nil {
t.Error("NewOrder() Expected error")
_, err := b.GetOrderbook(BTCAUD, 2)
if err != nil {
t.Error("GetTrades() error", err)
}
}
func TestCancelExistingOrder(t *testing.T) {
func TestGetMarketCandles(t *testing.T) {
t.Parallel()
_, err := b.CancelExistingOrder([]int64{1337})
if err == nil {
t.Error("CancelExistingOrder() Expected error")
_, err := b.GetMarketCandles(BTCAUD, "", "", "", 0, 0, 5)
if err != nil {
t.Error(err)
}
}
func TestGetOrders(t *testing.T) {
func TestGetTickers(t *testing.T) {
t.Parallel()
_, err := b.GetOrders("AUD", "BTC", 10, 0, false)
if err == nil {
t.Error("GetOrders() Expected error")
}
_, err = b.GetOrders("AUD", "BTC", 10, 0, true)
if err == nil {
t.Error("GetOrders() Expected error")
temp := []string{BTCAUD, LTCAUD, ETHAUD}
_, err := b.GetTickers(temp)
if err != nil {
t.Error(err)
}
}
func TestGetOrderDetail(t *testing.T) {
func TestGetMultipleOrderbooks(t *testing.T) {
t.Parallel()
_, err := b.GetOrderDetail([]int64{1337})
if err == nil {
t.Error("GetOrderDetail() Expected error")
temp := []string{BTCAUD, LTCAUD, ETHAUD}
_, err := b.GetMultipleOrderbooks(temp)
if err != nil {
t.Error(err)
}
}
func TestGetServerTime(t *testing.T) {
t.Parallel()
_, err := b.GetServerTime()
if err != nil {
t.Error(err)
}
}
func TestGetAccountBalance(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetAccountBalance()
if err == nil {
t.Error("GetAccountBalance() Expected error")
if err != nil {
t.Error(err)
}
}
func TestWithdrawCrypto(t *testing.T) {
func TestGetTradingFees(t *testing.T) {
t.Parallel()
_, err := b.WithdrawCrypto(0, "BTC", "LOLOLOL")
if err == nil {
t.Error("WithdrawCrypto() Expected error")
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetTradingFees()
if err != nil {
t.Error(err)
}
}
func TestWithdrawAUD(t *testing.T) {
func TestGetTradeHistory(t *testing.T) {
t.Parallel()
_, err := b.WithdrawAUD("BLA", "1337", "blawest", "1336", 10000000)
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetTradeHistory(ETHAUD, "", -1, -1, -1)
if err != nil {
t.Error(err)
}
_, err = b.GetTradeHistory(BTCAUD, "", -1, -1, 1)
if err != nil {
t.Error(err)
}
_, err = b.GetTradeHistory(fakePair, "", -1, -1, -1)
if err == nil {
t.Error("WithdrawAUD() Expected error")
t.Error("expected an error due to invalid trading pair")
}
}
func TestGetTradeByID(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetTradeByID("4712043732")
if err != nil {
t.Error(err)
}
}
func TestNewOrder(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := b.NewOrder(BTCAUD, 100, 1, limit, bid, 0, 0, "", true, "", "")
if err != nil {
t.Error(err)
}
_, err = b.NewOrder(BTCAUD, 100, 1, "invalid", bid, 0, 0, "", true, "", "")
if err == nil {
t.Error("expected an error due to invalid ordertype")
}
_, err = b.NewOrder(BTCAUD, 100, 1, limit, "invalid", 0, 0, "", true, "", "")
if err == nil {
t.Error("expected an error due to invalid orderside")
}
}
func TestGetOrders(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetOrders("", -1, -1, 2, "")
if err != nil {
t.Error(err)
}
_, err = b.GetOrders(LTCAUD, -1, -1, -1, "open")
if err != nil {
t.Error(err)
}
}
func TestCancelOpenOrders(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
temp := []string{BTCAUD, LTCAUD}
_, err := b.CancelAllOpenOrdersByPairs(temp)
if err != nil {
t.Error(err)
}
temp = []string{BTCAUD, fakePair}
_, err = b.CancelAllOpenOrdersByPairs(temp)
if err == nil {
t.Error("expected an error due to invalid marketID")
}
}
func TestFetchOrder(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.FetchOrder("4477045999")
if err != nil {
t.Error(err)
}
_, err = b.FetchOrder("696969")
if err == nil {
t.Error(err)
}
}
func TestRemoveOrder(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := b.RemoveOrder("")
if err != nil {
t.Error(err)
}
}
func TestListWithdrawals(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.ListWithdrawals(-1, -1, -1)
if err != nil {
t.Error(err)
}
}
func TestGetWithdrawal(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetWithdrawal("4477381751")
if err != nil {
t.Error(err)
}
}
func TestListDeposits(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.ListDeposits(-1, -1, -1)
if err != nil {
t.Error(err)
}
}
func TestGetDeposit(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetDeposit("4476769607")
if err != nil {
t.Error(err)
}
}
func TestListTransfers(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.ListTransfers(-1, -1, -1)
if err != nil {
t.Error(err)
}
}
func TestGetTransfer(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetTransfer("4476769607")
if err != nil {
t.Error(err)
}
_, err = b.GetTransfer("6969696")
if err == nil {
t.Error("expected an error due to invalid transferID")
}
}
func TestFetchDepositAddress(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.FetchDepositAddress("LTC", -1, -1, -1)
if err != nil {
t.Error(err)
}
_, err = b.FetchDepositAddress(fakePair, -1, -1, -1)
if err != nil {
t.Error("expected an error due to invalid assetID")
}
}
func TestGetWithdrawalFees(t *testing.T) {
t.Parallel()
_, err := b.GetWithdrawalFees()
if err != nil {
t.Error(err)
}
}
func TestListAssets(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.ListAssets()
if err != nil {
t.Error(err)
}
}
func TestGetTransactions(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetTransactions("", -1, -1, -1)
if err != nil {
t.Error(err)
}
}
func TestCreateNewReport(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.CreateNewReport("TransactionReport", "json")
if err != nil {
t.Error(err)
}
}
func TestGetReport(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetReport("1kv38epne5v7lek9f18m60idg6")
if err != nil {
t.Error(err)
}
}
func TestRequestWithdaw(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
_, err := b.RequestWithdraw("BTC", 1, "sdjflajdslfjld", "", "", "", "")
if err == nil {
t.Error("expected an error due to invalid toAddress")
}
}
func TestBatchPlaceCancelOrders(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
var temp []PlaceBatch
o := PlaceBatch{
MarketID: BTCAUD,
Amount: 11000,
Price: 1,
OrderType: order.Limit.String(),
Side: bid,
}
_, err := b.BatchPlaceCancelOrders(nil, append(temp, o))
if err != nil {
t.Error(err)
}
}
func TestGetBatchTrades(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
temp := []string{"4477045999", "4477381751", "4476769607"}
_, err := b.GetBatchTrades(temp)
if err != nil {
t.Error(err)
}
}
func TestCancelBatchOrders(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
}
temp := []string{"4477045999", "4477381751", "4477381751"}
_, err := b.CancelBatchOrders(temp)
if err != nil {
t.Error(err)
}
}
func TestGetAccountInfo(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetAccountInfo()
if err == nil {
t.Error("GetAccountInfo() Expected error")
}
}
func TestGetFundingHistory(t *testing.T) {
_, err := b.GetFundingHistory()
if err == nil {
t.Error("GetAccountInfo() Expected error")
}
}
func TestCancelOrder(t *testing.T) {
_, err := b.CancelExistingOrder([]int64{1337})
if err == nil {
t.Error("CancelgOrder() Expected error")
}
}
func TestGetOrderInfo(t *testing.T) {
_, err := b.GetOrderInfo("1337")
if err == nil {
t.Error("GetOrderInfo() Expected error")
}
}
func setFeeBuilder() *exchange.FeeBuilder {
return &exchange.FeeBuilder{
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.LTC),
PurchasePrice: 1,
}
}
// TestGetFeeByTypeOfflineTradeFee logic test
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
var feeBuilder = setFeeBuilder()
b.GetFeeByType(feeBuilder)
if apiKey == "" || apiSecret == "" {
if feeBuilder.FeeType != exchange.OfflineTradeFee {
t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType)
}
} else {
if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee {
t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType)
}
}
}
func TestGetFee(t *testing.T) {
b.SetDefaults()
TestSetup(t)
var feeBuilder = setFeeBuilder()
if apiKey != "" || apiSecret != "" {
// CryptocurrencyTradeFee Fiat
feeBuilder = setFeeBuilder()
feeBuilder.Pair.Quote = currency.USD
if resp, err := b.GetFee(feeBuilder); resp != float64(0.00849999) || err != nil {
t.Error(err)
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0.00849999), resp)
}
// CryptocurrencyTradeFee Basic
feeBuilder = setFeeBuilder()
if resp, err := b.GetFee(feeBuilder); resp != float64(0.0022) || err != nil {
t.Error(err)
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0.0022), resp)
}
// CryptocurrencyTradeFee High quantity
feeBuilder = setFeeBuilder()
feeBuilder.Amount = 1000
feeBuilder.PurchasePrice = 1000
if resp, err := b.GetFee(feeBuilder); resp != float64(2200) || err != nil {
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(22000), resp)
t.Error(err)
}
// CryptocurrencyTradeFee IsMaker
feeBuilder = setFeeBuilder()
feeBuilder.IsMaker = true
if resp, err := b.GetFee(feeBuilder); resp != float64(0.0022) || err != nil {
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0.0022), resp)
t.Error(err)
}
// CryptocurrencyTradeFee Negative purchase price
feeBuilder = setFeeBuilder()
feeBuilder.PurchasePrice = -1000
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
}
// CryptocurrencyWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
if resp, err := b.GetFee(feeBuilder); resp != float64(0.001) || err != nil {
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0.001), resp)
if err != nil {
t.Error(err)
}
// CyptocurrencyDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.CyptocurrencyDepositFee
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.FiatCurrency = currency.AUD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.FiatCurrency = currency.AUD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
}
func TestFormatWithdrawPermissions(t *testing.T) {
b.SetDefaults()
expectedResult := exchange.AutoWithdrawCryptoText + " & " + exchange.AutoWithdrawFiatText
withdrawPermissions := b.FormatWithdrawPermissions()
if withdrawPermissions != expectedResult {
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
}
}
func TestGetActiveOrders(t *testing.T) {
b.SetDefaults()
TestSetup(t)
var getOrdersRequest = order.GetOrdersRequest{
OrderType: order.AnyType,
}
_, err := b.GetActiveOrders(&getOrdersRequest)
if areTestAPIKeysSet() && err != nil {
t.Errorf("Could not get open orders: %s", err)
} else if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
}
}
func TestGetOrderHistory(t *testing.T) {
b.SetDefaults()
TestSetup(t)
var getOrdersRequest = order.GetOrdersRequest{
OrderType: order.AnyType,
Currencies: []currency.Pair{currency.NewPair(currency.LTC,
currency.BTC)},
t.Parallel()
if !areTestAPIKeysSet() {
t.Skip("API keys required but not set, skipping test")
}
_, err := b.GetOrderHistory(&getOrdersRequest)
if areTestAPIKeysSet() && err != nil {
t.Errorf("Could not get order history: %s", err)
} else if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
var input order.GetOrdersRequest
input.OrderSide = order.Buy
_, err := b.GetOrderHistory(&input)
if err != nil {
t.Error(err)
}
}
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
// ----------------------------------------------------------------------------------------------------------------------------
func areTestAPIKeysSet() bool {
return b.ValidateAPICredentials()
}
func TestSubmitOrder(t *testing.T) {
b.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var orderSubmission = &order.Submit{
Pair: currency.Pair{
Delimiter: "-",
Base: currency.BTC,
Quote: currency.LTC,
},
OrderSide: order.Buy,
OrderType: order.Limit,
Price: 1,
Amount: 1,
ClientID: "meowOrder",
}
response, err := b.SubmitOrder(orderSubmission)
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
t.Errorf("Order failed to be placed: %v", err)
} else if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
func TestUpdateOrderbook(t *testing.T) {
t.Parallel()
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.AUD.String(), "-")
_, err := b.UpdateOrderbook(cp, asset.Spot)
if err != nil {
t.Error(err)
}
}
func TestCancelExchangeOrder(t *testing.T) {
b.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
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,
}
err := b.CancelOrder(orderCancellation)
if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
}
if areTestAPIKeysSet() && err != nil {
t.Errorf("Could not cancel orders: %v", err)
}
}
func TestCancelAllExchangeOrders(t *testing.T) {
b.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
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)
if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
}
if areTestAPIKeysSet() && err != nil {
t.Errorf("Could not cancel orders: %v", err)
}
if len(resp.Status) > 0 {
t.Errorf("%v orders failed to cancel", len(resp.Status))
}
}
func TestModifyOrder(t *testing.T) {
_, err := b.ModifyOrder(&order.Modify{})
if err == nil {
t.Error("ModifyOrder() Expected error")
}
}
func TestWithdraw(t *testing.T) {
b.SetDefaults()
TestSetup(t)
withdrawCryptoRequest := exchange.CryptoWithdrawRequest{
GenericWithdrawRequestInfo: exchange.GenericWithdrawRequestInfo{
Amount: -1,
Currency: currency.BTC,
Description: "WITHDRAW IT ALL",
},
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
}
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
_, err := b.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest)
if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
}
if areTestAPIKeysSet() && err != nil {
t.Errorf("Withdraw failed to be placed: %v", err)
}
}
func TestWithdrawFiat(t *testing.T) {
b.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var withdrawFiatRequest = exchange.FiatWithdrawRequest{
GenericWithdrawRequestInfo: exchange.GenericWithdrawRequestInfo{
Amount: -1,
Currency: currency.USD,
Description: "WITHDRAW IT ALL",
},
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
BankAddress: "123 Fake St",
BankCity: "Tarry Town",
BankCountry: "Hyrule",
BankName: "Commonwealth Bank of Australia",
WireCurrency: currency.AUD.String(),
SwiftCode: "Taylor",
RequiresIntermediaryBank: false,
IsExpressWire: false,
}
_, err := b.WithdrawFiatFunds(&withdrawFiatRequest)
if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
}
if areTestAPIKeysSet() && err != nil {
t.Errorf("Withdraw failed to be placed: %v", err)
}
}
func TestWithdrawInternationalBank(t *testing.T) {
b.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
_, err := b.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
if err != common.ErrFunctionNotSupported {
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
}
}
func TestGetDepositAddress(t *testing.T) {
_, err := b.GetDepositAddress(currency.BTC, "")
if err == nil {
t.Error("GetDepositAddress() error cannot be nil")
func TestUpdateTicker(t *testing.T) {
t.Parallel()
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.AUD.String(), "-")
_, err := b.UpdateTicker(cp, asset.Spot)
if err != nil {
t.Error(err)
}
}

View File

@@ -1,66 +1,74 @@
package btcmarkets
import (
"time"
"github.com/thrasher-corp/gocryptotrader/currency"
)
// Response is the genralized response type
type Response struct {
Success bool `json:"success"`
ErrorCode int `json:"errorCode"`
ErrorMessage string `json:"errorMessage"`
ID int `json:"id"`
Responses []ResponseDetails `json:"responses"`
ClientRequestID string `json:"clientRequestId"`
Orders []Order `json:"orders"`
Status string `json:"status"`
}
// ResponseDetails holds order status details
type ResponseDetails struct {
Success bool `json:"success"`
ErrorCode int `json:"errorCode"`
ErrorMessage string `json:"errorMessage"`
ID int64 `json:"id"`
}
import "time"
// Market holds a tradable market instrument
type Market struct {
Instrument string `json:"instrument"`
Currency string `json:"currency"`
MarketID string `json:"marketId"`
BaseAsset string `json:"baseAsset"`
QuoteAsset string `json:"quoteAsset"`
MinOrderAmount float64 `json:"minOrderAmount,string"`
MaxOrderAmount float64 `json:"maxOrderAmount,string"`
AmountDecimals int64 `json:"amountDecimals,string"`
PriceDecimals int64 `json:"priceDecimals,string"`
}
// Ticker holds ticker information
type Ticker struct {
BestAsk float64 `json:"bestAsk"`
BestBid float64 `json:"bestBid"`
Currency currency.Code `json:"currency"`
High24h float64 `json:"high24h"`
Instrument currency.Pair `json:"instrument"`
LastPrice float64 `json:"lastPrice"`
Low24h float64 `json:"low24h"`
Price24h float64 `json:"price24h"`
Timestamp int64 `json:"timestamp"`
Volume24h float64 `json:"volume24h"`
}
// Orderbook holds current orderbook information returned from the exchange
type Orderbook struct {
Currency string `json:"currency"`
Instrument string `json:"instrument"`
Timestamp int64 `json:"timestamp"`
Asks [][]float64 `json:"asks"`
Bids [][]float64 `json:"bids"`
MarketID string `json:"marketId"`
BestBID float64 `json:"bestBid,string"`
BestAsk float64 `json:"bestAsk,string"`
LastPrice float64 `json:"lastPrice,string"`
Volume float64 `json:"volume24h,string"`
Change24h float64 `json:"price24h,string"`
Low24h float64 `json:"low24h,string"`
High24h float64 `json:"high24h,string"`
Timestamp time.Time `json:"timestamp"`
}
// Trade holds trade information
type Trade struct {
TradeID int64 `json:"tid"`
Amount float64 `json:"amount"`
Price float64 `json:"price"`
Date int64 `json:"date"`
TradeID string `json:"id"`
Amount float64 `json:"amount,string"`
Price float64 `json:"price,string"`
Timestamp time.Time `json:"timestamp"`
}
// tempOrderbook stores orderbook data
type tempOrderbook struct {
MarketID string `json:"marketId"`
SnapshotID int64 `json:"snapshotId"`
Asks [][2]string `json:"asks"`
Bids [][2]string `json:"bids"`
}
// OBData stores orderbook data
type OBData struct {
Price float64
Volume float64
}
// Orderbook holds current orderbook information returned from the exchange
type Orderbook struct {
MarketID string
SnapshotID int64
Asks []OBData
Bids []OBData
}
// MarketCandle stores candle data for a given pair
type MarketCandle struct {
Time time.Time
Open float64
Close float64
Low float64
High float64
Volume float64
}
// TimeResp stores server time
type TimeResp struct {
Time time.Time `json:"timestamp"`
}
// TradingFee 30 day trade volume
@@ -90,7 +98,7 @@ type Order struct {
Instrument string `json:"instrument"`
OrderSide string `json:"orderSide"`
OrderType string `json:"ordertype"`
CreationTime float64 `json:"creationTime"`
CreationTime time.Time `json:"creationTime"`
Status string `json:"status"`
ErrorMessage string `json:"errorMessage"`
Price float64 `json:"price"`
@@ -102,19 +110,164 @@ type Order struct {
// TradeResponse holds trade information
type TradeResponse struct {
ID int64 `json:"id"`
CreationTime float64 `json:"creationTime"`
Description string `json:"description"`
Price float64 `json:"price"`
Volume float64 `json:"volume"`
Fee float64 `json:"fee"`
ID int64 `json:"id"`
CreationTime time.Time `json:"creationTime"`
Description string `json:"description"`
Price float64 `json:"price"`
Volume float64 `json:"volume"`
Fee float64 `json:"fee"`
}
// AccountBalance holds account balance details
type AccountBalance struct {
Balance float64 `json:"balance"`
PendingFunds float64 `json:"pendingFunds"`
Currency string `json:"currency"`
// AccountData stores account data
type AccountData struct {
AssetName string `json:"assetName"`
Balance float64 `json:"balance,string"`
Available float64 `json:"available,string"`
Locked float64 `json:"locked,string"`
}
// TradeHistoryData stores data of past trades
type TradeHistoryData struct {
ID string `json:"id"`
MarketID string `json:"marketId"`
Timestamp time.Time `json:"timestamp"`
Price float64 `json:"price,string"`
Amount float64 `json:"amount,string"`
Side string `json:"side"`
Fee float64 `json:"fee,string"`
OrderID string `json:"orderId"`
LiquidityType string `json:"liquidityType"`
}
// OrderData stores data for new order created
type OrderData struct {
OrderID string `json:"orderId"`
MarketID string `json:"marketId"`
Side string `json:"side"`
Type string `json:"type"`
CreationTime time.Time `json:"creationTime"`
Price float64 `json:"price,string"`
Amount float64 `json:"amount,string"`
OpenAmount float64 `json:"openAmount,string"`
Status string `json:"status"`
}
// CancelOrderResp stores data for cancelled orders
type CancelOrderResp struct {
OrderID string `json:"orderId"`
ClientOrderID string `json:"clientOrderId"`
}
// PaymentDetails stores payment address
type PaymentDetails struct {
Address string `json:"address"`
}
// TransferData stores data from asset transfers
type TransferData struct {
ID string `json:"id"`
AssetName string `json:"assetName"`
Amount float64 `json:"amount,string"`
RequestType string `json:"type"`
CreationTime time.Time `json:"creationTime"`
Status string `json:"status"`
Description string `json:"description"`
Fee float64 `json:"fee,string"`
LastUpdate string `json:"lastUpdate"`
PaymentDetails PaymentDetails `json:"paymentDetail"`
}
// DepositAddress stores deposit address data
type DepositAddress struct {
Address string `json:"address"`
AssetName string `json:"assetName"`
}
// WithdrawalFeeData stores data for fees
type WithdrawalFeeData struct {
AssetName string `json:"assetName"`
Fee float64 `json:"fee,string"`
}
// AssetData stores data for given asset
type AssetData struct {
AssetName string `json:"assetName"`
MinDepositAmount float64 `json:"minDepositAmount,string"`
MaxDepositAmount float64 `json:"maxDepositAmount,string"`
DepositDecimals float64 `json:"depositDecimals,string"`
MinWithdrawalAmount float64 `json:"minWithdrawalAmount,string"`
MaxWithdrawalAmount float64 `json:"maxWithdrawalAmount,string"`
WithdrawalDecimals float64 `json:"withdrawalDecimals,string"`
WithdrawalFee float64 `json:"withdrawalFee,string"`
DepositFee float64 `json:"depositFee,string"`
}
// TransactionData stores data from past transactions
type TransactionData struct {
ID string `json:"id"`
CreationTime time.Time `json:"creationTime"`
Description string `json:"description"`
AssetName string `json:"assetName"`
Amount float64 `json:"amount,string"`
Balance float64 `json:"balance,string"`
FeeType string `json:"type"`
RecordType string `json:"recordType"`
ReferrenceID string `json:"referrenceId"`
}
// CreateReportResp stores data for created report
type CreateReportResp struct {
ReportID string `json:"reportId"`
}
// ReportData gets data for a created report
type ReportData struct {
ID string `json:"id"`
ContentURL string `json:"contentUrl"`
CreationTime time.Time `json:"creationTime"`
ReportType string `json:"reportType"`
Status string `json:"status"`
Format string `json:"format"`
}
// BatchPlaceData stores data for placed batch orders
type BatchPlaceData struct {
OrderID string `json:"orderId"`
MarketID string `json:"marketId"`
Side string `json:"side"`
Type string `json:"type"`
CreationTime time.Time `json:"creationTime"`
Price float64 `json:"price,string"`
Amount float64 `json:"amount,string"`
OpenAmount float64 `json:"openAmount,string"`
Status string `json:"status"`
ClientOrderID string `json:"clientOrderId"`
}
// UnprocessedBatchResp stores data for unprocessed response
type UnprocessedBatchResp struct {
Code string `json:"code"`
Message string `json:"message"`
RequestID string `json:"requestId"`
}
// BatchPlaceCancelResponse stores place and cancel batch data
type BatchPlaceCancelResponse struct {
PlacedOrders []BatchPlaceData `json:"placeOrders"`
CancelledOrders []CancelOrderResp `json:"cancelOrders"`
UnprocessedOrders []UnprocessedBatchResp `json:"unprocessedRequests"`
}
// BatchTradeResponse stores the trades from batchtrades
type BatchTradeResponse struct {
Orders []BatchPlaceData `json:"orders"`
UnprocessedRequests []UnprocessedBatchResp `json:"unprocessedRequests"`
}
// BatchCancelResponse stores the cancellation details from batch cancels
type BatchCancelResponse struct {
CancelOrders []CancelOrderResp `json:"cancelOrders"`
UnprocessedRequests []UnprocessedBatchResp `json:"unprocessedRequests"`
}
// WithdrawRequestCrypto is a generalized withdraw request type
@@ -134,18 +287,48 @@ type WithdrawRequestAUD struct {
BSBNumber string `json:"bsbNumber"`
}
// WithdrawalFees the large list of predefined withdrawal fees
// Prone to change
var WithdrawalFees = map[currency.Code]float64{
currency.AUD: 0,
currency.BTC: 0.001,
currency.ETH: 0.001,
currency.ETC: 0.001,
currency.LTC: 0.0001,
currency.XRP: 0.15,
currency.BCH: 0.0001,
currency.OMG: 0.15,
currency.POWR: 5,
// CancelBatch stores data for batch cancel request
type CancelBatch struct {
OrderID string `json:"orderId,omitempty"`
ClientOrderID string `json:"clientOrderId,omitempty"`
}
// PlaceBatch stores data for place batch request
type PlaceBatch struct {
MarketID string `json:"marketId"`
Price float64 `json:"price"`
Amount float64 `json:"amount"`
OrderType string `json:"type"`
Side string `json:"side"`
TriggerPrice float64 `json:"triggerPrice,omitempty"`
TriggerAmount float64 `json:"triggerAmount,omitempty"`
TimeInForce string `json:"timeInForce,omitempty"`
PostOnly bool `json:"postOnly,omitempty"`
SelfTrade string `json:"selfTrade,omitempty"`
ClientOrderID string `json:"clientOrderId,omitempty"`
}
// PlaceOrderMethod stores data for place request
type PlaceOrderMethod struct {
PlaceOrder PlaceBatch `json:"placeOrder,omitempty"`
}
// CancelOrderMethod stores data for Cancel request
type CancelOrderMethod struct {
CancelOrder CancelBatch `json:"cancelOrder,omitempty"`
}
// TradingFeeData stores trading fee data
type TradingFeeData struct {
MakerFeeRate float64 `json:"makerFeeRate,string"`
TakerFeeRate float64 `json:"takerFeeRate,string"`
MarketID string `json:"marketId"`
}
// TradingFeeResponse stores trading fee data
type TradingFeeResponse struct {
MonthlyVolume float64 `json:"volume30Day,string"`
FeeByMarkets []TradingFeeData `json:"FeeByMarkets"`
}
// WsSubscribe message sent via ws to subscribe
@@ -155,6 +338,16 @@ type WsSubscribe struct {
MessageType string `json:"messageType"`
}
// WsAuthSubscribe message sent via login to subscribe
type WsAuthSubscribe struct {
MarketIDs []string `json:"marketIds,omitempty"`
Channels []string `json:"channels"`
Key string `json:"key"`
Signature string `json:"signature"`
Timestamp string `json:"timestamp"`
MessageType string `json:"messageType"`
}
// WsMessageType message sent via ws to determine type
type WsMessageType struct {
MessageType string `json:"messageType"`
@@ -193,7 +386,42 @@ type WsOrderbook struct {
MessageType string `json:"messageType"`
}
// WsError message received for orderbook errors
// WsFundTransfer stores fund transfer data for websocket
type WsFundTransfer struct {
FundTransferID int64 `json:"fundtransferId"`
TransferType string `json:"type"`
Status string `json:"status"`
Timestamp time.Time `json:"timestamp"`
Amount float64 `json:"amount,string"`
Currency string `json:"currency"`
Fee float64 `json:"fee,string"`
MessageType string `json:"messageType"`
}
// WsTradeData stores trade data for websocket
type WsTradeData struct {
TradeID int64 `json:"tradeId"`
Price float64 `json:"price,string"`
Volume float64 `json:"volume,string"`
Fee float64 `json:"fee,string"`
LiquidityType string `json:"liquidityType"`
}
// WsOrderChange stores order data
type WsOrderChange struct {
OrderID int64 `json:"orderId"`
MarketID string `json:"marketId"`
Side string `json:"side"`
OrderType string `json:"type"`
OpenVolume float64 `json:"openVolume,string"`
Status string `json:"status"`
TriggerStatus string `json:"triggerStatus"`
Trades []WsTradeData `json:"trades"`
Timestamp time.Time `json:"timestamp"`
MessageType string `json:"messageType"`
}
// WsError stores websocket error data
type WsError struct {
MessageType string `json:"messageType"`
Code int64 `json:"code"`

View File

@@ -6,9 +6,13 @@ import (
"fmt"
"net/http"
"strconv"
"time"
"github.com/gorilla/websocket"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"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/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
@@ -32,10 +36,15 @@ func (b *BTCMarkets) WsConnect() error {
if b.Verbose {
log.Debugf(log.ExchangeSys, "%s Connected to Websocket.\n", b.Name)
}
b.generateDefaultSubscriptions()
go b.WsHandleData()
if b.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
b.createChannels()
if err != nil {
b.Websocket.DataHandler <- err
b.Websocket.SetCanUseAuthenticatedEndpoints(false)
}
}
b.generateDefaultSubscriptions()
return nil
}
@@ -64,11 +73,11 @@ func (b *BTCMarkets) WsHandleData() {
continue
}
switch wsResponse.MessageType {
case "heartbeat":
case heartbeat:
if b.Verbose {
log.Debugf(log.ExchangeSys, "%v - Websocket heartbeat received %s", b.Name, resp.Raw)
}
case "orderbook":
case wsOB:
var ob WsOrderbook
err := json.Unmarshal(resp.Raw, &ob)
if err != nil {
@@ -129,7 +138,7 @@ func (b *BTCMarkets) WsHandleData() {
Asset: asset.Spot,
Exchange: b.Name,
}
case "trade":
case trade:
var trade WsTrade
err := json.Unmarshal(resp.Raw, &trade)
if err != nil {
@@ -145,7 +154,7 @@ func (b *BTCMarkets) WsHandleData() {
Price: trade.Price,
Amount: trade.Volume,
}
case "tick":
case tick:
var tick WsTick
err := json.Unmarshal(resp.Raw, &tick)
if err != nil {
@@ -166,6 +175,22 @@ func (b *BTCMarkets) WsHandleData() {
AssetType: asset.Spot,
Pair: p,
}
case fundChange:
var transferData WsFundTransfer
err := json.Unmarshal(resp.Raw, &transferData)
if err != nil {
b.Websocket.DataHandler <- err
continue
}
b.Websocket.DataHandler <- transferData
case orderChange:
var orderData WsOrderChange
err := json.Unmarshal(resp.Raw, &orderData)
if err != nil {
b.Websocket.DataHandler <- err
continue
}
b.Websocket.DataHandler <- orderData
case "error":
var wsErr WsError
err := json.Unmarshal(resp.Raw, &wsErr)
@@ -182,7 +207,7 @@ func (b *BTCMarkets) WsHandleData() {
}
func (b *BTCMarkets) generateDefaultSubscriptions() {
var channels = []string{"tick", "trade", "orderbook"}
var channels = []string{tick, trade, wsOB}
enabledCurrencies := b.GetEnabledPairs(asset.Spot)
var subscriptions []wshandler.WebsocketChannelSubscription
for i := range channels {
@@ -198,10 +223,68 @@ func (b *BTCMarkets) generateDefaultSubscriptions() {
// Subscribe sends a websocket message to receive data from the channel
func (b *BTCMarkets) Subscribe(channelToSubscribe wshandler.WebsocketChannelSubscription) error {
req := WsSubscribe{
MarketIDs: []string{channelToSubscribe.Currency.String()},
Channels: []string{channelToSubscribe.Channel},
MessageType: "subscribe",
unauthChannels := []string{tick, trade, wsOB}
authChannels := []string{fundChange, heartbeat, orderChange}
switch {
case common.StringDataCompare(unauthChannels, channelToSubscribe.Channel):
req := WsSubscribe{
MarketIDs: []string{b.FormatExchangeCurrency(channelToSubscribe.Currency, asset.Spot).String()},
Channels: []string{channelToSubscribe.Channel},
MessageType: subscribe,
}
err := b.WebsocketConn.SendMessage(req)
if err != nil {
return err
}
case common.StringDataCompare(authChannels, channelToSubscribe.Channel):
message, ok := channelToSubscribe.Params["AuthSub"].(WsAuthSubscribe)
if !ok {
return errors.New("invalid params data")
}
tempAuthData := b.generateAuthSubscriptions()
message.Channels = append(message.Channels, channelToSubscribe.Channel, heartbeat)
message.Key = tempAuthData.Key
message.Signature = tempAuthData.Signature
message.Timestamp = tempAuthData.Timestamp
err := b.WebsocketConn.SendMessage(message)
if err != nil {
return err
}
}
return b.WebsocketConn.SendMessage(req)
return nil
}
// Login logs in allowing private ws events
func (b *BTCMarkets) generateAuthSubscriptions() WsAuthSubscribe {
var authSubInfo WsAuthSubscribe
signTime := strconv.FormatInt(time.Now().UTC().UnixNano()/1000000, 10)
strToSign := "/users/self/subscribe" + "\n" + signTime
tempSign := crypto.GetHMAC(crypto.HashSHA512,
[]byte(strToSign),
[]byte(b.API.Credentials.Secret))
sign := crypto.Base64Encode(tempSign)
authSubInfo.Key = b.API.Credentials.Key
authSubInfo.Signature = sign
authSubInfo.Timestamp = signTime
return authSubInfo
}
// createChannels creates channels that need to be
func (b *BTCMarkets) createChannels() {
tempChannels := []string{orderChange, fundChange}
var channels []wshandler.WebsocketChannelSubscription
pairArray := b.GetEnabledPairs(asset.Spot)
for y := range tempChannels {
for x := range pairArray {
var authSub WsAuthSubscribe
var channel wshandler.WebsocketChannelSubscription
channel.Params = make(map[string]interface{})
channel.Channel = tempChannels[y]
authSub.MarketIDs = append(authSub.MarketIDs, b.FormatExchangeCurrency(pairArray[x], asset.Spot).String())
authSub.MessageType = subscribe
channel.Params["AuthSub"] = authSub
channels = append(channels, channel)
}
}
b.Websocket.SubscribeToChannels(channels)
}

View File

@@ -3,7 +3,6 @@ package btcmarkets
import (
"errors"
"fmt"
"strconv"
"strings"
"sync"
"time"
@@ -62,6 +61,7 @@ func (b *BTCMarkets) SetDefaults() {
},
UseGlobalFormat: true,
RequestFormat: &currency.PairFormat{
Delimiter: "-",
Uppercase: true,
},
ConfigFormat: &currency.PairFormat{
@@ -172,19 +172,31 @@ func (b *BTCMarkets) Start(wg *sync.WaitGroup) {
// Run implements the BTC Markets wrapper
func (b *BTCMarkets) Run() {
if b.Verbose {
log.Debugf(log.ExchangeSys,
"%s Websocket: %s (url: %s).\n",
b.Name,
common.IsEnabled(b.Websocket.IsEnabled()),
btcMarketsWSURL)
b.PrintEnabledPairs()
}
forceUpdate := false
if !common.StringDataContains(b.GetEnabledPairs(asset.Spot).Strings(), "-") ||
!common.StringDataContains(b.GetAvailablePairs(asset.Spot).Strings(), "-") {
enabledPairs := []string{"BTC-AUD"}
log.Warnln(log.ExchangeSys, "Available pairs for BTC Markets reset due to config upgrade, please enable the pairs you would like again.")
forceUpdate = true
err := b.UpdatePairs(currency.NewPairsFromStrings(enabledPairs), asset.Spot, true, true)
}
if forceUpdate {
enabledPairs := currency.Pairs{currency.Pair{
Base: currency.BTC.Lower(),
Quote: currency.AUD.Lower(),
Delimiter: "-",
},
}
err := b.UpdatePairs(enabledPairs, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to update currencies. Err: %s", b.Name, err)
log.Errorf(log.ExchangeSys,
"%s Failed to update enabled currencies.\n",
b.Name)
}
}
@@ -194,12 +206,18 @@ func (b *BTCMarkets) Run() {
err := b.UpdateTradablePairs(forceUpdate)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", b.Name, err)
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
b.Name,
err)
}
}
// FetchTradablePairs returns a list of the exchanges tradable pairs
func (b *BTCMarkets) FetchTradablePairs(asset asset.Item) ([]string, error) {
func (b *BTCMarkets) FetchTradablePairs(a asset.Item) ([]string, error) {
if a != asset.Spot {
return nil, fmt.Errorf("asset type of %s is not supported by %s", a, b.Name)
}
markets, err := b.GetMarkets()
if err != nil {
return nil, err
@@ -207,9 +225,8 @@ func (b *BTCMarkets) FetchTradablePairs(asset asset.Item) ([]string, error) {
var pairs []string
for x := range markets {
pairs = append(pairs, fmt.Sprintf("%v%v%v", markets[x].Instrument, b.GetPairFormat(asset, false).Delimiter, markets[x].Currency))
pairs = append(pairs, markets[x].MarketID)
}
return pairs, nil
}
@@ -226,28 +243,26 @@ func (b *BTCMarkets) UpdateTradablePairs(forceUpdate bool) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *BTCMarkets) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := b.GetTicker(p.Base.String(), p.Quote.String())
if err != nil {
return tickerPrice, err
var resp ticker.Price
allPairs := b.GetEnabledPairs(assetType)
for x := range allPairs {
tick, err := b.GetTicker(b.FormatExchangeCurrency(allPairs[x], assetType).String())
if err != nil {
return resp, err
}
resp.Pair = allPairs[x]
resp.Last = tick.LastPrice
resp.High = tick.High24h
resp.Low = tick.Low24h
resp.Bid = tick.BestBID
resp.Ask = tick.BestAsk
resp.Volume = tick.Volume
resp.LastUpdated = time.Now()
err = ticker.ProcessTicker(b.Name, &resp, assetType)
if err != nil {
return resp, err
}
}
tickerPrice = ticker.Price{
Last: tick.LastPrice,
High: tick.High24h,
Low: tick.Low24h,
Bid: tick.BestBid,
Ask: tick.BestAsk,
Volume: tick.Volume24h,
Pair: p,
LastUpdated: time.Unix(tick.Timestamp, 0),
}
err = ticker.ProcessTicker(b.Name, &tickerPrice, assetType)
if err != nil {
return tickerPrice, err
}
return ticker.GetTicker(b.Name, p, assetType)
}
@@ -272,64 +287,50 @@ func (b *BTCMarkets) FetchOrderbook(p currency.Pair, assetType asset.Item) (orde
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *BTCMarkets) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := b.GetOrderbook(p.Base.String(),
p.Quote.String())
tempResp, err := b.GetOrderbook(b.FormatExchangeCurrency(p, assetType).String(), 2)
if err != nil {
return orderBook, err
}
for x := range orderbookNew.Bids {
for x := range tempResp.Bids {
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
Amount: orderbookNew.Bids[x][1],
Price: orderbookNew.Bids[x][0],
})
Amount: tempResp.Bids[x].Volume,
Price: tempResp.Bids[x].Price})
}
for x := range orderbookNew.Asks {
for y := range tempResp.Asks {
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
Amount: orderbookNew.Asks[x][1],
Price: orderbookNew.Asks[x][0],
})
Amount: tempResp.Asks[y].Volume,
Price: tempResp.Asks[y].Price})
}
orderBook.Pair = p
orderBook.ExchangeName = b.Name
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(b.Name, p, assetType)
}
// GetAccountInfo retrieves balances for all enabled currencies for the
// BTCMarkets exchange
// GetAccountInfo retrieves balances for all enabled currencies
func (b *BTCMarkets) GetAccountInfo() (exchange.AccountInfo, error) {
var response exchange.AccountInfo
response.Exchange = b.Name
accountBalance, err := b.GetAccountBalance()
var resp exchange.AccountInfo
data, err := b.GetAccountBalance()
if err != nil {
return response, err
return resp, err
}
var currencies []exchange.AccountCurrencyInfo
for i := 0; i < len(accountBalance); i++ {
var exchangeCurrency exchange.AccountCurrencyInfo
exchangeCurrency.CurrencyName = currency.NewCode(accountBalance[i].Currency)
exchangeCurrency.TotalValue = accountBalance[i].Balance
exchangeCurrency.Hold = accountBalance[i].PendingFunds
currencies = append(currencies, exchangeCurrency)
var account exchange.Account
for key := range data {
c := currency.NewCode(data[key].AssetName)
hold := data[key].Locked
total := data[key].Balance
account.Currencies = append(account.Currencies,
exchange.AccountCurrencyInfo{CurrencyName: c,
TotalValue: total,
Hold: hold})
}
response.Accounts = append(response.Accounts, exchange.Account{
Currencies: currencies,
})
return response, nil
resp.Accounts = append(resp.Accounts, account)
resp.Exchange = b.Name
return resp, nil
}
// GetFundingHistory returns funding history, deposits and
@@ -345,35 +346,35 @@ func (b *BTCMarkets) GetExchangeHistory(p currency.Pair, assetType asset.Item) (
// SubmitOrder submits a new order
func (b *BTCMarkets) SubmitOrder(s *order.Submit) (order.SubmitResponse, error) {
var submitOrderResponse order.SubmitResponse
var resp order.SubmitResponse
if err := s.Validate(); err != nil {
return submitOrderResponse, err
return resp, err
}
if strings.EqualFold(s.OrderSide.String(), order.Sell.String()) {
if s.OrderSide == order.Sell {
s.OrderSide = order.Ask
}
if strings.EqualFold(s.OrderSide.String(), order.Buy.String()) {
if s.OrderSide == order.Buy {
s.OrderSide = order.Bid
}
response, err := b.NewOrder(s.Pair.Base.Upper().String(),
s.Pair.Quote.Upper().String(),
tempResp, err := b.NewOrder(b.FormatExchangeCurrency(s.Pair, asset.Spot).String(),
s.Price,
s.Amount,
s.OrderSide.String(),
s.OrderType.String(),
s.TriggerPrice,
s.TargetAmount,
"",
false,
"",
s.ClientID)
if response > 0 {
submitOrderResponse.OrderID = strconv.FormatInt(response, 10)
if err != nil {
return resp, err
}
if err == nil {
submitOrderResponse.IsOrderPlaced = true
}
return submitOrderResponse, err
resp.IsOrderPlaced = true
resp.OrderID = tempResp.OrderID
return resp, nil
}
// ModifyOrder will allow of changing orderbook placement and limit to
@@ -383,116 +384,130 @@ func (b *BTCMarkets) ModifyOrder(action *order.Modify) (string, error) {
}
// CancelOrder cancels an order by its corresponding ID number
func (b *BTCMarkets) CancelOrder(order *order.Cancel) error {
orderIDInt, err := strconv.ParseInt(order.OrderID, 10, 64)
if err != nil {
return err
}
_, err = b.CancelExistingOrder([]int64{orderIDInt})
func (b *BTCMarkets) CancelOrder(o *order.Cancel) error {
_, err := b.RemoveOrder(o.OrderID)
return err
}
// CancelAllOrders cancels all orders associated with a currency pair
func (b *BTCMarkets) CancelAllOrders(_ *order.Cancel) (order.CancelAllResponse, error) {
cancelAllOrdersResponse := order.CancelAllResponse{
Status: make(map[string]string),
}
openOrders, err := b.GetOpenOrders()
var resp order.CancelAllResponse
tempMap := make(map[string]string)
var orderIDs []string
orders, err := b.GetOrders("", -1, -1, -1, "open")
if err != nil {
return cancelAllOrdersResponse, err
return resp, err
}
var orderList []int64
for i := range openOrders {
orderList = append(orderList, openOrders[i].ID)
for x := range orders {
orderIDs = append(orderIDs, orders[x].OrderID)
}
if len(orderList) > 0 {
orders, err := b.CancelExistingOrder(orderList)
if err != nil {
return cancelAllOrdersResponse, err
}
for i := range orders {
if !orders[i].Success {
cancelAllOrdersResponse.Status[strconv.FormatInt(orders[i].ID, 10)] = orders[i].ErrorMessage
}
}
tempResp, err := b.CancelBatchOrders(orderIDs)
if err != nil {
return resp, err
}
return cancelAllOrdersResponse, nil
for y := range tempResp.CancelOrders {
tempMap[tempResp.CancelOrders[y].OrderID] = "Success"
}
for z := range tempResp.UnprocessedRequests {
tempMap[tempResp.UnprocessedRequests[z].RequestID] = "Cancellation Failed"
}
return resp, nil
}
// GetOrderInfo returns information on a current open order
func (b *BTCMarkets) GetOrderInfo(orderID string) (order.Detail, error) {
var OrderDetail order.Detail
o, err := strconv.ParseInt(orderID, 10, 64)
var resp order.Detail
o, err := b.FetchOrder(orderID)
if err != nil {
return OrderDetail, err
return resp, err
}
orders, err := b.GetOrderDetail([]int64{o})
if err != nil {
return OrderDetail, err
resp.Exchange = b.Name
resp.ID = orderID
resp.CurrencyPair = currency.NewPairFromString(o.MarketID)
resp.Price = o.Price
resp.OrderDate = o.CreationTime
resp.ExecutedAmount = o.Amount - o.OpenAmount
resp.OrderSide = order.Bid
if o.Side == ask {
resp.OrderSide = order.Ask
}
if len(orders) > 1 {
return OrderDetail, errors.New("too many orders returned")
switch o.Type {
case limit:
resp.OrderType = order.Limit
case market:
resp.OrderType = order.Market
case stopLimit:
resp.OrderType = order.Stop
case stop:
resp.OrderType = order.Stop
case takeProfit:
resp.OrderType = order.ImmediateOrCancel
default:
resp.OrderType = order.Unknown
}
if len(orders) == 0 {
return OrderDetail, errors.New("no orders found")
resp.RemainingAmount = o.OpenAmount
switch o.Status {
case orderAccepted:
resp.Status = order.Active
case orderPlaced:
resp.Status = order.Active
case orderPartiallyMatched:
resp.Status = order.PartiallyFilled
case orderFullyMatched:
resp.Status = order.Filled
case orderCancelled:
resp.Status = order.Cancelled
case orderPartiallyCancelled:
resp.Status = order.PartiallyCancelled
case orderFailed:
resp.Status = order.Rejected
default:
resp.Status = order.UnknownStatus
}
for i := range orders {
var side order.Side
if strings.EqualFold(orders[i].OrderSide, order.Ask.String()) {
side = order.Sell
} else if strings.EqualFold(orders[i].OrderSide, order.Bid.String()) {
side = order.Buy
}
orderDate := time.Unix(int64(orders[i].CreationTime), 0)
orderType := order.Type(strings.ToUpper(orders[i].OrderType))
OrderDetail.Amount = orders[i].Volume
OrderDetail.OrderDate = orderDate
OrderDetail.Exchange = b.Name
OrderDetail.ID = strconv.FormatInt(orders[i].ID, 10)
OrderDetail.RemainingAmount = orders[i].OpenVolume
OrderDetail.OrderSide = side
OrderDetail.OrderType = orderType
OrderDetail.Price = orders[i].Price
OrderDetail.Status = order.Status(orders[i].Status)
OrderDetail.CurrencyPair = currency.NewPairWithDelimiter(orders[i].Instrument,
orders[i].Currency,
b.GetPairFormat(asset.Spot, false).Delimiter)
}
return OrderDetail, nil
return resp, nil
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *BTCMarkets) GetDepositAddress(cryptocurrency currency.Code, accountID string) (string, error) {
return "", common.ErrFunctionNotSupported
temp, err := b.FetchDepositAddress(strings.ToUpper(cryptocurrency.String()), -1, -1, -1)
if err != nil {
return "", err
}
return temp.Address, nil
}
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is submitted
func (b *BTCMarkets) WithdrawCryptocurrencyFunds(withdrawRequest *exchange.CryptoWithdrawRequest) (string, error) {
return b.WithdrawCrypto(withdrawRequest.Amount, withdrawRequest.Currency.String(), withdrawRequest.Address)
a, err := b.RequestWithdraw(withdrawRequest.Currency.String(),
withdrawRequest.Amount,
withdrawRequest.Address,
"",
"",
"",
"")
if err != nil {
return "", err
}
return a.Status, nil
}
// WithdrawFiatFunds returns a withdrawal ID when a
// withdrawal is submitted
func (b *BTCMarkets) WithdrawFiatFunds(withdrawRequest *exchange.FiatWithdrawRequest) (string, error) {
if withdrawRequest.Currency != currency.AUD {
return "", errors.New("only AUD is supported for withdrawals")
return "", errors.New("only aud is supported for withdrawals")
}
return b.WithdrawAUD(withdrawRequest.BankAccountName,
strconv.FormatFloat(withdrawRequest.BankAccountNumber, 'f', -1, 64),
withdrawRequest.BankName,
strconv.FormatFloat(withdrawRequest.BankCode, 'f', -1, 64),
withdrawRequest.Amount)
a, err := b.RequestWithdraw(withdrawRequest.GenericWithdrawRequestInfo.Currency.String(),
withdrawRequest.GenericWithdrawRequestInfo.Amount,
"",
withdrawRequest.BankAccountName,
withdrawRequest.BankAccountNumber,
withdrawRequest.BSB,
withdrawRequest.BankName)
if err != nil {
return "", err
}
return a.Status, nil
}
// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a
@@ -517,124 +532,116 @@ func (b *BTCMarkets) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, err
// GetActiveOrders retrieves any orders that are active/open
func (b *BTCMarkets) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail, error) {
resp, err := b.GetOpenOrders()
if err != nil {
return nil, err
var resp []order.Detail
var tempResp order.Detail
var tempData []OrderData
if len(req.Currencies) == 0 {
allPairs := b.GetEnabledPairs(asset.Spot)
for a := range allPairs {
req.Currencies = append(req.Currencies,
allPairs[a])
}
}
var orders []order.Detail
for i := range resp {
var side order.Side
if strings.EqualFold(resp[i].OrderSide, order.Ask.String()) {
side = order.Sell
} else if strings.EqualFold(resp[i].OrderSide, order.Bid.String()) {
side = order.Buy
var err error
for x := range req.Currencies {
tempData, err = b.GetOrders(b.FormatExchangeCurrency(req.Currencies[x], asset.Spot).String(), -1, -1, -1, "")
if err != nil {
return resp, err
}
orderDate := time.Unix(int64(resp[i].CreationTime), 0)
orderType := order.Type(strings.ToUpper(resp[i].OrderType))
openOrder := order.Detail{
ID: strconv.FormatInt(resp[i].ID, 10),
Amount: resp[i].Volume,
Exchange: b.Name,
RemainingAmount: resp[i].OpenVolume,
OrderDate: orderDate,
OrderSide: side,
OrderType: orderType,
Price: resp[i].Price,
Status: order.Status(resp[i].Status),
CurrencyPair: currency.NewPairWithDelimiter(resp[i].Instrument,
resp[i].Currency,
b.GetPairFormat(asset.Spot, false).Delimiter),
for y := range tempData {
tempResp.Exchange = b.Name
tempResp.CurrencyPair = req.Currencies[x]
tempResp.OrderSide = order.Bid
if tempData[y].Side == ask {
tempResp.OrderSide = order.Ask
}
tempResp.OrderDate = tempData[y].CreationTime
switch tempData[y].Status {
case orderAccepted:
tempResp.Status = order.Active
case orderPlaced:
tempResp.Status = order.Active
case orderPartiallyMatched:
tempResp.Status = order.PartiallyFilled
case orderFullyMatched:
tempResp.Status = order.Filled
case orderCancelled:
tempResp.Status = order.Cancelled
case orderPartiallyCancelled:
tempResp.Status = order.PartiallyCancelled
case orderFailed:
tempResp.Status = order.Rejected
}
tempResp.Price = tempData[y].Price
tempResp.Amount = tempData[y].Amount
tempResp.ExecutedAmount = tempData[y].Amount - tempData[y].OpenAmount
tempResp.RemainingAmount = tempData[y].OpenAmount
resp = append(resp, tempResp)
}
for j := range resp[i].Trades {
tradeDate := time.Unix(int64(resp[i].Trades[j].CreationTime), 0)
openOrder.Trades = append(openOrder.Trades, order.TradeHistory{
Amount: resp[i].Trades[j].Volume,
Exchange: b.Name,
Price: resp[i].Trades[j].Price,
TID: resp[i].Trades[j].ID,
Timestamp: tradeDate,
Fee: resp[i].Trades[j].Fee,
Description: resp[i].Trades[j].Description,
})
}
orders = append(orders, openOrder)
}
order.FilterOrdersByType(&orders, req.OrderType)
order.FilterOrdersByTickRange(&orders, req.StartTicks, req.EndTicks)
order.FilterOrdersBySide(&orders, req.OrderSide)
return orders, nil
order.FilterOrdersByType(&resp, req.OrderType)
order.FilterOrdersByTickRange(&resp, req.StartTicks, req.EndTicks)
order.FilterOrdersBySide(&resp, req.OrderSide)
return resp, nil
}
// GetOrderHistory retrieves account order information
// Can Limit response to specific order status
func (b *BTCMarkets) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail, error) {
var resp []order.Detail
var tempResp order.Detail
var tempArray []string
if len(req.Currencies) == 0 {
return nil, errors.New("requires at least one currency pair to retrieve history")
}
var respOrders []Order
for i := range req.Currencies {
resp, err := b.GetOrders(req.Currencies[i].Base.String(),
req.Currencies[i].Quote.String(),
200,
0,
true)
orders, err := b.GetOrders("", -1, -1, -1, "")
if err != nil {
return nil, err
return resp, err
}
for x := range orders {
tempArray = append(tempArray, orders[x].OrderID)
}
respOrders = append(respOrders, resp...)
}
var orders []order.Detail
for i := range respOrders {
var side order.Side
if strings.EqualFold(respOrders[i].OrderSide, order.Ask.String()) {
side = order.Sell
} else if strings.EqualFold(respOrders[i].OrderSide, order.Bid.String()) {
side = order.Buy
for y := range req.Currencies {
orders, err := b.GetOrders(b.FormatExchangeCurrency(req.Currencies[y], asset.Spot).String(), -1, -1, -1, "")
if err != nil {
return resp, err
}
orderDate := time.Unix(int64(respOrders[i].CreationTime), 0)
orderType := order.Type(strings.ToUpper(respOrders[i].OrderType))
openOrder := order.Detail{
ID: strconv.FormatInt(respOrders[i].ID, 10),
Amount: respOrders[i].Volume,
Exchange: b.Name,
RemainingAmount: respOrders[i].OpenVolume,
OrderDate: orderDate,
OrderSide: side,
OrderType: orderType,
Price: respOrders[i].Price,
Status: order.Status(respOrders[i].Status),
CurrencyPair: currency.NewPairWithDelimiter(respOrders[i].Instrument,
respOrders[i].Currency,
b.GetPairFormat(asset.Spot, false).Delimiter),
for z := range orders {
tempArray = append(tempArray, orders[z].OrderID)
}
for j := range respOrders[i].Trades {
tradeDate := time.Unix(int64(respOrders[i].Trades[j].CreationTime), 0)
openOrder.Trades = append(openOrder.Trades, order.TradeHistory{
Amount: respOrders[i].Trades[j].Volume,
Exchange: b.Name,
Price: respOrders[i].Trades[j].Price,
TID: respOrders[i].Trades[j].ID,
Timestamp: tradeDate,
Fee: respOrders[i].Trades[j].Fee,
Description: respOrders[i].Trades[j].Description,
})
}
orders = append(orders, openOrder)
}
order.FilterOrdersByType(&orders, req.OrderType)
order.FilterOrdersByTickRange(&orders, req.StartTicks, req.EndTicks)
order.FilterOrdersBySide(&orders, req.OrderSide)
return orders, nil
tempData, err := b.GetBatchTrades(tempArray)
if err != nil {
return resp, err
}
for c := range tempData.Orders {
switch tempData.Orders[c].Status {
case orderFailed:
tempResp.Status = order.Rejected
case orderPartiallyCancelled:
tempResp.Status = order.PartiallyCancelled
case orderCancelled:
tempResp.Status = order.Cancelled
case orderFullyMatched:
tempResp.Status = order.Filled
case orderPartiallyMatched:
continue
case orderPlaced:
continue
case orderAccepted:
continue
}
tempResp.Exchange = b.Name
tempResp.CurrencyPair = currency.NewPairFromString(tempData.Orders[c].MarketID)
tempResp.OrderSide = order.Bid
if tempData.Orders[c].Side == ask {
tempResp.OrderSide = order.Ask
}
tempResp.OrderDate = tempData.Orders[c].CreationTime
tempResp.Price = tempData.Orders[c].Price
tempResp.ExecutedAmount = tempData.Orders[c].Amount
resp = append(resp, tempResp)
}
return resp, nil
}
// SubscribeToWebsocketChannels appends to ChannelsToSubscribe

View File

@@ -193,12 +193,13 @@ type FiatWithdrawRequest struct {
GenericWithdrawRequestInfo
// FIAT related information
BankAccountName string
BankAccountNumber float64
BankAccountNumber string
BankName string
BankAddress string
BankCity string
BankCountry string
BankPostalCode string
BSB string
SwiftCode string
IBAN string
BankCode float64

View File

@@ -37,12 +37,14 @@ var (
// Submit contains the order submission data
type Submit struct {
Pair currency.Pair
OrderType Type
OrderSide Side
Price float64
Amount float64
ClientID string
Pair currency.Pair
OrderType Type
OrderSide Side
TriggerPrice float64
TargetAmount float64
Price float64
Amount float64
ClientID string
}
// SubmitResponse is what is returned after submitting an order to an exchange
@@ -161,17 +163,18 @@ type Status string
// All order status types
const (
AnyStatus Status = "ANY"
New Status = "NEW"
Active Status = "ACTIVE"
PartiallyFilled Status = "PARTIALLY_FILLED"
Filled Status = "FILLED"
Cancelled Status = "CANCELED"
PendingCancel Status = "PENDING_CANCEL"
Rejected Status = "REJECTED"
Expired Status = "EXPIRED"
Hidden Status = "HIDDEN"
UnknownStatus Status = "UNKNOWN"
AnyStatus Status = "ANY"
New Status = "NEW"
Active Status = "ACTIVE"
PartiallyCancelled Status = "PARTIALLY_CANCELLED"
PartiallyFilled Status = "PARTIALLY_FILLED"
Filled Status = "FILLED"
Cancelled Status = "CANCELED"
PendingCancel Status = "PENDING_CANCEL"
Rejected Status = "REJECTED"
Expired Status = "EXPIRED"
Hidden Status = "HIDDEN"
UnknownStatus Status = "UNKNOWN"
)
// ByPrice used for sorting orders by price