mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-17 15:09:59 +00:00
* orderbook/buffer: data integrity and resubscription pass * btcmarkets: REMOVE THAT LIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIINE!!!!!!!!!!!!!!!!! * buffer: reinstate publish, refaactor, invalidate more and comments * buffer/orderbook: improve update and snapshot performance. Move Update type to orderbook package to util. pointer through entire function calls. (cleanup). Change action string to uint8 for easier comparison. Add parsing helper. Update current test benchmark comments. * dispatch: change publish func to variadic id param * dispatch: remove sender receiver wait time as this adds overhead and complexity. update tests. * dispatch: don't create pointers for every job container * rpcserver: fix assertion issues with data publishing change * linter: fixes * glorious: nits addr * depth: change validation handling to incorporate and store err * linter: fix more issues * dispatch: fix race * travis: update before fetching * depth: wrap and return wrapped error in invalidate call and fix tests * btcmarkets: fix commenting * workflow: check * workflow: check * orderbook: check error * buffer/depth: return invalidation error and fix tests * gctcli: display errors on orderbook streams * buffer: remove unused types * orderbook/bitmex: shift function to bitmex * orderbook: Add specific comments to unexported functions that don't have locking require locking. * orderbook: restrict published data functionality to orderbook.Outbound interface * common: add assertion failure helper for error * dispatch: remove atomics, add mutex protection, remove add/remove worker, redo main tests * dispatch: export function * engine: revert and change sub logger to manager * engine: remove old test * dispatch: add common variable ;) * btcmarket: don't overflow int in tests on 32bit systems * ci: force 1.17.7 usage for go * Revert "ci: force 1.17.7 usage for go" This reverts commit af2f95563bf218cf2b9f36a9fcf3258e2c6a2d91. * golangci: bump version add and remove linter items * Revert "golangci: bump version add and remove linter items" This reverts commit 3c98bffc9d030e39faca0387ea40c151df2ab06b. * dispatch: remove unsused mutex from mux * order: slight optimizations * nits: glorious * dispatch: fix regression on uuid generation and input inline with master * linter: fix * linter: fix * glorious: nit - rm slice segration * account: fix test after merge * coinbasepro: revert change * account: close channel instead of needing a receiver, push alert in routine to prepare for waiter. Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
2200 lines
54 KiB
Go
2200 lines
54 KiB
Go
package ftx
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"log"
|
|
"math"
|
|
"os"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/shopspring/decimal"
|
|
"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/kline"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
|
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
|
)
|
|
|
|
// Please supply your own keys here to do authenticated endpoint testing
|
|
const (
|
|
apiKey = ""
|
|
apiSecret = ""
|
|
subaccount = ""
|
|
canManipulateRealOrders = false
|
|
spotPairStr = "FTT/BTC"
|
|
futuresPair = "DOGE-PERP"
|
|
testLeverageToken = "ADAMOON"
|
|
|
|
validFTTBTCStartTime = 1565445600 // Sat Aug 10 2019 14:00:00 GMT+0000
|
|
validFTTBTCEndTime = 1565532000 // Sat Aug 11 2019 14:00:00 GMT+0000
|
|
invalidFTTBTCStartTime = 1559881511 // Fri Jun 07 2019 04:25:11 GMT+0000
|
|
invalidFTTBTCEndTime = 1559901511 // Fri Jun 07 2019 09:58:31 GMT+0000
|
|
authStartTime = validFTTBTCStartTime // Adjust these to test auth requests
|
|
authEndTime = validFTTBTCEndTime
|
|
)
|
|
|
|
var (
|
|
f FTX
|
|
spotPair = currency.NewPair(currency.FTT, currency.BTC)
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
f.SetDefaults()
|
|
cfg := config.GetConfig()
|
|
err := cfg.LoadConfig("../../testdata/configtest.json", true)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
exchCfg, err := cfg.GetExchangeConfig("FTX")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
exchCfg.API.Credentials.Key = apiKey
|
|
exchCfg.API.Credentials.Secret = apiSecret
|
|
exchCfg.API.Credentials.Subaccount = subaccount
|
|
if apiKey != "" && apiSecret != "" {
|
|
// Only set auth to true when keys present as fee online calculation requires authentication
|
|
exchCfg.API.AuthenticatedSupport = true
|
|
exchCfg.API.AuthenticatedWebsocketSupport = true
|
|
}
|
|
f.Websocket = sharedtestvalues.NewTestWebsocket()
|
|
err = f.Setup(exchCfg)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
f.Websocket.DataHandler = sharedtestvalues.GetWebsocketInterfaceChannelOverride()
|
|
f.Websocket.TrafficAlert = sharedtestvalues.GetWebsocketStructChannelOverride()
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func areTestAPIKeysSet() bool {
|
|
return f.ValidateAPICredentials(f.GetDefaultCredentials()) == nil
|
|
}
|
|
|
|
// Implement tests for API endpoints below
|
|
|
|
func TestStart(t *testing.T) {
|
|
t.Parallel()
|
|
err := f.Start(nil)
|
|
if !errors.Is(err, common.ErrNilPointer) {
|
|
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer)
|
|
}
|
|
var testWg sync.WaitGroup
|
|
err = f.Start(&testWg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
testWg.Wait()
|
|
}
|
|
|
|
func TestGetMarkets(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.GetMarkets(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetHistoricalIndex(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.GetHistoricalIndex(context.Background(),
|
|
"BTC", 3600, time.Now().Add(-time.Hour*2), time.Now().Add(-time.Hour*1))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetHistoricalIndex(context.Background(),
|
|
"BTC", 3600, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarket(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.GetMarket(context.Background(), spotPairStr)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOrderbook(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.GetOrderbook(context.Background(), spotPairStr, 5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetTrades(t *testing.T) {
|
|
t.Parallel()
|
|
// test empty market
|
|
_, err := f.GetTrades(context.Background(), "", 0, 0, 200)
|
|
if err == nil {
|
|
t.Error("empty market should return an error")
|
|
}
|
|
_, err = f.GetTrades(context.Background(),
|
|
spotPairStr, validFTTBTCEndTime, validFTTBTCStartTime, 5)
|
|
if err != errStartTimeCannotBeAfterEndTime {
|
|
t.Errorf("should have thrown errStartTimeCannotBeAfterEndTime, got %v", err)
|
|
}
|
|
// test optional params
|
|
var trades []TradeData
|
|
trades, err = f.GetTrades(context.Background(), spotPairStr, 0, 0, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(trades) != 20 {
|
|
t.Error("default limit should return 20 items")
|
|
}
|
|
trades, err = f.GetTrades(context.Background(),
|
|
spotPairStr, validFTTBTCStartTime, validFTTBTCEndTime, 5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(trades) != 5 {
|
|
t.Error("limit of 5 should return 5 items")
|
|
}
|
|
trades, err = f.GetTrades(context.Background(),
|
|
spotPairStr, invalidFTTBTCStartTime, invalidFTTBTCEndTime, 5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(trades) != 0 {
|
|
t.Error("invalid time range should return 0 items")
|
|
}
|
|
}
|
|
|
|
func TestGetHistoricalData(t *testing.T) {
|
|
t.Parallel()
|
|
// test empty market
|
|
_, err := f.GetHistoricalData(context.Background(),
|
|
"", 86400, 5, time.Time{}, time.Time{})
|
|
if err == nil {
|
|
t.Error("empty market should return an error")
|
|
}
|
|
// test empty resolution
|
|
_, err = f.GetHistoricalData(context.Background(),
|
|
spotPairStr, 0, 5, time.Time{}, time.Time{})
|
|
if err == nil {
|
|
t.Error("empty resolution should return an error")
|
|
}
|
|
_, err = f.GetHistoricalData(context.Background(),
|
|
spotPairStr, 86400, 5, time.Unix(validFTTBTCEndTime, 0),
|
|
time.Unix(validFTTBTCStartTime, 0))
|
|
if err != errStartTimeCannotBeAfterEndTime {
|
|
t.Errorf("should have thrown errStartTimeCannotBeAfterEndTime, got %v", err)
|
|
}
|
|
var o []OHLCVData
|
|
o, err = f.GetHistoricalData(context.Background(),
|
|
spotPairStr, 86400, 5, time.Time{}, time.Time{})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(o) != 5 {
|
|
t.Error("limit of 5 should return 5 items")
|
|
}
|
|
o, err = f.GetHistoricalData(context.Background(),
|
|
spotPairStr, 86400, 5, time.Unix(invalidFTTBTCStartTime, 0),
|
|
time.Unix(invalidFTTBTCEndTime, 0))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(o) != 0 {
|
|
t.Error("invalid time range should return 0 items")
|
|
}
|
|
}
|
|
|
|
func TestGetFutures(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.GetFutures(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFuture(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.GetFuture(context.Background(), futuresPair)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFutureStats(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.GetFutureStats(context.Background(), "BTC-PERP")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
future, err := f.GetFutureStats(context.Background(), "BTC-MOVE-2021Q4")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if future.Greeks == nil {
|
|
t.Fatal("no greeks returned for futures contract")
|
|
}
|
|
}
|
|
|
|
func TestGetFundingRates(t *testing.T) {
|
|
t.Parallel()
|
|
// optional params
|
|
_, err := f.GetFundingRates(context.Background(), time.Time{}, time.Time{}, "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetFundingRates(context.Background(),
|
|
time.Now().Add(-time.Hour), time.Now(), "BTC-PERP")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetAccountInfo(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetAccountInfo(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetPositions(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetPositions(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetBalances(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetBalances(context.Background(), false, false)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetBalances(context.Background(), true, false)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetBalances(context.Background(), false, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetBalances(context.Background(), true, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetAllWalletBalances(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetAllWalletBalances(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestChangeAccountLeverage(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
err := f.ChangeAccountLeverage(context.Background(), 50)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetCoins(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetCoins(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarginBorrowRates(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetMarginBorrowRates(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarginLendingRates(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetMarginLendingRates(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestMarginDailyBorrowedAmounts(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.MarginDailyBorrowedAmounts(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarginMarketInfo(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetMarginMarketInfo(context.Background(), "BTC_USD")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarginBorrowHistory(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmNow := time.Now()
|
|
_, err := f.GetMarginBorrowHistory(context.Background(),
|
|
tmNow.AddDate(0, 0, 1),
|
|
tmNow)
|
|
if !errors.Is(err, errStartTimeCannotBeAfterEndTime) {
|
|
t.Errorf("expected %s, got %s", errStartTimeCannotBeAfterEndTime, err)
|
|
}
|
|
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err = f.GetMarginBorrowHistory(context.Background(),
|
|
tmNow.AddDate(0, 0, -1),
|
|
tmNow)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarginMarketLendingHistory(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmNow := time.Now()
|
|
_, err := f.GetMarginMarketLendingHistory(context.Background(),
|
|
currency.USD, tmNow.AddDate(0, 0, 1), tmNow)
|
|
if !errors.Is(err, errStartTimeCannotBeAfterEndTime) {
|
|
t.Errorf("expected %s, got %s", errStartTimeCannotBeAfterEndTime, err)
|
|
}
|
|
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("api keys not set")
|
|
}
|
|
_, err = f.GetMarginMarketLendingHistory(context.Background(),
|
|
currency.USD, tmNow.AddDate(0, 0, -1), tmNow)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarginLendingHistory(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmNow := time.Now()
|
|
_, err := f.GetMarginLendingHistory(context.Background(),
|
|
currency.USD, tmNow.AddDate(0, 0, 1), tmNow)
|
|
if !errors.Is(err, errStartTimeCannotBeAfterEndTime) {
|
|
t.Errorf("expected %s, got %s", errStartTimeCannotBeAfterEndTime, err)
|
|
}
|
|
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err = f.GetMarginLendingHistory(context.Background(),
|
|
currency.USD, tmNow.AddDate(0, 0, -1), tmNow)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarginLendingOffers(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetMarginLendingOffers(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetLendingInfo(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetLendingInfo(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestSubmitLendingOffer(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip()
|
|
}
|
|
if err := f.SubmitLendingOffer(context.Background(),
|
|
currency.NewCode("bTc"), 0.1, 500); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFetchDepositAddress(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
r, err := f.FetchDepositAddress(context.Background(), currency.NewCode("UsDt"), "trx")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if r.Method != "trx" {
|
|
t.Error("expected trx method")
|
|
}
|
|
}
|
|
|
|
func TestFetchDepositHistory(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.FetchDepositHistory(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFetchWithdrawalHistory(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.FetchWithdrawalHistory(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWithdraw(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.Withdraw(context.Background(),
|
|
currency.NewCode("UsDT"),
|
|
"TJU9piX2WA8WTvxVKMqpvTzZGhvXQAZKSY",
|
|
"",
|
|
"",
|
|
"trx",
|
|
"715913",
|
|
-1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetOpenOrders(context.Background(), "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetOpenOrders(context.Background(), spotPairStr)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFetchOrderHistory(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.FetchOrderHistory(context.Background(),
|
|
"", time.Time{}, time.Time{}, "2")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.FetchOrderHistory(context.Background(),
|
|
spotPairStr, time.Unix(authStartTime, 0), time.Unix(authEndTime, 0), "2")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.FetchOrderHistory(context.Background(),
|
|
spotPairStr, time.Unix(authEndTime, 0), time.Unix(authStartTime, 0), "2")
|
|
if err != errStartTimeCannotBeAfterEndTime {
|
|
t.Errorf("should have thrown errStartTimeCannotBeAfterEndTime, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetOpenTriggerOrders(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
// optional params
|
|
_, err := f.GetOpenTriggerOrders(context.Background(), "", "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetOpenTriggerOrders(context.Background(), spotPairStr, "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetTriggerOrderTriggers(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetTriggerOrderTriggers(context.Background(), "1031")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetTriggerOrderHistory(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetTriggerOrderHistory(context.Background(),
|
|
"", time.Time{}, time.Time{}, "", "", "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetTriggerOrderHistory(context.Background(),
|
|
spotPairStr, time.Time{}, time.Time{}, order.Buy.Lower(), "stop", "1")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetTriggerOrderHistory(context.Background(),
|
|
spotPairStr,
|
|
time.Unix(authStartTime, 0),
|
|
time.Unix(authEndTime, 0),
|
|
order.Buy.Lower(),
|
|
"stop",
|
|
"1")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetTriggerOrderHistory(context.Background(),
|
|
spotPairStr,
|
|
time.Unix(authEndTime, 0),
|
|
time.Unix(authStartTime, 0),
|
|
order.Buy.Lower(),
|
|
"stop",
|
|
"1")
|
|
if err != errStartTimeCannotBeAfterEndTime {
|
|
t.Errorf("should have thrown errStartTimeCannotBeAfterEndTime, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestOrder(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.Order(context.Background(),
|
|
spotPairStr,
|
|
order.Buy.Lower(),
|
|
"limit",
|
|
false, false, false,
|
|
"", 0.0001, 500)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestSubmitOrder(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isn't set correctly")
|
|
}
|
|
|
|
currencyPair, err := currency.NewPairFromString(spotPairStr)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var orderSubmission = &order.Submit{
|
|
Pair: currencyPair,
|
|
Side: order.Sell,
|
|
Type: order.Limit,
|
|
Price: 100000,
|
|
Amount: 1,
|
|
AssetType: asset.Spot,
|
|
ClientOrderID: "order12345679$$$$$",
|
|
}
|
|
_, err = f.SubmitOrder(context.Background(), orderSubmission)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestTriggerOrder(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.TriggerOrder(context.Background(),
|
|
spotPairStr,
|
|
order.Buy.Lower(),
|
|
order.Stop.Lower(),
|
|
"", "",
|
|
500, 0.0004, 0.0001, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCancelOrder(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isn't set correctly")
|
|
}
|
|
|
|
currencyPair, err := currency.NewPairFromString(spotPairStr)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
c := order.Cancel{
|
|
ID: "12366984218",
|
|
Pair: currencyPair,
|
|
AssetType: asset.Spot,
|
|
}
|
|
if err := f.CancelOrder(context.Background(), &c); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
c.ClientOrderID = "1337"
|
|
if err := f.CancelOrder(context.Background(), &c); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestDeleteOrder(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.DeleteOrder(context.Background(), "1031")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestDeleteOrderByClientID(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.DeleteOrderByClientID(context.Background(), "clientID123")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestDeleteTriggerOrder(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.DeleteTriggerOrder(context.Background(), "1031")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFills(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetFills(context.Background(),
|
|
currency.Pair{}, asset.Futures, time.Now().Add(time.Hour*24*365), time.Now())
|
|
if !errors.Is(err, errStartTimeCannotBeAfterEndTime) {
|
|
t.Errorf("received '%v' expected '%v'", err, errStartTimeCannotBeAfterEndTime)
|
|
}
|
|
|
|
_, err = f.GetFills(context.Background(),
|
|
currency.Pair{}, asset.Futures, time.Time{}, time.Time{})
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
_, err = f.GetFills(context.Background(),
|
|
currency.Pair{}, asset.Futures, time.Now().Add(-time.Hour*24*365), time.Now())
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
|
|
_, err = f.GetFills(context.Background(),
|
|
spotPair, asset.Spot, time.Now().Add(-time.Hour*24*365), time.Now())
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
}
|
|
|
|
func TestGetFundingPayments(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
// optional params
|
|
_, err := f.GetFundingPayments(context.Background(),
|
|
time.Time{}, time.Time{}, "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetFundingPayments(context.Background(),
|
|
time.Unix(authStartTime, 0), time.Unix(authEndTime, 0), futuresPair)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetFundingPayments(context.Background(),
|
|
time.Unix(authEndTime, 0), time.Unix(authStartTime, 0), futuresPair)
|
|
if err != errStartTimeCannotBeAfterEndTime {
|
|
t.Errorf("should have thrown errStartTimeCannotBeAfterEndTime, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestListLeveragedTokens(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.ListLeveragedTokens(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetTokenInfo(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetTokenInfo(context.Background(), "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestListLTBalances(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.ListLTBalances(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestListLTCreations(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.ListLTCreations(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestRequestLTCreation(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.RequestLTCreation(context.Background(), testLeverageToken, 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestListLTRedemptions(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.ListLTRedemptions(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetQuoteRequests(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetQuoteRequests(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetYourQuoteRequests(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetYourQuoteRequests(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCreateQuoteRequest(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.CreateQuoteRequest(context.Background(),
|
|
currency.BTC, "call", order.Buy.Lower(), 1593140400, "", 10, 10, 5, 0, false)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestDeleteQuote(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.DeleteQuote(context.Background(), "1031")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetQuotesForYourQuote(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetQuotesForYourQuote(context.Background(), "1031")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestMakeQuote(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.MakeQuote(context.Background(), "1031", "5")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestMyQuotes(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.MyQuotes(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestDeleteMyQuote(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.DeleteMyQuote(context.Background(), "1031")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestAcceptQuote(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.AcceptQuote(context.Background(), "1031")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetAccountOptionsInfo(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetAccountOptionsInfo(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOptionsPositions(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetOptionsPositions(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetPublicOptionsTrades(t *testing.T) {
|
|
t.Parallel()
|
|
// test optional params
|
|
result, err := f.GetPublicOptionsTrades(context.Background(),
|
|
time.Time{}, time.Time{}, "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(result) != 20 {
|
|
t.Error("default limit should have returned 20 items")
|
|
}
|
|
tmNow := time.Now()
|
|
result, err = f.GetPublicOptionsTrades(context.Background(),
|
|
tmNow.AddDate(-1, 0, 0), tmNow, "5")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(result) > 5 {
|
|
t.Error("limit of 5 should not exceed 5 items")
|
|
}
|
|
_, err = f.GetPublicOptionsTrades(context.Background(),
|
|
time.Unix(validFTTBTCEndTime, 0), time.Unix(validFTTBTCStartTime, 0), "5")
|
|
if err != errStartTimeCannotBeAfterEndTime {
|
|
t.Errorf("should have thrown errStartTimeCannotBeAfterEndTime, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetOptionsFills(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetOptionsFills(context.Background(), time.Time{}, time.Time{}, "5")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetOptionsFills(context.Background(),
|
|
time.Unix(authStartTime, 0), time.Unix(authEndTime, 0), "5")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetOptionsFills(context.Background(),
|
|
time.Unix(authEndTime, 0), time.Unix(authStartTime, 0), "5")
|
|
if err != errStartTimeCannotBeAfterEndTime {
|
|
t.Errorf("should have thrown errStartTimeCannotBeAfterEndTime, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateOrderbook(t *testing.T) {
|
|
t.Parallel()
|
|
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "/")
|
|
_, err := f.UpdateOrderbook(context.Background(), cp, asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
cp = currency.NewPairWithDelimiter("ALGOBEAR", currency.USD.String(), "/")
|
|
_, err = f.UpdateOrderbook(context.Background(), cp, asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
cp = currency.NewPairWithDelimiter("ASDBEAR", currency.USD.String(), "/")
|
|
_, err = f.UpdateOrderbook(context.Background(), cp, asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateTicker(t *testing.T) {
|
|
t.Parallel()
|
|
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "/")
|
|
_, err := f.UpdateTicker(context.Background(), cp, asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateTickers(t *testing.T) {
|
|
t.Parallel()
|
|
err := f.UpdateTickers(context.Background(), asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetActiveOrders(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("API keys required but not set, skipping test")
|
|
}
|
|
var orderReq order.GetOrdersRequest
|
|
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "/")
|
|
orderReq.Pairs = append(orderReq.Pairs, cp)
|
|
orderReq.AssetType = asset.Spot
|
|
_, err := f.GetActiveOrders(context.Background(), &orderReq)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOrderHistory(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("API keys required but not set, skipping test")
|
|
}
|
|
var orderReq order.GetOrdersRequest
|
|
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "/")
|
|
orderReq.Pairs = append(orderReq.Pairs, cp)
|
|
orderReq.AssetType = asset.Spot
|
|
_, err := f.GetOrderHistory(context.Background(), &orderReq)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateAccountHoldings(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("API keys required but not set, skipping test")
|
|
}
|
|
_, err := f.UpdateAccountInfo(context.Background(), asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFetchAccountInfo(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("API keys required but not set, skipping test")
|
|
}
|
|
_, err := f.FetchAccountInfo(context.Background(), asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFee(t *testing.T) {
|
|
t.Parallel()
|
|
feeBuilder := &exchange.FeeBuilder{
|
|
PurchasePrice: 10,
|
|
Amount: 1,
|
|
IsMaker: true,
|
|
}
|
|
fee, err := f.GetFee(context.Background(), feeBuilder)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if fee <= 0 {
|
|
t.Errorf("incorrect maker fee value")
|
|
}
|
|
|
|
feeBuilder.IsMaker = false
|
|
if fee, err = f.GetFee(context.Background(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if fee <= 0 {
|
|
t.Errorf("incorrect maker fee value")
|
|
}
|
|
|
|
feeBuilder.FeeType = exchange.OfflineTradeFee
|
|
fee, err = f.GetFee(context.Background(), feeBuilder)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if fee <= 0 {
|
|
t.Errorf("incorrect maker fee value")
|
|
}
|
|
|
|
feeBuilder.IsMaker = true
|
|
fee, err = f.GetFee(context.Background(), feeBuilder)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if fee <= 0 {
|
|
t.Errorf("incorrect maker fee value")
|
|
}
|
|
}
|
|
|
|
func TestGetOfflineTradingFee(t *testing.T) {
|
|
t.Parallel()
|
|
var f exchange.FeeBuilder
|
|
f.PurchasePrice = 10
|
|
f.Amount = 1
|
|
f.IsMaker = true
|
|
fee := getOfflineTradeFee(&f)
|
|
if fee != 0.002 {
|
|
t.Errorf("incorrect offline maker fee")
|
|
}
|
|
f.IsMaker = false
|
|
fee = getOfflineTradeFee(&f)
|
|
if fee != 0.007 {
|
|
t.Errorf("incorrect offline taker fee")
|
|
}
|
|
}
|
|
|
|
func TestGetOrderStatus(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("API keys required but not set, skipping test")
|
|
}
|
|
_, err := f.GetOrderStatus(context.Background(), "1031")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOrderStatusByClientID(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("API keys required but not set, skipping test")
|
|
}
|
|
_, err := f.GetOrderStatusByClientID(context.Background(), "testID")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestRequestLTRedemption(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("API keys required but not set, skipping test")
|
|
}
|
|
_, err := f.RequestLTRedemption(context.Background(), "ETHBULL", 5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWithdrawCryptocurrencyFunds(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
var request = new(withdraw.Request)
|
|
request.Amount = 5
|
|
request.Currency = currency.NewCode("FTT")
|
|
var cryptoData withdraw.CryptoRequest
|
|
cryptoData.Address = "testaddress123"
|
|
cryptoData.AddressTag = "testtag123"
|
|
request.Crypto = cryptoData
|
|
request.OneTimePassword = 123456
|
|
request.TradePassword = "incorrectTradePassword"
|
|
_, err := f.WithdrawCryptocurrencyFunds(context.Background(), request)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetDepositAddress(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("API keys required but not set, skipping test")
|
|
}
|
|
_, err := f.GetDepositAddress(context.Background(), currency.NewCode("FTT"), "", "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFundingHistory(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("API keys required but not set, skipping test")
|
|
}
|
|
_, err := f.GetFundingHistory(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetHistoricCandles(t *testing.T) {
|
|
t.Parallel()
|
|
currencyPair, err := currency.NewPairFromString("BTC/USD")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
start := time.Date(2019, 11, 12, 0, 0, 0, 0, time.UTC)
|
|
end := start.AddDate(0, 0, 2)
|
|
_, err = f.GetHistoricCandles(context.Background(),
|
|
currencyPair, asset.Spot, start, end, kline.OneDay)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGetHistoricCandlesExtended(t *testing.T) {
|
|
t.Parallel()
|
|
currencyPair, err := currency.NewPairFromString("BTC/USD")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
start := time.Date(2019, 11, 12, 0, 0, 0, 0, time.UTC)
|
|
end := start.AddDate(0, 0, 2)
|
|
_, err = f.GetHistoricCandlesExtended(context.Background(),
|
|
currencyPair, asset.Spot, start, end, kline.OneDay)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOTCQuoteStatus(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("API keys required but not set, skipping test")
|
|
}
|
|
_, err := f.GetOTCQuoteStatus(context.Background(), spotPairStr, "1")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestRequestForQuotes(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.RequestForQuotes(context.Background(),
|
|
currency.NewCode("BtC"), currency.NewCode("UsD"), 0.5)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestAcceptOTCQuote(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
err := f.AcceptOTCQuote(context.Background(), "1031")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetHistoricTrades(t *testing.T) {
|
|
t.Parallel()
|
|
assets := f.GetAssetTypes(false)
|
|
for i := range assets {
|
|
enabledPairs, err := f.GetEnabledPairs(assets[i])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err = f.GetHistoricTrades(context.Background(),
|
|
enabledPairs.GetRandomPair(),
|
|
assets[i],
|
|
time.Now().Add(-time.Minute*15),
|
|
time.Now())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetRecentTrades(t *testing.T) {
|
|
t.Parallel()
|
|
assets := f.GetAssetTypes(false)
|
|
for i := range assets {
|
|
enabledPairs, err := f.GetEnabledPairs(assets[i])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err = f.GetRecentTrades(context.Background(),
|
|
enabledPairs.GetRandomPair(), assets[i])
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTimestampFromFloat64(t *testing.T) {
|
|
t.Parallel()
|
|
constTime := 1592697600.0
|
|
checkTime := time.Date(2020, time.June, 21, 0, 0, 0, 0, time.UTC)
|
|
timeConst := timestampFromFloat64(constTime)
|
|
if timeConst != checkTime {
|
|
t.Error("invalid time conversion")
|
|
}
|
|
}
|
|
|
|
func TestCompatibleOrderVars(t *testing.T) {
|
|
t.Parallel()
|
|
orderVars, err := f.compatibleOrderVars(context.Background(),
|
|
"buy",
|
|
"closed",
|
|
"limit",
|
|
0.5,
|
|
0.5,
|
|
9500)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if orderVars.Side != order.Buy {
|
|
t.Errorf("received %v expected %v", orderVars.Side, order.Buy)
|
|
}
|
|
if orderVars.OrderType != order.Limit {
|
|
t.Errorf("received %v expected %v", orderVars.OrderType, order.Limit)
|
|
}
|
|
if orderVars.Status != order.Filled {
|
|
t.Errorf("received %v expected %v", orderVars.Status, order.Filled)
|
|
}
|
|
|
|
orderVars, err = f.compatibleOrderVars(context.Background(),
|
|
"buy",
|
|
"closed",
|
|
"limit",
|
|
0,
|
|
0,
|
|
9500)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received %v expected %v", err, nil)
|
|
}
|
|
if orderVars.Status != order.Cancelled {
|
|
t.Errorf("received %v expected %v", orderVars.Status, order.Cancelled)
|
|
}
|
|
|
|
orderVars, err = f.compatibleOrderVars(context.Background(),
|
|
"buy",
|
|
"closed",
|
|
"limit",
|
|
0.5,
|
|
0.2,
|
|
9500)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received %v expected %v", err, nil)
|
|
}
|
|
if orderVars.Status != order.PartiallyCancelled {
|
|
t.Errorf("received %v expected %v", orderVars.Status, order.PartiallyCancelled)
|
|
}
|
|
|
|
orderVars, err = f.compatibleOrderVars(context.Background(),
|
|
"sell",
|
|
"closed",
|
|
"limit",
|
|
1337,
|
|
1337,
|
|
9500)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received %v expected %v", err, nil)
|
|
}
|
|
if orderVars.Status != order.Filled {
|
|
t.Errorf("received %v expected %v", orderVars.Status, order.Filled)
|
|
}
|
|
|
|
_, err = f.compatibleOrderVars(context.Background(),
|
|
"buy",
|
|
"closed",
|
|
"limit",
|
|
0.1,
|
|
0.2,
|
|
9500)
|
|
if !errors.Is(err, errInvalidOrderAmounts) {
|
|
t.Errorf("received %v expected %v", err, errInvalidOrderAmounts)
|
|
}
|
|
|
|
_, err = f.compatibleOrderVars(context.Background(),
|
|
"buy",
|
|
"fake",
|
|
"limit",
|
|
0.3,
|
|
0.2,
|
|
9500)
|
|
if !errors.Is(err, errUnrecognisedOrderStatus) {
|
|
t.Errorf("received %v expected %v", err, errUnrecognisedOrderStatus)
|
|
}
|
|
|
|
orderVars, err = f.compatibleOrderVars(context.Background(),
|
|
"buy",
|
|
"new",
|
|
"limit",
|
|
0.3,
|
|
0.2,
|
|
9500)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received %v expected %v", err, nil)
|
|
}
|
|
if orderVars.Status != order.New {
|
|
t.Errorf("received %v expected %v", orderVars.Status, order.New)
|
|
}
|
|
|
|
orderVars, err = f.compatibleOrderVars(context.Background(),
|
|
"buy",
|
|
"open",
|
|
"limit",
|
|
0.3,
|
|
0.2,
|
|
9500)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received %v expected %v", err, nil)
|
|
}
|
|
if orderVars.Status != order.Open {
|
|
t.Errorf("received %v expected %v", orderVars.Status, order.Open)
|
|
}
|
|
}
|
|
|
|
func TestGetIndexWeights(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.GetIndexWeights(context.Background(), "SHIT")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestModifyPlacedOrder(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.ModifyPlacedOrder(context.Background(), "1234", "", -0.1, 0.1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestModifyOrderByClientID(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.ModifyOrderByClientID(context.Background(), "1234", "", -0.1, 0.1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestModifyTriggerOrder(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
|
|
}
|
|
_, err := f.ModifyTriggerOrder(context.Background(),
|
|
"1234", "stop", -0.1, 0.1, 0.02, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetSubaccounts(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("skipping test, api keys not set")
|
|
}
|
|
_, err := f.GetSubaccounts(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCreateSubaccount(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.CreateSubaccount(context.Background(), "")
|
|
if !errors.Is(err, errSubaccountNameMustBeSpecified) {
|
|
t.Errorf("expected %v, but received: %s", errSubaccountNameMustBeSpecified, err)
|
|
}
|
|
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isn't set")
|
|
}
|
|
_, err = f.CreateSubaccount(context.Background(), "subzero")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = f.DeleteSubaccount(context.Background(), "subzero"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateSubaccountName(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.UpdateSubaccountName(context.Background(), "", "")
|
|
if !errors.Is(err, errSubaccountUpdateNameInvalid) {
|
|
t.Errorf("expected %v, but received: %s", errSubaccountUpdateNameInvalid, err)
|
|
}
|
|
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isn't set")
|
|
}
|
|
_, err = f.CreateSubaccount(context.Background(), "subzero")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err = f.UpdateSubaccountName(context.Background(), "subzero", "bizzlebot")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.DeleteSubaccount(context.Background(), "bizzlebot"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestDeleteSubaccountName(t *testing.T) {
|
|
t.Parallel()
|
|
if err := f.DeleteSubaccount(context.Background(), ""); !errors.Is(err, errSubaccountNameMustBeSpecified) {
|
|
t.Errorf("expected %v, but received: %s", errSubaccountNameMustBeSpecified, err)
|
|
}
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isn't set")
|
|
}
|
|
_, err := f.CreateSubaccount(context.Background(), "subzero")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.DeleteSubaccount(context.Background(), "subzero"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestSubaccountBalances(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.SubaccountBalances(context.Background(), "")
|
|
if !errors.Is(err, errSubaccountNameMustBeSpecified) {
|
|
t.Errorf("expected %s, but received: %s", errSubaccountNameMustBeSpecified, err)
|
|
}
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("skipping test, api keys not set")
|
|
}
|
|
_, err = f.SubaccountBalances(context.Background(), "non-existent")
|
|
if err == nil {
|
|
t.Error("expecting non-existent subaccount to return an error")
|
|
}
|
|
_, err = f.CreateSubaccount(context.Background(), "subzero")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err = f.SubaccountBalances(context.Background(), "subzero")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := f.DeleteSubaccount(context.Background(), "subzero"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestSubaccountTransfer(t *testing.T) {
|
|
t.Parallel()
|
|
tt := []struct {
|
|
Coin currency.Code
|
|
Source string
|
|
Destination string
|
|
Size float64
|
|
ErrExpected error
|
|
}{
|
|
{ErrExpected: errCoinMustBeSpecified},
|
|
{Coin: currency.BTC, ErrExpected: errSubaccountTransferSizeGreaterThanZero},
|
|
{Coin: currency.BTC, Size: 420, ErrExpected: errSubaccountTransferSourceDestinationMustNotBeEqual},
|
|
}
|
|
for x := range tt {
|
|
_, err := f.SubaccountTransfer(context.Background(),
|
|
tt[x].Coin, tt[x].Source, tt[x].Destination, tt[x].Size)
|
|
if !errors.Is(err, tt[x].ErrExpected) {
|
|
t.Errorf("expected %s, but received: %s", tt[x].ErrExpected, err)
|
|
}
|
|
}
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isn't set")
|
|
}
|
|
_, err := f.SubaccountTransfer(context.Background(),
|
|
currency.BTC, "", "test", 0.1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetStakes(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("skipping test, api keys not set")
|
|
}
|
|
_, err := f.GetStakes(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetUnstakeRequests(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("skipping test, api keys not set")
|
|
}
|
|
_, err := f.GetUnstakeRequests(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetStakeBalances(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("skipping test, api keys not set")
|
|
}
|
|
_, err := f.GetStakeBalances(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUnstakeRequest(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isn't set")
|
|
}
|
|
r, err := f.UnstakeRequest(context.Background(), currency.FTT, 0.1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
success, err := f.CancelUnstakeRequest(context.Background(), r.ID)
|
|
if err != nil || !success {
|
|
t.Errorf("unable to cancel unstaking request: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestCancelUnstakeRequest(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isn't set")
|
|
}
|
|
_, err := f.CancelUnstakeRequest(context.Background(), 74351)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetStakingRewards(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("skipping test, api keys not set")
|
|
}
|
|
_, err := f.GetStakingRewards(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestStakeRequest(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
|
t.Skip("skipping test, either api keys or canManipulateRealOrders isn't set")
|
|
}
|
|
|
|
// WARNING: This will lock up your funds for 14 days
|
|
_, err := f.StakeRequest(context.Background(), currency.FTT, 0.1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateOrderExecutionLimits(t *testing.T) {
|
|
t.Parallel()
|
|
err := f.UpdateOrderExecutionLimits(context.Background(), asset.Empty)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cp := currency.NewPair(currency.BTC, currency.USD)
|
|
limit, err := f.GetOrderExecutionLimits(asset.Spot, cp)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = limit.Conforms(33000, 0.00001, order.Limit)
|
|
if !errors.Is(err, order.ErrAmountBelowMin) {
|
|
t.Fatalf("expected error %v but received %v",
|
|
order.ErrAmountBelowMin,
|
|
err)
|
|
}
|
|
|
|
err = limit.Conforms(33000, 0.0001, order.Limit)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("expected error %v but received %v",
|
|
nil,
|
|
err)
|
|
}
|
|
}
|
|
|
|
func TestScaleCollateral(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
result, err := f.ScaleCollateral(
|
|
context.Background(),
|
|
&order.CollateralCalculator{
|
|
CollateralCurrency: currency.USDT,
|
|
Asset: asset.Spot,
|
|
Side: order.Buy,
|
|
CalculateOffline: true,
|
|
FreeCollateral: decimal.NewFromInt(100000),
|
|
USDPrice: decimal.NewFromFloat(1.0003),
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
expectedUSDValue := decimal.NewFromFloat(97529.25)
|
|
if !result.CollateralContribution.Equal(expectedUSDValue) {
|
|
t.Errorf("received %v expected %v", result.CollateralContribution, expectedUSDValue)
|
|
}
|
|
|
|
if !areTestAPIKeysSet() {
|
|
return
|
|
}
|
|
accountInfo, err := f.GetAccountInfo(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
walletInfo, err := f.GetAllWalletBalances(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
localScaling := 0.0
|
|
providedUSDValue := 0.0
|
|
for _, v := range walletInfo {
|
|
for v2 := range v {
|
|
coin := v[v2].Coin
|
|
if coin.Equal(currency.USD) {
|
|
localScaling += v[v2].Total
|
|
providedUSDValue += v[v2].USDValue
|
|
continue
|
|
}
|
|
var tick MarketData
|
|
tick, err = f.GetMarket(context.Background(), currency.NewPairWithDelimiter(coin.String(), "usd", "/").String())
|
|
if err != nil {
|
|
// not all markets exist like this, skip
|
|
continue
|
|
}
|
|
_, err = f.ScaleCollateral(
|
|
context.Background(),
|
|
&order.CollateralCalculator{
|
|
CollateralCurrency: coin,
|
|
Asset: asset.Spot,
|
|
Side: order.Buy,
|
|
FreeCollateral: decimal.NewFromFloat(v[v2].Total),
|
|
USDPrice: decimal.NewFromFloat(tick.Price),
|
|
CalculateOffline: true,
|
|
})
|
|
if err != nil {
|
|
if errors.Is(err, errCollateralCurrencyNotFound) ||
|
|
errors.Is(err, order.ErrUSDValueRequired) {
|
|
continue
|
|
}
|
|
t.Error(err)
|
|
}
|
|
providedUSDValue += v[v2].USDValue
|
|
_, err = f.ScaleCollateral(context.Background(),
|
|
&order.CollateralCalculator{
|
|
CollateralCurrency: coin,
|
|
Asset: asset.Spot,
|
|
Side: order.Buy,
|
|
FreeCollateral: decimal.NewFromFloat(v[v2].Total),
|
|
USDPrice: decimal.NewFromFloat(tick.Price),
|
|
IsForNewPosition: true,
|
|
CalculateOffline: true,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.ScaleCollateral(context.Background(),
|
|
&order.CollateralCalculator{
|
|
CollateralCurrency: coin,
|
|
Asset: asset.Spot,
|
|
Side: order.Buy,
|
|
FreeCollateral: decimal.NewFromFloat(v[v2].Total),
|
|
USDPrice: decimal.Zero,
|
|
IsLiquidating: true,
|
|
CalculateOffline: true,
|
|
})
|
|
if !errors.Is(err, order.ErrUSDValueRequired) {
|
|
t.Errorf("received '%v' exepected '%v'", err, order.ErrUSDValueRequired)
|
|
}
|
|
|
|
_, err = f.ScaleCollateral(
|
|
context.Background(),
|
|
&order.CollateralCalculator{
|
|
CollateralCurrency: coin,
|
|
Asset: asset.Spot,
|
|
Side: order.Buy,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
if accountInfo.Collateral == 0 {
|
|
return
|
|
}
|
|
if (math.Abs((localScaling-accountInfo.Collateral)/accountInfo.Collateral) * 100) > 5 {
|
|
t.Errorf("collateral scaling less than 95%% accurate, received '%v' expected roughly '%v'", localScaling, accountInfo.Collateral)
|
|
}
|
|
}
|
|
|
|
func TestCalculateTotalCollateral(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("skipping test, api keys not set")
|
|
}
|
|
walletInfo, err := f.GetAllWalletBalances(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
var scales []order.CollateralCalculator
|
|
for _, v := range walletInfo {
|
|
for v2 := range v {
|
|
coin := v[v2].Coin
|
|
if coin.Equal(currency.USD) {
|
|
total := decimal.NewFromFloat(v[v2].Total)
|
|
scales = append(scales, order.CollateralCalculator{
|
|
CollateralCurrency: coin,
|
|
Asset: asset.Spot,
|
|
Side: order.Buy,
|
|
FreeCollateral: total,
|
|
USDPrice: total,
|
|
CalculateOffline: true,
|
|
})
|
|
continue
|
|
}
|
|
var tick MarketData
|
|
tick, err = f.GetMarket(context.Background(), currency.NewPairWithDelimiter(coin.String(), "usd", "/").String())
|
|
if err != nil {
|
|
// some assumed markets don't exist, just don't process them
|
|
t.Log(err)
|
|
continue
|
|
}
|
|
if tick.Price == 0 {
|
|
continue
|
|
}
|
|
scales = append(scales, order.CollateralCalculator{
|
|
CollateralCurrency: coin,
|
|
Asset: asset.Spot,
|
|
Side: order.Buy,
|
|
FreeCollateral: decimal.NewFromFloat(v[v2].Total),
|
|
USDPrice: decimal.NewFromFloat(tick.Price),
|
|
CalculateOffline: true,
|
|
})
|
|
}
|
|
}
|
|
calc := &order.TotalCollateralCalculator{
|
|
CollateralAssets: scales,
|
|
FetchPositions: false,
|
|
CalculateOffline: true,
|
|
}
|
|
total, err := f.CalculateTotalCollateral(context.Background(), calc)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
localScaling := total.AvailableCollateral.InexactFloat64()
|
|
accountInfo, err := f.GetAccountInfo(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if accountInfo.Collateral != 0 && (math.Abs((localScaling-accountInfo.Collateral)/accountInfo.Collateral)*100) > 5 {
|
|
t.Errorf("collateral scaling less than 95%% accurate, received '%v' expected roughly '%v'", localScaling, accountInfo.Collateral)
|
|
}
|
|
|
|
for i := range scales {
|
|
scales[i].CalculateOffline = false
|
|
}
|
|
calc.CalculateOffline = false
|
|
_, err = f.CalculateTotalCollateral(context.Background(), calc)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCalculateTotalCollateralOnline(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("skipping test, api keys not set")
|
|
}
|
|
// nil data
|
|
_, err := f.calculateTotalCollateralOnline(context.Background(), nil, nil)
|
|
if !errors.Is(err, common.ErrNilPointer) {
|
|
t.Errorf("received '%v' expected '%v'", err, common.ErrNilPointer)
|
|
}
|
|
calc := &order.TotalCollateralCalculator{}
|
|
// no currency data
|
|
_, err = f.calculateTotalCollateralOnline(context.Background(), calc, nil)
|
|
if !errors.Is(err, errCollateralCurrencyNotFound) {
|
|
t.Errorf("received '%v' expected '%v'", err, errCollateralCurrencyNotFound)
|
|
}
|
|
calc.CalculateOffline = true
|
|
calc.CollateralAssets = []order.CollateralCalculator{
|
|
{
|
|
CollateralCurrency: currency.BTC,
|
|
},
|
|
{
|
|
CollateralCurrency: currency.USD,
|
|
},
|
|
}
|
|
// offline true
|
|
_, err = f.calculateTotalCollateralOnline(context.Background(), calc, nil)
|
|
if !errors.Is(err, order.ErrOfflineCalculationSet) {
|
|
t.Errorf("received '%v' expected '%v'", err, order.ErrOfflineCalculationSet)
|
|
}
|
|
|
|
calc.CalculateOffline = false
|
|
calc.CollateralAssets[0].CalculateOffline = true
|
|
// offline true for individual currency
|
|
_, err = f.calculateTotalCollateralOnline(context.Background(), calc, nil)
|
|
if !errors.Is(err, order.ErrOfflineCalculationSet) {
|
|
t.Errorf("received '%v' expected '%v'", err, order.ErrOfflineCalculationSet)
|
|
}
|
|
// successful run
|
|
calc.CollateralAssets[0].CalculateOffline = false
|
|
result, err := f.calculateTotalCollateralOnline(context.Background(), calc, nil)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if !result.CollateralCurrency.Equal(currency.USD) {
|
|
t.Error("expected USD collateral currency")
|
|
}
|
|
curr, err := currency.NewPairFromString("BTC-PERP")
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
// with position data
|
|
pos := []PositionData{
|
|
{
|
|
CollateralUsed: 5,
|
|
Future: curr,
|
|
UnrealizedPNL: 10,
|
|
},
|
|
}
|
|
_, err = f.calculateTotalCollateralOnline(context.Background(), calc, pos)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
calc.CollateralAssets = []order.CollateralCalculator{
|
|
{
|
|
CollateralCurrency: currency.BURST,
|
|
},
|
|
}
|
|
// irrelevant currency
|
|
result, err = f.calculateTotalCollateralOnline(context.Background(), calc, pos)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if !result.UnrealisedPNL.IsZero() {
|
|
t.Error("expected zero")
|
|
}
|
|
}
|
|
|
|
func TestCalculatePNL(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("skipping test, api keys not set")
|
|
}
|
|
pair := currency.NewPair(currency.BTC, currency.NewCode("20211231"))
|
|
positions, err := f.GetFuturesPositions(context.Background(), asset.Futures, pair, time.Date(2021, 1, 6, 4, 28, 0, 0, time.UTC), time.Date(2021, 12, 31, 4, 32, 0, 0, time.UTC))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
orders := make([]order.Detail, len(positions))
|
|
for i := range positions {
|
|
orders[i] = order.Detail{
|
|
Side: positions[i].Side,
|
|
Pair: pair,
|
|
ID: positions[i].ID,
|
|
Price: positions[i].Price,
|
|
Amount: positions[i].Amount,
|
|
AssetType: asset.Futures,
|
|
Exchange: f.Name,
|
|
Fee: positions[i].Fee,
|
|
Date: positions[i].Date,
|
|
}
|
|
}
|
|
|
|
exch := f.Name
|
|
item := asset.Futures
|
|
setup := &order.MultiPositionTrackerSetup{
|
|
Exchange: exch,
|
|
Asset: item,
|
|
Pair: pair,
|
|
Underlying: pair.Base,
|
|
UseExchangePNLCalculation: true,
|
|
ExchangePNLCalculation: &f,
|
|
}
|
|
p, err := order.SetupMultiPositionTracker(setup)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
for i := range orders {
|
|
err = p.TrackNewOrder(&orders[i])
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
results := p.GetPositions()
|
|
if len(orders) > 0 && len(results) == 0 {
|
|
t.Error("expected position(s) to be generated")
|
|
}
|
|
}
|
|
|
|
func TestGetFuturesPositions(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip("skipping test, api keys not set")
|
|
}
|
|
cp := currency.NewPair(currency.BTC, currency.NewCode("20211231"))
|
|
start := time.Now().Add(-time.Hour * 24 * 365)
|
|
end := time.Now()
|
|
a := asset.Futures
|
|
_, err := f.GetFuturesPositions(context.Background(), a, cp, start, end)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestLoadCollateralWeightings(t *testing.T) {
|
|
t.Parallel()
|
|
ff := FTX{}
|
|
err := ff.LoadCollateralWeightings(context.Background())
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if len(ff.collateralWeight) == 0 {
|
|
t.Fatal("expected some weight")
|
|
}
|
|
if !ff.collateralWeight.hasData() {
|
|
t.Error("expected loaded weight")
|
|
}
|
|
if !areTestAPIKeysSet() {
|
|
return
|
|
}
|
|
err = f.LoadCollateralWeightings(context.Background())
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
if len(f.collateralWeight) == 0 {
|
|
t.Fatal("expected some weight")
|
|
}
|
|
}
|
|
|
|
func TestLoadTotalIMF(t *testing.T) {
|
|
t.Parallel()
|
|
c := CollateralWeightHolder{}
|
|
c.loadTotal("BTC", 1)
|
|
if _, ok := c[currency.BTC.Item]; !ok {
|
|
t.Error("expected entry")
|
|
}
|
|
c.loadInitialMarginFraction("btc", 1)
|
|
cw, ok := c[currency.BTC.Item]
|
|
if !ok {
|
|
t.Error("expected entry")
|
|
}
|
|
if cw.Total != 1 {
|
|
t.Errorf("expected '1', received '%v'", cw.Total)
|
|
}
|
|
if cw.InitialMarginFractionFactor != 1 {
|
|
t.Errorf("expected '1', received '%v'", cw.InitialMarginFractionFactor)
|
|
}
|
|
}
|
|
|
|
func TestLoadCollateralWeight(t *testing.T) {
|
|
t.Parallel()
|
|
c := CollateralWeightHolder{}
|
|
c.load("DOGE", 1, 2, 3)
|
|
cw, ok := c[currency.DOGE.Item]
|
|
if !ok {
|
|
t.Fatal("expected loaded collateral weight")
|
|
}
|
|
if cw.Total != 1 {
|
|
t.Errorf("expected '1', received '%v'", cw.Total)
|
|
}
|
|
if cw.Initial != 2 {
|
|
t.Errorf("expected '2', received '%v'", cw.Initial)
|
|
}
|
|
if cw.InitialMarginFractionFactor != 3 {
|
|
t.Errorf("expected '3', received '%v'", cw.InitialMarginFractionFactor)
|
|
}
|
|
}
|
|
|
|
func TestCollateralWeightHasData(t *testing.T) {
|
|
t.Parallel()
|
|
c := CollateralWeightHolder{}
|
|
if c.hasData() {
|
|
t.Error("expected false")
|
|
}
|
|
c.load("test", 1, 2, 3)
|
|
if !c.hasData() {
|
|
t.Error("expected true")
|
|
}
|
|
}
|
|
|
|
func TestGetExpiredFutures(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.GetExpiredFutures(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetExpiredFuture(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := f.GetExpiredFuture(context.Background(), currency.NewPairWithDelimiter("BTC", "20211231", "-"))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetCollateral(t *testing.T) {
|
|
t.Parallel()
|
|
if !areTestAPIKeysSet() {
|
|
t.Skip()
|
|
}
|
|
_, err := f.GetCollateral(context.Background(), false)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = f.GetCollateral(context.Background(), true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|