modernise: Run new gopls modernise tool against the codebase and fix minor issues (#1826)

* modernise: Run new gopls modernise tool against codebase

* Address shazbert's nits

* apichecker, gctcli: Simplify HTML scraping functions and improve depth limit handling

* refactor: Create minSyncInterval const and update order book limit handling for binance and binanceUS

* refactor: Various slice usage improvements and rename TODO

* tranches: Revert deleteByID changes due to performance decrease

Shazbert was a F1 driver in a past lifetime 🏎️

* tranches: Simply retrieve copy

Thanks to shazbert

* documentation: Sort contributors list by contributions

* tranches: Remove deadcode in deleteByID
This commit is contained in:
Adrian Gallagher
2025-03-21 09:17:10 +11:00
committed by GitHub
parent d857d704e3
commit 4651af5767
223 changed files with 1504 additions and 1752 deletions

View File

@@ -10,6 +10,7 @@ import (
"net/url"
"os"
"regexp"
"slices"
"strconv"
"strings"
"sync"
@@ -301,19 +302,16 @@ func checkExistingExchanges(exchName string) bool {
// checkMissingExchanges checks if any supported exchanges are missing api checker functionality
func checkMissingExchanges() []string {
tempArray := make([]string, len(usageData.Exchanges))
for x := range usageData.Exchanges {
tempArray[x] = usageData.Exchanges[x].Name
exchanges := make([]string, len(usageData.Exchanges))
for i, exch := range usageData.Exchanges {
exchanges[i] = exch.Name
}
supportedExchs := exchange.Exchanges
for z := 0; z < len(supportedExchs); {
if common.StringSliceContainsInsensitive(tempArray, supportedExchs[z]) {
supportedExchs = append(supportedExchs[:z], supportedExchs[z+1:]...)
continue
}
z++
}
return supportedExchs
supportedExchs := slices.Clone(exchange.Exchanges)
return slices.DeleteFunc(supportedExchs, func(exchName string) bool {
return common.StringSliceContainsInsensitive(exchanges, exchName)
})
}
// readFileData reads the file data from the given json file
@@ -461,8 +459,6 @@ func checkChangeLog(htmlData *HTMLScrapingData) (string, error) {
dataStrings, err = htmlScrapeBitfinex(htmlData)
case pathBitmex:
dataStrings, err = htmlScrapeBitmex(htmlData)
case pathANX:
dataStrings, err = htmlScrapeANX(htmlData)
case pathPoloniex:
dataStrings, err = htmlScrapePoloniex(htmlData)
case pathBTCMarkets:
@@ -513,7 +509,7 @@ func checkChangeLog(htmlData *HTMLScrapingData) (string, error) {
}
// addExch appends exchange data to updates.json for future api checks
func addExch(exchName, checkType string, data interface{}, isUpdate bool) error {
func addExch(exchName, checkType string, data any, isUpdate bool) error {
var file []byte
if !isUpdate {
if checkExistingExchanges(exchName) {
@@ -554,7 +550,7 @@ func addExch(exchName, checkType string, data interface{}, isUpdate bool) error
}
// fillData fills exchange data based on the given checkType
func fillData(exchName, checkType string, data interface{}) (ExchangeInfo, error) {
func fillData(exchName, checkType string, data any) (ExchangeInfo, error) {
switch checkType {
case github:
tempData, ok := data.(GithubData)
@@ -743,27 +739,13 @@ func htmlScrapeHitBTC(htmlData *HTMLScrapingData) ([]string, error) {
if err != nil {
return nil, err
}
aBody := string(a)
r, err := regexp.Compile(htmlData.RegExp)
if err != nil {
return nil, err
}
str := r.FindAllString(aBody, -1)
var resp []string
for x := range str {
tempStr := strings.Replace(str[x], "section-v-", "", 1)
var repeat bool
for y := range resp {
if tempStr == resp[y] {
repeat = true
break
}
}
if !repeat {
resp = append(resp, tempStr)
}
}
return resp, nil
return r.FindAllString(string(a), -1), nil
}
// htmlScrapeBTCMarkets gets the check string for BTCMarkets exchange
@@ -844,41 +826,6 @@ loop:
return resp, nil
}
// htmlScrapeANX gets the check string for BTCMarkets exchange
func htmlScrapeANX(htmlData *HTMLScrapingData) ([]string, error) {
temp, err := sendHTTPGetRequest(htmlData.Path, nil)
if err != nil {
return nil, err
}
defer temp.Body.Close()
a, err := io.ReadAll(temp.Body)
if err != nil {
return nil, err
}
aBody := string(a)
r, err := regexp.Compile(htmlData.RegExp)
if err != nil {
return nil, err
}
str := r.FindAllString(aBody, -1)
var resp []string
for x := range str {
tempStr := strings.Replace(str[x], "section-v-", "", 1)
var repeat bool
for y := range resp {
if tempStr == resp[y] {
repeat = true
break
}
}
if !repeat {
resp = append(resp, tempStr)
}
}
return resp, nil
}
// htmlScrapeExmo gets the check string for Exmo Exchange
func htmlScrapeExmo(htmlData *HTMLScrapingData) ([]string, error) {
header := map[string]string{
@@ -1098,7 +1045,7 @@ func trelloCreateNewCheck(newCheckName string) error {
if err != nil {
return err
}
var resp interface{}
var resp any
params := url.Values{}
params.Set("name", newName)
return sendAuthReq(http.MethodPost,
@@ -1180,7 +1127,7 @@ func nameStateChanges(currentName, currentState string) (string, error) {
// trelloUpdateCheckItem updates a check item for trello
func trelloUpdateCheckItem(checkItemID, name, state string) error {
var resp interface{}
var resp any
params := url.Values{}
newName, err := nameStateChanges(name, state)
if err != nil {
@@ -1217,7 +1164,7 @@ func updateFile(name string) error {
}
// SendGetReq sends get req
func sendGetReq(path string, result interface{}) error {
func sendGetReq(path string, result any) error {
var requester *request.Requester
var err error
if strings.Contains(path, "github") {
@@ -1244,7 +1191,7 @@ func sendGetReq(path string, result interface{}) error {
}
// sendAuthReq sends auth req
func sendAuthReq(method, path string, result interface{}) error {
func sendAuthReq(method, path string, result any) error {
requester, err := request.New("Apichecker",
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout),
request.WithLimiter(request.NewBasicRateLimit(time.Second*10, 100, 1)))
@@ -1292,7 +1239,7 @@ func trelloCreateNewList() error {
if trelloBoardID == "" {
return errors.New("trelloBoardID not set, cannot create a new list")
}
var resp interface{}
var resp any
listName := createList
if configData.CreateListName != "" {
listName = configData.CreateListName
@@ -1327,7 +1274,7 @@ func trelloDeleteCheckItem(checkitemID string) error {
if checkitemID == "" {
return errors.New("checkitemID cannot be empty")
}
var resp interface{}
var resp any
return sendAuthReq(http.MethodDelete,
fmt.Sprintf(pathDeleteCheckitems, trelloChecklistID, checkitemID, apiKey, apiToken),
&resp)
@@ -1344,7 +1291,7 @@ func trelloCreateNewCard() error {
if trelloListID == "" {
return errors.New("trelloListID not set, cannot create a new checklist")
}
var resp interface{}
var resp any
cardName := createCard
if configData.CreateCardName != "" {
cardName = configData.CreateCardName
@@ -1385,7 +1332,7 @@ func trelloCreateNewChecklist() error {
if !areAPIKeysSet() || (trelloCardID == "") {
return errors.New("apikeys or trelloCardID not set, cannot create a new checklist")
}
var resp interface{}
var resp any
checklistName := createChecklist
if configData.CreateChecklistName != "" {
checklistName = configData.CreateChecklistName
@@ -1540,22 +1487,14 @@ func htmlScrapeBitfinex(htmlData *HTMLScrapingData) ([]string, error) {
if err != nil {
return nil, err
}
str := r.FindAllString(string(a), -1)
var resp []string
for x := range str {
tempStr := strings.Replace(str[x], "section-v-", "", 1)
var repeat bool
for y := range resp {
if tempStr == resp[y] {
repeat = true
break
}
}
if !repeat {
resp = append(resp, tempStr)
}
matches := r.FindAllString(string(a), -1)
results := make([]string, 0, len(matches))
for _, match := range matches {
s := strings.Replace(match, "section-v-", "", 1)
results = append(results, s)
}
return resp, nil
slices.Sort(results)
return slices.Clip(slices.Compact(results)), nil
}
// htmlScrapeBinance gets checkstring for binance exchange

View File

@@ -5,6 +5,7 @@ import (
"reflect"
"testing"
"github.com/stretchr/testify/require"
gctfile "github.com/thrasher-corp/gocryptotrader/common/file"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
@@ -221,15 +222,10 @@ func TestHTMLScrapeCoinbasepro(t *testing.T) {
func TestHTMLScrapeBitfinex(t *testing.T) {
t.Parallel()
data := HTMLScrapingData{
DateFormat: "2006-01-02",
RegExp: `section-v-(2\d{3}-\d{1,2}-\d{1,2})`,
Path: "https://docs.bitfinex.com/docs/changelog",
}
_, err := htmlScrapeBitfinex(&data)
if err != nil {
t.Error(err)
}
data := HTMLScrapingData{DateFormat: "2006-01-02", RegExp: `section-v-(2\d{3}-\d{1,2}-\d{1,2})`, Path: "https://docs.bitfinex.com/docs/changelog"}
r, err := htmlScrapeBitfinex(&data)
require.NoError(t, err, "htmlScrapeBitfinex must not error")
require.NotEmpty(t, r, "htmlScrapeBitfinex must return a non empty result")
}
func TestHTMLScrapeBitmex(t *testing.T) {
@@ -251,13 +247,10 @@ func TestHTMLScrapeBitmex(t *testing.T) {
func TestHTMLScrapeHitBTC(t *testing.T) {
t.Parallel()
data := HTMLScrapingData{
RegExp: `newest version \d{1}.\d{1}`,
Path: "https://api.hitbtc.com/",
}
if _, err := htmlScrapeHitBTC(&data); err != nil {
t.Error(err)
}
data := HTMLScrapingData{RegExp: `newest version \d{1}.\d{1}`, Path: "https://api.hitbtc.com/"}
r, err := htmlScrapeHitBTC(&data)
require.NoError(t, err, "htmlScrapeHitBTC must not error")
require.NotEmpty(t, r, "htmlScrapeHitBTC must return a non empty result")
}
func TestHTMLScrapeBTSE(t *testing.T) {
@@ -296,17 +289,6 @@ func TestHTMLScrapeBitflyer(t *testing.T) {
}
}
func TestHTMLScrapeANX(t *testing.T) {
t.Parallel()
data := HTMLScrapingData{
RegExp: `ANX Exchange API v\d{1}`,
Path: "https://anxv3.docs.apiary.io/#reference/quickstart-catalog",
}
if _, err := htmlScrapeANX(&data); err != nil {
t.Error(err)
}
}
func TestHTMLPoloniex(t *testing.T) {
t.Parallel()
data := HTMLScrapingData{

View File

@@ -9,6 +9,8 @@ import (
"net/http"
"os"
"path/filepath"
"slices"
"sort"
"strings"
"text/template"
"time"
@@ -313,6 +315,10 @@ func main() {
},
}...)
sort.Slice(contributors, func(i, j int) bool {
return contributors[i].Contributions > contributors[j].Contributions
})
if verbose {
fmt.Println("Contributor List Fetched")
for i := range contributors {
@@ -391,16 +397,6 @@ func GetConfiguration() (Config, error) {
return c, nil
}
// IsExcluded returns if the file path is included in the exclusion list
func IsExcluded(path string, exclusion []string) bool {
for i := range exclusion {
if path == exclusion[i] {
return true
}
}
return false
}
// GetProjectDirectoryTree uses filepath walk functions to get each individual
// directory name and path to match templates with
func GetProjectDirectoryTree(c *Config) ([]string, error) {
@@ -423,7 +419,7 @@ func GetProjectDirectoryTree(c *Config) ([]string, error) {
}
if info.IsDir() {
// Bypass what is contained in config.json directory exclusion
if IsExcluded(info.Name(), c.Exclusions.Directories) {
if slices.Contains(c.Exclusions.Directories, info.Name()) {
if verbose {
fmt.Println("Excluding Directory:", info.Name())
}
@@ -559,7 +555,7 @@ func UpdateDocumentation(details DocumentationDetails) {
name = strings.Join(temp, " ")
}
if IsExcluded(name, details.Config.Exclusions.Files) {
if slices.Contains(details.Config.Exclusions.Files, name) {
if verbose {
fmt.Println("Excluding file:", name)
}

View File

@@ -357,10 +357,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i]}),
SentParams: jsonifyInterface([]any{p, assetTypes[i]}),
Function: "UpdateTicker",
Error: msg,
Response: jsonifyInterface([]interface{}{updateTickerResponse}),
Response: jsonifyInterface([]any{updateTickerResponse}),
})
var GetCachedTickerResponse *ticker.Price
@@ -371,10 +371,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i]}),
SentParams: jsonifyInterface([]any{p, assetTypes[i]}),
Function: "GetCachedTicker",
Error: msg,
Response: jsonifyInterface([]interface{}{GetCachedTickerResponse}),
Response: jsonifyInterface([]any{GetCachedTickerResponse}),
})
var updateOrderbookResponse *orderbook.Base
@@ -385,10 +385,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i]}),
SentParams: jsonifyInterface([]any{p, assetTypes[i]}),
Function: "UpdateOrderbook",
Error: msg,
Response: jsonifyInterface([]interface{}{updateOrderbookResponse}),
Response: jsonifyInterface([]any{updateOrderbookResponse}),
})
var GetCachedOrderbookResponse *orderbook.Base
@@ -399,10 +399,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i]}),
SentParams: jsonifyInterface([]any{p, assetTypes[i]}),
Function: "GetCachedOrderbook",
Error: msg,
Response: jsonifyInterface([]interface{}{GetCachedOrderbookResponse}),
Response: jsonifyInterface([]any{GetCachedOrderbookResponse}),
})
var fetchTradablePairsResponse []currency.Pair
@@ -413,10 +413,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{assetTypes[i]}),
SentParams: jsonifyInterface([]any{assetTypes[i]}),
Function: "FetchTradablePairs",
Error: msg,
Response: jsonifyInterface([]interface{}{fetchTradablePairsResponse}),
Response: jsonifyInterface([]any{fetchTradablePairsResponse}),
})
// r6
err = e.UpdateTradablePairs(context.TODO(), false)
@@ -426,10 +426,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{false}),
SentParams: jsonifyInterface([]any{false}),
Function: "UpdateTradablePairs",
Error: msg,
Response: jsonifyInterface([]interface{}{nil}),
Response: jsonifyInterface([]any{nil}),
})
var getHistoricTradesResponse []trade.Data
@@ -440,10 +440,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i], time.Now().Add(-time.Hour), time.Now()}),
SentParams: jsonifyInterface([]any{p, assetTypes[i], time.Now().Add(-time.Hour), time.Now()}),
Function: "GetHistoricTrades",
Error: msg,
Response: jsonifyInterface([]interface{}{getHistoricTradesResponse}),
Response: jsonifyInterface([]any{getHistoricTradesResponse}),
})
var getRecentTradesResponse []trade.Data
@@ -454,10 +454,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i]}),
SentParams: jsonifyInterface([]any{p, assetTypes[i]}),
Function: "GetRecentTrades",
Error: msg,
Response: jsonifyInterface([]interface{}{getRecentTradesResponse}),
Response: jsonifyInterface([]any{getRecentTradesResponse}),
})
var getHistoricCandlesResponse *kline.Item
@@ -472,7 +472,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
Function: "GetHistoricCandles",
Error: msg,
Response: getHistoricCandlesResponse,
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i], startTime, endTime, kline.OneDay}),
SentParams: jsonifyInterface([]any{p, assetTypes[i], startTime, endTime, kline.OneDay}),
})
var getHistoricCandlesExtendedResponse *kline.Item
@@ -486,7 +486,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
Function: "GetHistoricCandlesExtended",
Error: msg,
Response: getHistoricCandlesExtendedResponse,
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i], startTime, endTime, kline.OneDay}),
SentParams: jsonifyInterface([]any{p, assetTypes[i], startTime, endTime, kline.OneDay}),
})
var getServerTimeResponse time.Time
@@ -500,7 +500,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
Function: "GetServerTime",
Error: msg,
Response: getServerTimeResponse,
SentParams: jsonifyInterface([]interface{}{assetTypes[i]}),
SentParams: jsonifyInterface([]any{assetTypes[i]}),
})
err = e.UpdateOrderExecutionLimits(context.TODO(), assetTypes[i])
@@ -511,10 +511,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{assetTypes[i]}),
SentParams: jsonifyInterface([]any{assetTypes[i]}),
Function: "UpdateOrderExecutionLimits",
Error: msg,
Response: jsonifyInterface([]interface{}{""}),
Response: jsonifyInterface([]any{""}),
})
fundingRateRequest := &fundingrate.HistoricalRatesRequest{
@@ -532,10 +532,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{fundingRateRequest}),
SentParams: jsonifyInterface([]any{fundingRateRequest}),
Function: "GetFundingRates",
Error: msg,
Response: jsonifyInterface([]interface{}{fundingRateResponse}),
Response: jsonifyInterface([]any{fundingRateResponse}),
})
var isPerpetualFutures bool
@@ -546,10 +546,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{assetTypes[i], p}),
SentParams: jsonifyInterface([]any{assetTypes[i], p}),
Function: "IsPerpetualFutureCurrency",
Error: msg,
Response: jsonifyInterface([]interface{}{isPerpetualFutures}),
Response: jsonifyInterface([]any{isPerpetualFutures}),
})
}
@@ -563,7 +563,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
Function: "GetCachedAccountInfo",
Error: msg,
Response: jsonifyInterface([]interface{}{GetCachedAccountInfoResponse}),
Response: jsonifyInterface([]any{GetCachedAccountInfoResponse}),
})
var getFundingHistoryResponse []exchange.FundingHistory
@@ -576,7 +576,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
Function: "GetAccountFundingHistory",
Error: msg,
Response: jsonifyInterface([]interface{}{getFundingHistoryResponse}),
Response: jsonifyInterface([]any{getFundingHistoryResponse}),
})
feeType := exchange.FeeBuilder{
@@ -593,10 +593,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{feeType}),
SentParams: jsonifyInterface([]any{feeType}),
Function: "GetFeeByType-Trade",
Error: msg,
Response: jsonifyInterface([]interface{}{getFeeByTypeResponse}),
Response: jsonifyInterface([]any{getFeeByTypeResponse}),
})
s := &order.Submit{
@@ -617,10 +617,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{*s}),
SentParams: jsonifyInterface([]any{*s}),
Function: "SubmitOrder",
Error: msg,
Response: jsonifyInterface([]interface{}{submitOrderResponse}),
Response: jsonifyInterface([]any{submitOrderResponse}),
})
modifyRequest := order.Modify{
@@ -639,7 +639,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{modifyRequest}),
SentParams: jsonifyInterface([]any{modifyRequest}),
Function: "ModifyOrder",
Error: msg,
Response: modifyOrderResponse,
@@ -658,10 +658,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{cancelRequest}),
SentParams: jsonifyInterface([]any{cancelRequest}),
Function: "CancelOrder",
Error: msg,
Response: jsonifyInterface([]interface{}{nil}),
Response: jsonifyInterface([]any{nil}),
})
var request []order.Cancel
@@ -680,10 +680,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{cancelRequest}),
SentParams: jsonifyInterface([]any{cancelRequest}),
Function: "CancelBatchOrders",
Error: msg,
Response: jsonifyInterface([]interface{}{CancelBatchOrdersResponse}),
Response: jsonifyInterface([]any{CancelBatchOrdersResponse}),
})
var cancellAllOrdersResponse order.CancelAllResponse
@@ -694,10 +694,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{cancelRequest}),
SentParams: jsonifyInterface([]any{cancelRequest}),
Function: "CancelAllOrders",
Error: msg,
Response: jsonifyInterface([]interface{}{cancellAllOrdersResponse}),
Response: jsonifyInterface([]any{cancellAllOrdersResponse}),
})
var r15 *order.Detail
@@ -708,10 +708,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{config.OrderSubmission.OrderID, p, assetTypes[i]}),
SentParams: jsonifyInterface([]any{config.OrderSubmission.OrderID, p, assetTypes[i]}),
Function: "GetOrderInfo",
Error: msg,
Response: jsonifyInterface([]interface{}{r15}),
Response: jsonifyInterface([]any{r15}),
})
historyRequest := order.MultiOrderRequest{
@@ -730,10 +730,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{historyRequest}),
SentParams: jsonifyInterface([]any{historyRequest}),
Function: "GetOrderHistory",
Error: msg,
Response: jsonifyInterface([]interface{}{getOrderHistoryResponse}),
Response: jsonifyInterface([]any{getOrderHistoryResponse}),
})
orderRequest := order.MultiOrderRequest{
@@ -752,10 +752,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{orderRequest}),
SentParams: jsonifyInterface([]any{orderRequest}),
Function: "GetActiveOrders",
Error: msg,
Response: jsonifyInterface([]interface{}{getActiveOrdersResponse}),
Response: jsonifyInterface([]any{getActiveOrdersResponse}),
})
var getDepositAddressResponse *deposit.Address
@@ -766,7 +766,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{p.Base, ""}),
SentParams: jsonifyInterface([]any{p.Base, ""}),
Function: "GetDepositAddress",
Error: msg,
Response: getDepositAddressResponse,
@@ -786,10 +786,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{feeType}),
SentParams: jsonifyInterface([]any{feeType}),
Function: "GetFeeByType-Crypto-Withdraw",
Error: msg,
Response: jsonifyInterface([]interface{}{GetFeeByTypeResponse}),
Response: jsonifyInterface([]any{GetFeeByTypeResponse}),
})
withdrawRequest := withdraw.Request{
@@ -811,7 +811,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{withdrawRequest}),
SentParams: jsonifyInterface([]any{withdrawRequest}),
Function: "WithdrawCryptocurrencyFunds",
Error: msg,
Response: withdrawCryptocurrencyFundsResponse,
@@ -833,10 +833,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{feeType}),
SentParams: jsonifyInterface([]any{feeType}),
Function: "GetFeeByType-FIAT-Withdraw",
Error: msg,
Response: jsonifyInterface([]interface{}{getFeeByTypeFiatResponse}),
Response: jsonifyInterface([]any{getFeeByTypeFiatResponse}),
})
withdrawRequestFiat := withdraw.Request{
@@ -876,7 +876,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{withdrawRequestFiat}),
SentParams: jsonifyInterface([]any{withdrawRequestFiat}),
Function: "WithdrawFiatFunds",
Error: msg,
Response: withdrawFiatFundsResponse,
@@ -889,7 +889,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{withdrawRequestFiat}),
SentParams: jsonifyInterface([]any{withdrawRequestFiat}),
Function: "WithdrawFiatFundsToInternationalBank",
Error: msg,
Response: withdrawFiatFundsInternationalResponse,
@@ -913,7 +913,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{marginRateHistoryRequest}),
SentParams: jsonifyInterface([]any{marginRateHistoryRequest}),
Function: "GetMarginRatesHistory",
Error: msg,
Response: marginRateHistoryResponse,
@@ -931,10 +931,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{positionSummaryRequest}),
SentParams: jsonifyInterface([]any{positionSummaryRequest}),
Function: "GetFuturesPositionSummary",
Error: msg,
Response: jsonifyInterface([]interface{}{positionSummaryResponse}),
Response: jsonifyInterface([]any{positionSummaryResponse}),
})
calculatePNLRequest := &futures.PNLCalculatorRequest{
@@ -957,10 +957,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{calculatePNLRequest}),
SentParams: jsonifyInterface([]any{calculatePNLRequest}),
Function: "CalculatePNL",
Error: msg,
Response: jsonifyInterface([]interface{}{calculatePNLResponse}),
Response: jsonifyInterface([]any{calculatePNLResponse}),
})
collateralCalculator := &futures.CollateralCalculator{
@@ -980,10 +980,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{collateralCalculator}),
SentParams: jsonifyInterface([]any{collateralCalculator}),
Function: "ScaleCollateral",
Error: msg,
Response: jsonifyInterface([]interface{}{scaleCollateralResponse}),
Response: jsonifyInterface([]any{scaleCollateralResponse}),
})
totalCollateralCalculator := &futures.TotalCollateralCalculator{
@@ -997,10 +997,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{totalCollateralCalculator}),
SentParams: jsonifyInterface([]any{totalCollateralCalculator}),
Function: "CalculateTotalCollateral",
Error: msg,
Response: jsonifyInterface([]interface{}{calculateTotalCollateralResponse}),
Response: jsonifyInterface([]any{calculateTotalCollateralResponse}),
})
var futuresPositionsResponse []futures.PositionResponse
@@ -1016,10 +1016,10 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
responseContainer.ErrorCount++
}
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
SentParams: jsonifyInterface([]interface{}{futuresPositionsRequest}),
SentParams: jsonifyInterface([]any{futuresPositionsRequest}),
Function: "GetFuturesPositionOrders",
Error: msg,
Response: jsonifyInterface([]interface{}{futuresPositionsResponse}),
Response: jsonifyInterface([]any{futuresPositionsResponse}),
})
response = append(response, responseContainer)
@@ -1027,7 +1027,7 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
return response
}
func jsonifyInterface(params []interface{}) json.RawMessage {
func jsonifyInterface(params []any) json.RawMessage {
response, _ := json.MarshalIndent(params, "", " ")
return response
}

View File

@@ -57,7 +57,7 @@ type ExchangeAssetPairResponses struct {
type EndpointResponse struct {
Function string `json:"function"`
Error string `json:"error"`
Response interface{} `json:"response"`
Response any `json:"response"`
SentParams json.RawMessage `json:"sentParams"`
}

View File

@@ -170,6 +170,17 @@ func isUnacceptableError(t *testing.T, err error) error {
return err
}
var validWrapperParams = []reflect.Type{
assetParam,
orderSubmitParam,
orderModifyParam,
orderCancelParam,
orderCancelsParam,
pairKeySliceParam,
getOrdersRequestParam,
latestRateRequest,
}
func executeExchangeWrapperTests(ctx context.Context, t *testing.T, exch exchange.IBotExchange, assetParams []assetPair) {
t.Helper()
iExchange := reflect.TypeOf(&exch).Elem()
@@ -184,15 +195,11 @@ func executeExchangeWrapperTests(ctx context.Context, t *testing.T, exch exchang
var assetLen int
for y := range method.Type().NumIn() {
input := method.Type().In(y)
for _, t := range []reflect.Type{
assetParam, orderSubmitParam, orderModifyParam, orderCancelParam, orderCancelsParam, pairKeySliceParam, getOrdersRequestParam, latestRateRequest,
} {
if input.AssignableTo(t) {
// this allows wrapper functions that support assets types
// to be tested with all supported assets
assetLen = len(assetParams) - 1
break
}
if slices.ContainsFunc(validWrapperParams, func(t reflect.Type) bool {
return input.AssignableTo(t)
}) {
assetLen = len(assetParams) - 1
break
}
}
tt := time.Now()
@@ -239,7 +246,7 @@ func CallExchangeMethod(t *testing.T, methodToCall reflect.Value, methodValues [
continue
}
if isUnacceptableError(t, err) != nil {
literalInputs := make([]interface{}, len(methodValues))
literalInputs := make([]any, len(methodValues))
for j := range methodValues {
if methodValues[j].Kind() == reflect.Ptr {
// dereference pointers just to add a bit more clarity
@@ -699,12 +706,7 @@ func isFiat(t *testing.T, c string) bool {
currency.ZCAD.Item.Lower,
currency.ZJPY.Item.Lower,
}
for i := range fiats {
if fiats[i] == c {
return true
}
}
return false
return slices.Contains(fiats, c)
}
// disruptFormatting adds in an unused delimiter and strange casing features to

View File

@@ -35,7 +35,7 @@ var (
const defaultTimeout = time.Second * 30
func jsonOutput(in interface{}) {
func jsonOutput(in any) {
j, err := json.MarshalIndent(in, "", " ")
if err != nil {
return

View File

@@ -371,7 +371,6 @@ func getOrderbook(c *cli.Context) error {
var (
exchangeName, pair, assetType string
depthLimit int64
exchangeStyle bool
err error
)
@@ -407,12 +406,15 @@ func getOrderbook(c *cli.Context) error {
}
}
if c.IsSet("depthlimit") {
depthLimit = c.Int64("depthlimit")
} else if c.Args().Get(4) != "" {
depthLimit, err = strconv.ParseInt(c.Args().Get(4), 10, 64)
if err != nil {
const depthCeiling uint64 = 100 // The maximum the depth can be regardless of user entry
depthLimit := depthCeiling
if d := c.Uint64("depthlimit"); d > 0 && d < depthCeiling {
depthLimit = d
} else if d := c.Args().Get(4); d != "" {
if du, err := strconv.ParseUint(d, 10, 64); err != nil {
return err
} else if du > 0 && du < depthCeiling {
depthLimit = du
}
}
@@ -449,20 +451,9 @@ func getOrderbook(c *cli.Context) error {
}
if exchangeStyle {
var maxLen, bidLen, askLen int64
bidLen = int64(len(result.Bids) - 1)
askLen = int64(len(result.Asks) - 1)
if bidLen >= askLen {
maxLen = bidLen
} else {
maxLen = askLen
}
if depthLimit > 0 && depthLimit < maxLen {
maxLen = depthLimit
}
if maxLen > 100 {
maxLen = 100
}
bidLen := uint64(len(result.Bids) - 1) //nolint:gosec // Can fit in uint64
askLen := uint64(len(result.Asks) - 1) //nolint:gosec // Can fit in uint64
maxLen := min(max(bidLen, askLen), depthLimit)
renderOrderbookExchangeStyle(result, exchangeName, assetType, maxLen, askLen, bidLen)
} else {
jsonOutput(result)
@@ -516,7 +507,6 @@ func getOrderbookStream(c *cli.Context) error {
var (
exchangeName, pair, assetType string
depthLimit int64
exchangeStyle bool
err error
)
@@ -552,12 +542,15 @@ func getOrderbookStream(c *cli.Context) error {
}
}
if c.IsSet("depthlimit") {
depthLimit = c.Int64("depthlimit")
} else if c.Args().Get(4) != "" {
depthLimit, err = strconv.ParseInt(c.Args().Get(4), 10, 64)
if err != nil {
const depthCeiling uint64 = 50 // The maximum the depth can be regardless of user entry
depthLimit := depthCeiling
if d := c.Uint64("depthlimit"); d > 0 && d < depthCeiling {
depthLimit = d
} else if d := c.Args().Get(4); d != "" {
if du, err := strconv.ParseUint(d, 10, 64); err != nil {
return err
} else if du > 0 && du < depthCeiling {
depthLimit = du
}
}
@@ -610,21 +603,9 @@ func getOrderbookStream(c *cli.Context) error {
continue
}
bidLen := int64(len(resp.Bids) - 1)
askLen := int64(len(resp.Asks) - 1)
var maxLen int64
if bidLen >= askLen {
maxLen = bidLen
} else {
maxLen = askLen
}
if depthLimit > 0 && depthLimit < maxLen {
maxLen = depthLimit
}
if maxLen > 50 {
maxLen = 50
}
bidLen := uint64(len(resp.Bids) - 1) //nolint:gosec // Can fit in uint64
askLen := uint64(len(resp.Asks) - 1) //nolint:gosec // Can fit in uint64
maxLen := min(max(bidLen, askLen), depthLimit)
if exchangeStyle {
renderOrderbookExchangeStyle(resp, exchangeName, assetType, maxLen, askLen, bidLen)
@@ -660,7 +641,7 @@ func getOrderbookStream(c *cli.Context) error {
}
}
func renderOrderbookExchangeStyle(resp *gctrpc.OrderbookResponse, exchangeName, assetType string, maxLen, askLen, bidLen int64) {
func renderOrderbookExchangeStyle(resp *gctrpc.OrderbookResponse, exchangeName, assetType string, maxLen, askLen, bidLen uint64) {
maxLen-- // ensure we get the 0 index at the correct max length
upperBase := strings.ToUpper(resp.Pair.Base)
upperQuote := strings.ToUpper(resp.Pair.Quote)
@@ -670,16 +651,17 @@ func renderOrderbookExchangeStyle(resp *gctrpc.OrderbookResponse, exchangeName,
fmt.Printf("%sPrice(%v)\t\tAmount(%s)\n",
grayText, upperQuote, upperBase)
for i := maxLen; i >= 0; i-- {
for i := uint64(0); i <= maxLen; i++ {
j := maxLen - i
var askAmount, askPrice float64
if i <= askLen {
askAmount = resp.Asks[i].Amount
askPrice = resp.Asks[i].Price
if j <= askLen {
askAmount = resp.Asks[j].Amount
askPrice = resp.Asks[j].Price
}
fmt.Printf(printFmt, redText, askPrice, askAmount)
}
fmt.Println()
for i := int64(0); i <= maxLen; i++ {
for i := uint64(0); i <= maxLen; i++ {
var bidAmount, bidPrice float64
if i <= bidLen {
bidAmount = resp.Bids[i].Amount

View File

@@ -26,7 +26,7 @@ type WebsocketEvent struct {
Exchange string `json:"exchange,omitempty"`
AssetType string `json:"assetType,omitempty"`
Event string
Data interface{}
Data any
}
// WebsocketAuth is the struct used for a websocket auth request
@@ -37,9 +37,9 @@ type WebsocketAuth struct {
// WebsocketEventResponse is the struct used for websocket event responses
type WebsocketEventResponse struct {
Event string `json:"event"`
Data interface{} `json:"data"`
Error string `json:"error"`
Event string `json:"event"`
Data any `json:"data"`
Error string `json:"error"`
}
// WebsocketOrderbookTickerRequest is a struct used for ticker and orderbook
@@ -51,7 +51,7 @@ type WebsocketOrderbookTickerRequest struct {
}
// SendWebsocketEvent sends a websocket event message
func SendWebsocketEvent(event string, reqData interface{}, result *WebsocketEventResponse) error {
func SendWebsocketEvent(event string, reqData any, result *WebsocketEventResponse) error {
req := WebsocketEvent{
Event: event,
}