golangci-lint/CI: Bump versions and introduce new linters (#798)

* golangci-lint/CI: Bump versions

Fix remaining linter issues

* Specifically set AppVeyor version

* Fix the infamous typos 👀

* Add go env cmd to AppVeyor

* Add go version cmd to AppVeyor

* Specify AppVeyor image, adjust linters

* Update go get to go install due to deprecation

* Bump golangci-lint timeout time for AppVeyor

* Change NW contract to NQ

* Address nitters

* GetRandomPair -> Pair{}

* Address nits

* Address time nitterinos plus additional tweaks

* More time inception upgrades!

* Bending time and space
This commit is contained in:
Adrian Gallagher
2021-10-14 16:38:53 +11:00
committed by GitHub
parent 0a91af0f2e
commit f0d45aa1d2
194 changed files with 1506 additions and 1233 deletions

View File

@@ -1,5 +1,7 @@
build: off
image: Visual Studio 2019
clone_folder: c:\gopath\src\github.com\thrasher-corp\gocryptotrader
cache:
@@ -26,7 +28,7 @@ environment:
PSQL_SSLMODE: disable
PSQL_SKIPSQLCMD: true
PSQL_TESTDBNAME: gct_dev_ci
stack: go 1.16.x
stack: go 1.17.x
services:
- postgresql96
@@ -45,11 +47,13 @@ build_script:
before_test:
- cd c:\gopath\src\github.com\thrasher-corp\gocryptotrader
- go get
- go env
- go version
- go install
test_script:
# test back-end
- go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.31.0
- go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.42.1
- '%GOPATH%\bin\golangci-lint.exe run --verbose'
- ps: >-
if($env:APPVEYOR_SCHEDULED_BUILD -eq 'true') {

View File

@@ -9,4 +9,4 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
version: v1.31
version: v1.42.1

View File

@@ -1,7 +1,7 @@
on: [push, pull_request]
name: CI
env:
GO_VERSION: 1.16.x
GO_VERSION: 1.17.x
jobs:
backend-psql:
name: GoCryptoTrader back-end with PSQL

View File

@@ -1,5 +1,5 @@
run:
timeout: 2m30s
timeout: 3m
issues-exit-code: 1
tests: true
skip-dirs:
@@ -25,11 +25,18 @@ linters:
# disabled by default linters
- asciicheck
- bodyclose
# - cyclop
- depguard
- dogsled
# - dupl
- durationcheck
- errname
# - errorlint
# - exhaustive
# - exhaustivestruct
- exportloopref
# - forbidigo
- forcetypeassert
# - funlen
- gci
# - gochecknoglobals
@@ -43,31 +50,45 @@ linters:
# - goerr113
- gofmt
# - gofumpt
- goheader
# - goheader
- goimports
- golint
# - golint // deprecated since 1.41.0, replaced by revive
# - gomnd
- gomoddirectives
- gomodguard
- goprintffuncname
- gosec
# - interfacer
# - lll
- ifshort
# - importas
# - interfacer // deprecated by its owner
# - lll
- makezero
# - maligned
- misspell
- nakedret
# - nestif
- nilerr
# - nlreturn
- noctx
- nolintlint
# - paralleltest
# - prealloc
- predeclared
# - promlinter
- revive
- rowserrcheck
- scopelint
- sqlclosecheck
# - scopelint // deprecated since v1.39.0, replaced by exportloopref
# - sqlclosecheck
- stylecheck
# - tagliatelle
# - testpackage
- thelper
- tparallel
- unconvert
- unparam
- wastedassign
- whitespace
# - wrapcheck
# - wsl
linters-settings:

View File

@@ -18,7 +18,7 @@ matrix:
dist: xenial
name: 'GoCryptoTrader [back-end] [linux] [64-bit]'
go:
- 1.15.x
- 1.17.x
env:
- GO111MODULE=on
- PSQL_USER=postgres
@@ -43,7 +43,7 @@ matrix:
dist: xenial
name: 'GoCryptoTrader [back-end] [linux] [32-bit]'
go:
- 1.15.x
- 1.17.x
env:
- GO111MODULE=on
- NO_RACE_TEST=1
@@ -72,7 +72,7 @@ matrix:
os: osx
name: 'GoCryptoTrader [back-end] [darwin]'
go:
- 1.15.x
- 1.17.x
env:
- GO111MODULE=on
- PSQL_USER=postgres

View File

@@ -1,4 +1,4 @@
FROM golang:1.15 as build
FROM golang:1.17 as build
WORKDIR /go/src/github.com/thrasher-corp/gocryptotrader
COPY . .
RUN GO111MODULE=on go mod vendor

View File

@@ -1,6 +1,6 @@
LDFLAGS = -ldflags "-w -s"
GCTPKG = github.com/thrasher-corp/gocryptotrader
LINTPKG = github.com/golangci/golangci-lint/cmd/golangci-lint@v1.31.0
LINTPKG = github.com/golangci/golangci-lint/cmd/golangci-lint@v1.42.1
LINTBIN = $(GOPATH)/bin/golangci-lint
GCTLISTENPORT=9050
GCTPROFILERLISTENPORT=8085
@@ -14,11 +14,11 @@ CONFIG_FLAG = $(if $(CONFIG),-config $(CONFIG),)
all: check build
get:
GO111MODULE=on go get $(GCTPKG)
go install $(GCTPKG)
linter:
GO111MODULE=on go get $(GCTPKG)
GO111MODULE=on go get $(LINTPKG)
go install $(GCTPKG)
go install $(LINTPKG)
test -z "$$($(LINTBIN) run --verbose | tee /dev/stderr)"
check: linter test
@@ -31,19 +31,19 @@ else
endif
build:
GO111MODULE=on go build $(LDFLAGS)
go build $(LDFLAGS)
install:
GO111MODULE=on go install $(LDFLAGS)
go install $(LDFLAGS)
fmt:
gofmt -l -w -s $(shell find . -type f -name '*.go')
update_deps:
GO111MODULE=on go mod verify
GO111MODULE=on go mod tidy
go mod verify
go mod tidy
rm -rf vendor
GO111MODULE=on go mod vendor
go mod vendor
.PHONY: profile_heap
profile_heap:

View File

@@ -1208,8 +1208,7 @@ func TestValidate(t *testing.T) {
},
},
}
err := c.Validate()
if !errors.Is(err, nil) {
if err := c.Validate(); !errors.Is(err, nil) {
t.Errorf("received %v expected %v", err, nil)
}
}

View File

@@ -399,8 +399,7 @@ func parseDatabase(reader *bufio.Reader, cfg *config.Config) error {
}
fmt.Printf("What is the end date? Leave blank for \"%v\"\n", defaultStart.Format(gctcommon.SimpleTimeFormat))
endDate := quickParse(reader)
if endDate != "" {
if endDate := quickParse(reader); endDate != "" {
cfg.DataSettings.DatabaseData.EndDate, err = time.Parse(endDate, gctcommon.SimpleTimeFormat)
if err != nil {
return err

View File

@@ -19,8 +19,7 @@ type fakeDataHandler struct {
func TestBaseDataFunctions(t *testing.T) {
t.Parallel()
var d Base
latest := d.Latest()
if latest != nil {
if latest := d.Latest(); latest != nil {
t.Error("expected nil")
}
d.Next()
@@ -37,17 +36,14 @@ func TestBaseDataFunctions(t *testing.T) {
if o != 0 {
t.Error("expected 0")
}
list := d.List()
if list != nil {
if list := d.List(); list != nil {
t.Error("expected nil")
}
history := d.History()
if history != nil {
if history := d.History(); history != nil {
t.Error("expected nil")
}
d.SetStream(nil)
st := d.GetStream()
if st != nil {
if st := d.GetStream(); st != nil {
t.Error("expected nil")
}
d.Reset()
@@ -91,24 +87,24 @@ func TestStream(t *testing.T) {
d.SortStream()
f = d.Next().(fakeDataHandler)
if f.time != 1 {
f, ok := d.Next().(fakeDataHandler)
if f.time != 1 || !ok {
t.Error("expected 1")
}
f = d.Next().(fakeDataHandler)
if f.time != 2 {
f, ok = d.Next().(fakeDataHandler)
if f.time != 2 || !ok {
t.Error("expected 2")
}
f = d.Next().(fakeDataHandler)
if f.time != 4 {
f, ok = d.Next().(fakeDataHandler)
if f.time != 4 || !ok {
t.Error("expected 4")
}
f = d.Next().(fakeDataHandler)
if f.time != 10 {
f, ok = d.Next().(fakeDataHandler)
if f.time != 10 || !ok {
t.Error("expected 10")
}
f = d.Next().(fakeDataHandler)
if f.time != 20 {
f, ok = d.Next().(fakeDataHandler)
if f.time != 20 || !ok {
t.Error("expected 20")
}
}

View File

@@ -81,8 +81,7 @@ func TestHasDataAtTime(t *testing.T) {
},
},
}
err := d.Load()
if err != nil {
if err := d.Load(); err != nil {
t.Error(err)
}

View File

@@ -28,8 +28,7 @@ func TestAppendEvent(t *testing.T) {
func TestNextEvent(t *testing.T) {
t.Parallel()
e := Holder{Queue: []common.EventHandler{}}
ev := e.NextEvent()
if ev != nil {
if ev := e.NextEvent(); ev != nil {
t.Error("expected not ok")
}

View File

@@ -58,8 +58,7 @@ func (h *Holding) HasFunds() bool {
func (h *Holding) update(e fill.Event, f funding.IPairReader) {
direction := e.GetDirection()
o := e.GetOrder()
if o != nil {
if o := e.GetOrder(); o != nil {
amount := decimal.NewFromFloat(o.Amount)
fee := decimal.NewFromFloat(o.Fee)
price := decimal.NewFromFloat(o.Price)

View File

@@ -60,7 +60,7 @@ func TestUpdate(t *testing.T) {
if err != nil {
t.Error(err)
}
t1 := h.Timestamp
t1 := h.Timestamp // nolint:ifshort,nolintlint // false positive and triggers only on Windows
h.Update(&fill.Fill{
Base: event.Base{
Time: time.Now(),

View File

@@ -262,8 +262,7 @@ func (p *Portfolio) addComplianceSnapshot(fillEvent fill.Event) error {
return err
}
prevSnap := complianceManager.GetLatestSnapshot()
fo := fillEvent.GetOrder()
if fo != nil {
if fo := fillEvent.GetOrder(); fo != nil {
price := decimal.NewFromFloat(fo.Price)
amount := decimal.NewFromFloat(fo.Amount)
fee := decimal.NewFromFloat(fo.Fee)

View File

@@ -376,8 +376,7 @@ func TestAddComplianceSnapshotForTime(t *testing.T) {
func TestSerialise(t *testing.T) {
t.Parallel()
s := Statistic{}
_, err := s.Serialise()
if err != nil {
if _, err := s.Serialise(); err != nil {
t.Error(err)
}
}

View File

@@ -21,8 +21,7 @@ import (
func TestName(t *testing.T) {
d := Strategy{}
n := d.Name()
if n != Name {
if n := d.Name(); n != Name {
t.Errorf("expected %v", Name)
}
}

View File

@@ -55,9 +55,8 @@ func (s *Strategy) OnSignal(d data.Handler, _ funding.IFundTransferer) (signal.E
return nil, err
}
es.SetPrice(d.Latest().ClosePrice())
offset := d.Offset()
if offset <= int(s.rsiPeriod.IntPart()) {
if offset := d.Offset(); offset <= int(s.rsiPeriod.IntPart()) {
es.AppendReason("Not enough data for signal generation")
es.SetDirection(common.DoNothing)
return &es, nil

View File

@@ -22,8 +22,7 @@ import (
func TestName(t *testing.T) {
t.Parallel()
d := Strategy{}
n := d.Name()
if n != Name {
if n := d.Name(); n != Name {
t.Errorf("expected %v", Name)
}
}

View File

@@ -23,8 +23,7 @@ import (
func TestName(t *testing.T) {
t.Parallel()
d := Strategy{}
n := d.Name()
if n != Name {
if n := d.Name(); n != Name {
t.Errorf("expected %v", Name)
}
}
@@ -94,8 +93,7 @@ func TestSetCustomSettings(t *testing.T) {
func TestOnSignal(t *testing.T) {
t.Parallel()
s := Strategy{}
_, err := s.OnSignal(nil, nil)
if !errors.Is(err, errStrategyOnlySupportsSimultaneousProcessing) {
if _, err := s.OnSignal(nil, nil); !errors.Is(err, errStrategyOnlySupportsSimultaneousProcessing) {
t.Errorf("received: %v, expected: %v", err, errStrategyOnlySupportsSimultaneousProcessing)
}
}

View File

@@ -25,8 +25,7 @@ func TestEvent_GetAssetType(t *testing.T) {
e := &Base{
AssetType: asset.Spot,
}
y := e.GetAssetType()
if y != asset.Spot {
if y := e.GetAssetType(); y != asset.Spot {
t.Error("expected spot")
}
}
@@ -36,8 +35,7 @@ func TestEvent_GetExchange(t *testing.T) {
e := &Base{
Exchange: "test",
}
y := e.GetExchange()
if y != "test" {
if y := e.GetExchange(); y != "test" {
t.Error("expected test")
}
}
@@ -47,8 +45,7 @@ func TestEvent_GetInterval(t *testing.T) {
e := &Base{
Interval: gctkline.OneMin,
}
y := e.GetInterval()
if y != gctkline.OneMin {
if y := e.GetInterval(); y != gctkline.OneMin {
t.Error("expected one minute")
}
}

View File

@@ -565,7 +565,10 @@ func addExch(exchName, checkType string, data interface{}, isUpdate bool) error
func fillData(exchName, checkType string, data interface{}) (ExchangeInfo, error) {
switch checkType {
case github:
tempData := data.(GithubData)
tempData, ok := data.(GithubData)
if !ok {
return ExchangeInfo{}, errors.New("unable to type assert GithubData")
}
tempSha, err := getSha(path)
if err != nil {
return ExchangeInfo{}, err
@@ -579,7 +582,10 @@ func fillData(exchName, checkType string, data interface{}) (ExchangeInfo, error
},
}, nil
case htmlScrape:
tempData := data.(HTMLScrapingData)
tempData, ok := data.(HTMLScrapingData)
if !ok {
return ExchangeInfo{}, errors.New("unable to type assert HTMLScrapingData")
}
checkStr, err := checkChangeLog(&tempData)
if err != nil {
return ExchangeInfo{}, err

View File

@@ -142,8 +142,7 @@ func TestCheckChangeLog(t *testing.T) {
DateFormat: "2006/01/02",
RegExp: `^20(\d){2}/(\d){2}/(\d){2}$`,
Path: "https://docs.gemini.com/rest-api/#revision-history"}
_, err := checkChangeLog(&data)
if err != nil {
if _, err := checkChangeLog(&data); err != nil {
t.Error(err)
}
}
@@ -236,8 +235,7 @@ func TestHTMLScrapeBitmex(t *testing.T) {
DateFormat: "Jan-2-2006",
RegExp: `([A-Z]{1}[a-z]{2}-\d{1,2}-2\d{3})`,
Path: "https://www.bitmex.com/static/md/en-US/apiChangelog"}
_, err := htmlScrapeBitmex(&data)
if err != nil {
if _, err := htmlScrapeBitmex(&data); err != nil {
t.Error(err)
}
}
@@ -246,8 +244,7 @@ func TestHTMLScrapeHitBTC(t *testing.T) {
t.Parallel()
data := HTMLScrapingData{RegExp: `newest version \d{1}.\d{1}`,
Path: "https://api.hitbtc.com/"}
_, err := htmlScrapeHitBTC(&data)
if err != nil {
if _, err := htmlScrapeHitBTC(&data); err != nil {
t.Error(err)
}
}
@@ -273,8 +270,7 @@ func TestHTMLScrapeBTSE(t *testing.T) {
t.Parallel()
data := HTMLScrapingData{RegExp: `^version: \d{1}.\d{1}.\d{1}`,
Path: "https://api.btcmarkets.net/openapi/info/index.yaml"}
_, err := htmlScrapeBTSE(&data)
if err != nil {
if _, err := htmlScrapeBTSE(&data); err != nil {
t.Error(err)
}
}
@@ -283,8 +279,7 @@ func TestHTMLScrapeBTCMarkets(t *testing.T) {
t.Parallel()
data := HTMLScrapingData{RegExp: `^version: \d{1}.\d{1}.\d{1}`,
Path: "https://api.btcmarkets.net/openapi/info/index.yaml"}
_, err := htmlScrapeBTCMarkets(&data)
if err != nil {
if _, err := htmlScrapeBTCMarkets(&data); err != nil {
t.Error(err)
}
}
@@ -296,8 +291,7 @@ func TestHTMLScrapeBitflyer(t *testing.T) {
TextTokenData: "code",
RegExp: `^https://api.bitflyer.com/v\d{1}/$`,
Path: "https://lightning.bitflyer.com/docs?lang=en"}
_, err := htmlScrapeBitflyer(&data)
if err != nil {
if _, err := htmlScrapeBitflyer(&data); err != nil {
t.Error(err)
}
}
@@ -306,8 +300,7 @@ 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"}
_, err := htmlScrapeANX(&data)
if err != nil {
if _, err := htmlScrapeANX(&data); err != nil {
t.Error(err)
}
}
@@ -322,8 +315,7 @@ func TestHTMLPoloniex(t *testing.T) {
DateFormat: "2006-01-02",
RegExp: `(2\d{3}-\d{1,2}-\d{1,2})`,
Path: "https://docs.poloniex.com/#changelog"}
_, err := htmlScrapePoloniex(&data)
if err != nil {
if _, err := htmlScrapePoloniex(&data); err != nil {
t.Error(err)
}
}
@@ -338,8 +330,7 @@ func TestHTMLItBit(t *testing.T) {
DateFormat: "2006-01-02",
RegExp: `^https://api.itbit.com/v\d{1}/$`,
Path: "https://api.itbit.com/docs"}
_, err := htmlScrapeItBit(&data)
if err != nil {
if _, err := htmlScrapeItBit(&data); err != nil {
t.Error(err)
}
}
@@ -348,8 +339,7 @@ func TestHTMLScrapeExmo(t *testing.T) {
t.Parallel()
data := HTMLScrapingData{RegExp: `Last updated on [\s\S]*, 20\d{2}`,
Path: "https://exmo.com/en/api/"}
_, err := htmlScrapeExmo(&data)
if err != nil {
if _, err := htmlScrapeExmo(&data); err != nil {
t.Error(err)
}
}
@@ -358,8 +348,7 @@ func TestHTMLBitstamp(t *testing.T) {
t.Parallel()
data := HTMLScrapingData{RegExp: `refer to the v\d{1} API for future references.`,
Path: "https://www.bitstamp.net/api/"}
_, err := htmlScrapeBitstamp(&data)
if err != nil {
if _, err := htmlScrapeBitstamp(&data); err != nil {
t.Error(err)
}
}
@@ -371,8 +360,7 @@ func TestHTMLKraken(t *testing.T) {
TextTokenData: "p",
RegExp: `URL: https://api.kraken.com/\d{1}/private/Balance`,
Path: "https://www.kraken.com/features/api"}
_, err := htmlScrapeKraken(&data)
if err != nil {
if _, err := htmlScrapeKraken(&data); err != nil {
t.Error(err)
}
}
@@ -386,8 +374,7 @@ func TestHTMLAlphaPoint(t *testing.T) {
TextTokenData: "h3",
RegExp: `revised-calls-\d{1}-\d{1}-\d{1}-gt-\d{1}-\d{1}-\d{1}`,
Path: "https://alphapoint.github.io/slate/#introduction"}
_, err := htmlScrapeAlphaPoint(&data)
if err != nil {
if _, err := htmlScrapeAlphaPoint(&data); err != nil {
t.Error(err)
}
}
@@ -397,8 +384,7 @@ func TestHTMLYobit(t *testing.T) {
data := HTMLScrapingData{TokenData: "h2",
Key: "id",
Path: "https://www.yobit.net/en/api/"}
_, err := htmlScrapeYobit(&data)
if err != nil {
if _, err := htmlScrapeYobit(&data); err != nil {
t.Error(err)
}
}
@@ -408,8 +394,7 @@ func TestHTMLScrapeLocalBitcoins(t *testing.T) {
data := HTMLScrapingData{TokenData: "div",
RegExp: `col-md-12([\s\S]*?)clearfix`,
Path: "https://localbitcoins.com/api-docs/"}
_, err := htmlScrapeLocalBitcoins(&data)
if err != nil {
if _, err := htmlScrapeLocalBitcoins(&data); err != nil {
t.Error(err)
}
}
@@ -422,8 +407,7 @@ func TestHTMLScrapeOk(t *testing.T) {
TokenDataEnd: "./#change-",
RegExp: `./#change-\d{8}`,
Path: "https://www.okex.com/docs/en/"}
_, err := htmlScrapeOk(&data)
if err != nil {
if _, err := htmlScrapeOk(&data); err != nil {
t.Error(err)
}
}
@@ -547,8 +531,7 @@ func TestTrelloGetLists(t *testing.T) {
if !areTestAPIKeysSet() {
t.Skip()
}
_, err := trelloGetLists()
if err != nil {
if _, err := trelloGetLists(); err != nil {
t.Error(err)
}
}
@@ -557,8 +540,7 @@ func TestGetAllCards(t *testing.T) {
if !areTestAPIKeysSet() {
t.Skip()
}
_, err := trelloGetAllCards()
if err != nil {
if _, err := trelloGetAllCards(); err != nil {
t.Error(err)
}
}
@@ -567,8 +549,7 @@ func TestGetAllChecklists(t *testing.T) {
if !areTestAPIKeysSet() {
t.Skip()
}
_, err := trelloGetAllChecklists()
if err != nil {
if _, err := trelloGetAllChecklists(); err != nil {
t.Error(err)
}
}
@@ -580,8 +561,7 @@ func TestTrelloGetAllBoards(t *testing.T) {
if trelloBoardID != "" || testBoardName != "" {
t.Skip()
}
_, err := trelloGetBoardID()
if err != nil {
if _, err := trelloGetBoardID(); err != nil {
t.Error(err)
}
}
@@ -590,8 +570,7 @@ func TestCreateNewList(t *testing.T) {
if !areTestAPIKeysSet() {
t.Skip()
}
err := trelloCreateNewList()
if err != nil {
if err := trelloCreateNewList(); err != nil {
t.Error(err)
}
}
@@ -600,8 +579,7 @@ func TestTrelloCreateNewCard(t *testing.T) {
if !areTestAPIKeysSet() {
t.Skip()
}
err := trelloCreateNewCard()
if err != nil {
if err := trelloCreateNewCard(); err != nil {
t.Error(err)
}
}
@@ -610,8 +588,7 @@ func TestCreateNewChecklist(t *testing.T) {
if !areTestAPIKeysSet() {
t.Skip()
}
err := trelloCreateNewChecklist()
if err != nil {
if err := trelloCreateNewChecklist(); err != nil {
t.Error(err)
}
}
@@ -619,8 +596,7 @@ func TestCreateNewChecklist(t *testing.T) {
func TestWriteAuthVars(t *testing.T) {
if canTestMainFile {
trelloCardID = "jdsfl"
err := writeAuthVars(testMode)
if err != nil {
if err := writeAuthVars(testMode); err != nil {
t.Error(err)
}
}

View File

@@ -38,8 +38,7 @@ func TestLoad(t *testing.T) {
fs := &flag.FlagSet{}
fs.String("config", testConfig, "")
newCtx := cli.NewContext(testApp, fs, &cli.Context{})
err := load(newCtx)
if err != nil {
if err := load(newCtx); err != nil {
t.Fatal(err)
}
}

View File

@@ -951,12 +951,10 @@ func outputToConsole(exchangeResponses []ExchangeResponses) {
// disruptFormatting adds in an unused delimiter and strange casing features to
// ensure format currency pair is used throughout the code base.
func disruptFormatting(p currency.Pair) (currency.Pair, error) {
base := p.Base.String()
if base == "" {
if p.Base.IsEmpty() {
return currency.Pair{}, errors.New("cannot disrupt formatting as base is not populated")
}
quote := p.Quote.String()
if quote == "" {
if p.Quote.IsEmpty() {
return currency.Pair{}, errors.New("cannot disrupt formatting as quote is not populated")
}

View File

@@ -24,8 +24,7 @@ func clearScreen() error {
}
func closeConn(conn *grpc.ClientConn, cancel context.CancelFunc) {
err := conn.Close()
if err != nil {
if err := conn.Close(); err != nil {
fmt.Println(err)
}
if cancel != nil {

View File

@@ -130,16 +130,14 @@ func TestRemove(t *testing.T) {
func TestGetNewest(t *testing.T) {
lruCache := New(2)
k, _ := lruCache.getNewest()
if k != nil {
if k, _ := lruCache.getNewest(); k != nil {
t.Fatal("expected GetNewest() on empty cache to return nil")
}
}
func TestGetOldest(t *testing.T) {
lruCache := New(2)
k, _ := lruCache.getOldest()
if k != nil {
if k, _ := lruCache.getOldest(); k != nil {
t.Fatal("expected GetOldest() on empty cache to return nil")
}
}

9
common/cache/lru.go vendored
View File

@@ -47,8 +47,7 @@ func (l *LRU) Get(key interface{}) interface{} {
// GetOldest returns the oldest entry
func (l *LRU) getOldest() (key, value interface{}) {
x := l.l.Back()
if x != nil {
if x := l.l.Back(); x != nil {
return x.Value.(*item).key, x.Value.(*item).value
}
return
@@ -56,8 +55,7 @@ func (l *LRU) getOldest() (key, value interface{}) {
// GetNewest returns the newest entry
func (l *LRU) getNewest() (key, value interface{}) {
x := l.l.Front()
if x != nil {
if x := l.l.Front(); x != nil {
return x.Value.(*item).key, x.Value.(*item).value
}
return
@@ -93,8 +91,7 @@ func (l *LRU) Len() uint64 {
// removeOldest removes the oldest item from the cache.
func (l *LRU) removeOldestEntry() {
i := l.l.Back()
if i != nil {
if i := l.l.Back(); i != nil {
l.removeElement(i)
}
}

View File

@@ -248,15 +248,13 @@ func TestStringDataContains(t *testing.T) {
originalHaystack := []string{"hello", "world", "USDT", "Contains", "string"}
originalNeedle := "USD"
anotherNeedle := "thing"
expectedOutput := true
expectedOutputTwo := false
actualResult := StringDataContains(originalHaystack, originalNeedle)
if actualResult != expectedOutput {
if expectedOutput := true; actualResult != expectedOutput {
t.Errorf("Expected '%v'. Actual '%v'",
expectedOutput, actualResult)
}
actualResult = StringDataContains(originalHaystack, anotherNeedle)
if actualResult != expectedOutputTwo {
if expectedOutput := false; actualResult != expectedOutput {
t.Errorf("Expected '%v'. Actual '%v'",
expectedOutput, actualResult)
}
@@ -267,15 +265,13 @@ func TestStringDataCompare(t *testing.T) {
originalHaystack := []string{"hello", "WoRld", "USDT", "Contains", "string"}
originalNeedle := "WoRld"
anotherNeedle := "USD"
expectedOutput := true
expectedOutputTwo := false
actualResult := StringDataCompare(originalHaystack, originalNeedle)
if actualResult != expectedOutput {
if expectedOutput := true; actualResult != expectedOutput {
t.Errorf("Expected '%v'. Actual '%v'",
expectedOutput, actualResult)
}
actualResult = StringDataCompare(originalHaystack, anotherNeedle)
if actualResult != expectedOutputTwo {
if expectedOutput := false; actualResult != expectedOutput {
t.Errorf("Expected '%v'. Actual '%v'",
expectedOutput, actualResult)
}
@@ -286,16 +282,14 @@ func TestStringDataCompareUpper(t *testing.T) {
originalHaystack := []string{"hello", "WoRld", "USDT", "Contains", "string"}
originalNeedle := "WoRld"
anotherNeedle := "WoRldD"
expectedOutput := true
expectedOutputTwo := false
actualResult := StringDataCompareInsensitive(originalHaystack, originalNeedle)
if actualResult != expectedOutput {
if expectedOutput := true; actualResult != expectedOutput {
t.Errorf("Expected '%v'. Actual '%v'",
expectedOutput, actualResult)
}
actualResult = StringDataCompareInsensitive(originalHaystack, anotherNeedle)
if actualResult != expectedOutputTwo {
if expectedOutput := false; actualResult != expectedOutput {
t.Errorf("Expected '%v'. Actual '%v'",
expectedOutput, actualResult)
}
@@ -306,15 +300,13 @@ func TestStringDataContainsUpper(t *testing.T) {
originalHaystack := []string{"bLa", "BrO", "sUp"}
originalNeedle := "Bla"
anotherNeedle := "ning"
expectedOutput := true
expectedOutputTwo := false
actualResult := StringDataContainsInsensitive(originalHaystack, originalNeedle)
if actualResult != expectedOutput {
if expectedOutput := true; actualResult != expectedOutput {
t.Errorf("Expected '%v'. Actual '%v'",
expectedOutput, actualResult)
}
actualResult = StringDataContainsInsensitive(originalHaystack, anotherNeedle)
if actualResult != expectedOutputTwo {
if expectedOutput := false; actualResult != expectedOutput {
t.Errorf("Expected '%v'. Actual '%v'",
expectedOutput, actualResult)
}
@@ -410,8 +402,7 @@ func TestGetURIPath(t *testing.T) {
func TestGetExecutablePath(t *testing.T) {
t.Parallel()
_, err := GetExecutablePath()
if err != nil {
if _, err := GetExecutablePath(); err != nil {
t.Errorf("Common GetExecutablePath. Error: %s", err)
}
}

View File

@@ -52,7 +52,7 @@ func TimeFromUnixTimestampFloat(raw interface{}) (time.Time, error) {
if !ok {
return time.Time{}, fmt.Errorf("unable to parse, value not float64: %T", raw)
}
return time.Unix(0, int64(ts)*int64(time.Millisecond)), nil
return time.UnixMilli(int64(ts)), nil
}
// TimeFromUnixTimestampDecimal converts a unix timestamp in decimal form to
@@ -76,23 +76,8 @@ func UnixTimestampStrToTime(timeStr string) (time.Time, error) {
return time.Unix(i, 0), nil
}
// UnixMillis converts a UnixNano timestamp to milliseconds
func UnixMillis(t time.Time) int64 {
return t.UnixNano() / int64(time.Millisecond)
}
// RecvWindow converts a supplied time.Duration to milliseconds
func RecvWindow(d time.Duration) int64 {
return int64(d) / int64(time.Millisecond)
}
// BoolPtr takes in boolen condition and returns pointer version of it
func BoolPtr(condition bool) *bool {
b := condition
return &b
}
// UnixMillisToNano converts Unix milli time to UnixNano
func UnixMillisToNano(milli int64) int64 {
return milli * int64(time.Millisecond)
}

View File

@@ -32,10 +32,8 @@ func TestFloatFromString(t *testing.T) {
func TestIntFromString(t *testing.T) {
t.Parallel()
testString := "1337"
expectedOutput := 1337
actualOutput, err := IntFromString(testString)
if actualOutput != expectedOutput || err != nil {
if expectedOutput := 1337; actualOutput != expectedOutput || err != nil {
t.Errorf("Common IntFromString. Expected '%v'. Actual '%v'. Error: %s",
expectedOutput, actualOutput, err)
}
@@ -136,33 +134,9 @@ func TestUnixTimestampStrToTime(t *testing.T) {
t.Errorf(
"Expected '%s'. Actual '%s'.", expectedOutput, actualResult)
}
actualResult, err = UnixTimestampStrToTime(incorrectTime)
_, err = UnixTimestampStrToTime(incorrectTime)
if err == nil {
t.Error("Common UnixTimestampStrToTime error")
}
}
func TestUnixMillis(t *testing.T) {
t.Parallel()
testTime := time.Date(2014, time.October, 28, 0, 32, 0, 0, time.UTC)
expectedOutput := int64(1414456320000)
actualOutput := UnixMillis(testTime)
if actualOutput != expectedOutput {
t.Errorf("Common UnixMillis. Expected '%d'. Actual '%d'.",
expectedOutput, actualOutput)
}
}
func TestRecvWindow(t *testing.T) {
t.Parallel()
testTime := time.Duration(24760000)
expectedOutput := int64(24)
actualOutput := RecvWindow(testTime)
if actualOutput != expectedOutput {
t.Errorf("Common RecvWindow. Expected '%d'. Actual '%d'",
expectedOutput, actualOutput)
t.Error("should throw an error")
}
}
@@ -176,10 +150,3 @@ func TestBoolPtr(t *testing.T) {
t.Fatal("false expected received true")
}
}
func TestUnixMillisToNano(t *testing.T) {
v := UnixMillisToNano(1588653603424)
if v != 1588653603424000000 {
t.Fatalf("unexpected result received %v", v)
}
}

View File

@@ -35,9 +35,8 @@ func TestBase64Decode(t *testing.T) {
func TestBase64Encode(t *testing.T) {
t.Parallel()
originalInput := []byte("hello")
expectedOutput := "aGVsbG8="
actualResult := Base64Encode(originalInput)
if actualResult != expectedOutput {
if expectedOutput := "aGVsbG8="; actualResult != expectedOutput {
t.Errorf("Expected '%s'. Actual '%s'",
expectedOutput, actualResult)
}

View File

@@ -80,8 +80,7 @@ func TestZip(t *testing.T) {
if filepath.Base(o[0]) != "binance.json" || filepath.Base(o[4]) != "localbitcoins.json" {
t.Fatal("unexpected archive result received")
}
expected := 7
if len(o) != expected {
if expected := 7; len(o) != expected {
t.Fatalf("expected %v files to be extracted received: %v ", expected, len(o))
}

View File

@@ -116,8 +116,7 @@ func WriteAsCSV(filename string, records [][]string) error {
w.Flush()
err := w.Error()
if err != nil {
if err := w.Error(); err != nil {
return err
}
return Write(filename, buf.Bytes())

View File

@@ -12,9 +12,7 @@ func TestCalculateFee(t *testing.T) {
t.Parallel()
originalInput := float64(1)
fee := float64(1)
expectedOutput := 0.01
actualResult := CalculateFee(originalInput, fee)
if expectedOutput != actualResult {
if expectedOutput, actualResult := 0.01, CalculateFee(originalInput, fee); expectedOutput != actualResult {
t.Errorf(
"Expected '%f'. Actual '%f'.", expectedOutput, actualResult)
}
@@ -24,9 +22,7 @@ func TestCalculateAmountWithFee(t *testing.T) {
t.Parallel()
originalInput := float64(1)
fee := float64(1)
expectedOutput := 1.01
actualResult := CalculateAmountWithFee(originalInput, fee)
if expectedOutput != actualResult {
if actualResult, expectedOutput := CalculateAmountWithFee(originalInput, fee), 1.01; expectedOutput != actualResult {
t.Errorf(
"Expected '%f'. Actual '%f'.", expectedOutput, actualResult)
}
@@ -62,9 +58,8 @@ func TestCalculateNetProfit(t *testing.T) {
priceThen := float64(1)
priceNow := float64(10)
costs := float64(1)
expectedOutput := float64(44)
actualResult := CalculateNetProfit(amount, priceThen, priceNow, costs)
if expectedOutput != actualResult {
if expectedOutput := float64(44); expectedOutput != actualResult {
t.Errorf(
"Expected '%f'. Actual '%f'.", expectedOutput, actualResult)
}
@@ -164,8 +159,7 @@ func TestSortinoRatio(t *testing.T) {
if err != nil {
t.Error(err)
}
rr := math.Round(r*10) / 10
if rr != 0.2 {
if rr := math.Round(r*10) / 10; rr != 0.2 {
t.Errorf("expected 0.2, received %v", rr)
}
}
@@ -538,8 +532,7 @@ func TestDecimalSortinoRatio(t *testing.T) {
if err != nil && !errors.Is(err, ErrInexactConversion) {
t.Error(err)
}
rr := r.Round(1)
if !rr.Equal(decimal.NewFromFloat(0.2)) {
if rr := r.Round(1); !rr.Equal(decimal.NewFromFloat(0.2)) {
t.Errorf("expected 0.2, received %v", rr)
}
}

View File

@@ -100,7 +100,6 @@ func (t *TimePeriodCalculator) calculateRanges() {
}
tr.HasDataInRange = t.TimePeriods[len(t.TimePeriods)-1].dataInRange
t.TimeRanges = append(t.TimeRanges, tr)
tr = TimeRange{}
}
}

View File

@@ -8,8 +8,7 @@ import (
func TestNewComm(t *testing.T) {
var cfg base.CommunicationsConfig
_, err := NewComm(&cfg)
if err == nil {
if _, err := NewComm(&cfg); err == nil {
t.Error("NewComm should have failed on no enabled communication mediums")
}

View File

@@ -67,8 +67,7 @@ func (s *Slack) Setup(cfg *base.CommunicationsConfig) {
// Connect connects to the service
func (s *Slack) Connect() error {
err := s.NewConnection()
if err != nil {
if err := s.NewConnection(); err != nil {
return err
}

View File

@@ -25,8 +25,7 @@ func TestSetup(t *testing.T) {
func TestConnect(t *testing.T) {
t.Parallel()
var s Slack
err := s.Connect()
if err == nil {
if err := s.Connect(); err == nil {
t.Error("slack Connect() error cannot be nil")
}
}
@@ -43,8 +42,7 @@ func TestPushEvent(t *testing.T) {
func TestBuildURL(t *testing.T) {
t.Parallel()
var s Slack
v := s.BuildURL("lol123")
if v != "https://slack.com/api/rtm.start?token=lol123" {
if v := s.BuildURL("lol123"); v != "https://slack.com/api/rtm.start?token=lol123" {
t.Error("slack BuildURL() error")
}
}
@@ -183,8 +181,7 @@ func TestGetUsersInGroup(t *testing.T) {
func TestNewConnection(t *testing.T) {
t.Parallel()
var s Slack
err := s.NewConnection()
if err == nil {
if err := s.NewConnection(); err == nil {
t.Error("slack NewConnection() error")
}
}
@@ -192,8 +189,7 @@ func TestNewConnection(t *testing.T) {
func TestWebsocketConnect(t *testing.T) {
t.Parallel()
var s Slack
err := s.WebsocketConnect()
if err == nil {
if err := s.WebsocketConnect(); err == nil {
t.Error("slack WebsocketConnect() error")
}
}

View File

@@ -18,9 +18,8 @@ func TestSetup(t *testing.T) {
func TestConnect(t *testing.T) {
t.Parallel()
var s SMSGlobal
err := s.Connect()
if err != nil {
t.Error("SMSGlobal Connect() error", err)
if err := s.Connect(); err != nil {
t.Error(err)
}
}
@@ -43,9 +42,8 @@ func TestGetEnabledContacts(t *testing.T) {
},
},
}
v := s.GetEnabledContacts()
if v != 1 {
t.Error("SMSGlobal GetEnabledContacts() error")
if v := s.GetEnabledContacts(); v != 1 {
t.Error("expected one enabled contact")
}
}

View File

@@ -17,8 +17,7 @@ func TestSetup(t *testing.T) {
}
func TestConnect(t *testing.T) {
err := s.Connect()
if err != nil {
if err := s.Connect(); err != nil {
t.Error("smtpservice Connect() error", err)
}
}

View File

@@ -36,9 +36,8 @@ func TestSetup(t *testing.T) {
func TestConnect(t *testing.T) {
t.Parallel()
var T Telegram
err := T.Connect()
if err == nil {
t.Error("telegram Connect() error")
if err := T.Connect(); err == nil {
t.Error("expected error")
}
}
@@ -91,8 +90,7 @@ func TestHandleMessages(t *testing.T) {
func TestGetUpdates(t *testing.T) {
t.Parallel()
var T Telegram
_, err := T.GetUpdates()
if err != nil {
if _, err := T.GetUpdates(); err != nil {
t.Error("telegram GetUpdates() error", err)
}
}
@@ -100,10 +98,8 @@ func TestGetUpdates(t *testing.T) {
func TestTestConnection(t *testing.T) {
t.Parallel()
var T Telegram
err := T.TestConnection()
if err.Error() != testErrNotFound {
t.Errorf("telegram TestConnection() error, expected 'Not found' got '%s'",
err)
if err := T.TestConnection(); err.Error() != testErrNotFound {
t.Errorf("received %s, expected: %s", err, testErrNotFound)
}
}

View File

@@ -1870,7 +1870,7 @@ func (c *Config) AssetTypeEnabled(a asset.Item, exch string) (bool, error) {
err = cfg.CurrencyPairs.IsAssetEnabled(a)
if err != nil {
return false, nil
return false, nil // nolint:nilerr // non-fatal error
}
return true, nil
}

View File

@@ -34,8 +34,7 @@ func promptForConfigEncryption() (bool, error) {
log.Println("Would you like to encrypt your config file (y/n)?")
input := ""
_, err := fmt.Scanln(&input)
if err != nil {
if _, err := fmt.Scanln(&input); err != nil {
return false, err
}
@@ -194,8 +193,7 @@ func ConfirmECS(file []byte) bool {
// or errors, if the prefix wasn't found
func skipECS(file io.Reader) error {
buf := make([]byte, len(EncryptConfirmString))
_, err := io.ReadFull(file, buf)
if err != nil {
if _, err := io.ReadFull(file, buf); err != nil {
return err
}
if string(buf) != EncryptConfirmString {

View File

@@ -130,8 +130,7 @@ func TestRemoveECS(t *testing.T) {
func TestMakeNewSessionDK(t *testing.T) {
t.Parallel()
_, _, err := makeNewSessionDK(nil)
if err == nil {
if _, _, err := makeNewSessionDK(nil); err == nil {
t.Fatal("makeNewSessionDK passed with nil key")
}
}
@@ -238,6 +237,7 @@ func TestSaveAndReopenEncryptedConfig(t *testing.T) {
// setAnswersFile sets the given file as the current stdin
// returns the close function to defer for reverting the stdin
func setAnswersFile(t *testing.T, answerFile string) func() {
t.Helper()
oldIn := os.Stdin
inputFile, err := os.Open(answerFile)
@@ -359,6 +359,7 @@ func TestSaveConfigToFileWithErrorInPasswordPrompt(t *testing.T) {
}
func withInteractiveResponse(t *testing.T, response string, body func() error) error {
t.Helper()
// Answers to the prompt
responseFile, err := ioutil.TempFile("", "*.in")
if err != nil {

View File

@@ -35,8 +35,7 @@ func TestGetNonExistentDefaultFilePathDoesNotCreateDefaultDir(t *testing.T) {
if file.Exists(dir) {
t.Skip("The default directory already exists before running the test")
}
_, _, err := GetFilePath("")
if err != nil {
if _, _, err := GetFilePath(""); err != nil {
t.Fatal(err)
}
if file.Exists(dir) {
@@ -921,7 +920,7 @@ func TestSupportsPair(t *testing.T) {
},
},
}
assetType := asset.Spot
assetType := asset.Spot // nolint // ifshort false positive
if cfg.SupportsPair("asdf",
currency.NewPair(currency.BTC, currency.USD), assetType) {
t.Error(
@@ -1284,7 +1283,7 @@ func TestGetForexProviders(t *testing.T) {
func TestGetPrimaryForexProvider(t *testing.T) {
t.Parallel()
fxr := "Fixer"
fxr := "Fixer" // nolint:ifshort,nolintlint // false positive and triggers only on Windows
cfg := &Config{
Currency: CurrencyConfig{
ForexProviders: []currency.FXSettings{
@@ -1937,8 +1936,7 @@ func TestCheckConfig(t *testing.T) {
},
},
}
err := cfg.CheckConfig()
if err != nil {
if err := cfg.CheckConfig(); err != nil {
t.Fatal(err)
}
}
@@ -2209,6 +2207,7 @@ func TestRemoveExchange(t *testing.T) {
}
func TestGetDataPath(t *testing.T) {
t.Parallel()
tests := []struct {
name string
dir string
@@ -2238,6 +2237,7 @@ func TestGetDataPath(t *testing.T) {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
t.Helper()
c := &Config{
DataDirectory: tt.dir,
}
@@ -2278,6 +2278,7 @@ func TestMigrateConfig(t *testing.T) {
{
name: "source present, no target dir",
setup: func(t *testing.T) {
t.Helper()
test, err := os.Create("test.json")
if err != nil {
t.Fatal(err)
@@ -2285,6 +2286,7 @@ func TestMigrateConfig(t *testing.T) {
test.Close()
},
cleanup: func(t *testing.T) {
t.Helper()
os.Remove("test.json")
},
args: args{
@@ -2297,6 +2299,7 @@ func TestMigrateConfig(t *testing.T) {
{
name: "source same as target",
setup: func(t *testing.T) {
t.Helper()
err := file.Write(filepath.Join(dir, File), nil)
if err != nil {
t.Fatal(err)
@@ -2312,6 +2315,7 @@ func TestMigrateConfig(t *testing.T) {
{
name: "source and target present",
setup: func(t *testing.T) {
t.Helper()
err := file.Write(filepath.Join(dir, File), nil)
if err != nil {
t.Fatal(err)

View File

@@ -48,8 +48,7 @@ func New(dnsList, domainList []string, checkInterval time.Duration) (*Checker, e
c.CheckInterval = checkInterval
}
err := c.initialCheck()
if err != nil {
if err := c.initialCheck(); err != nil {
return nil, err
}

View File

@@ -51,8 +51,7 @@ func TestRoleMarshalJSON(t *testing.T) {
t.Error("Role MarshalJSON() error", err)
}
expected := `"fiatCurrency"`
if string(d) != expected {
if expected := `"fiatCurrency"`; string(d) != expected {
t.Errorf("Role MarshalJSON() error expected %s but received %s",
expected,
string(d))
@@ -337,18 +336,14 @@ func TestBaseCode(t *testing.T) {
}
func TestCodeString(t *testing.T) {
expected := "TEST"
cc := NewCode("TEST")
if cc.String() != expected {
if cc, expected := NewCode("TEST"), "TEST"; cc.String() != expected {
t.Errorf("Currency Code String() error expected %s but received %s",
expected, cc)
}
}
func TestCodeLower(t *testing.T) {
expected := "test"
cc := NewCode("TEST")
if cc.Lower().String() != expected {
if cc, expected := NewCode("TEST"), "test"; cc.Lower().String() != expected {
t.Errorf("Currency Code Lower() error expected %s but received %s",
expected,
cc.Lower())
@@ -356,9 +351,7 @@ func TestCodeLower(t *testing.T) {
}
func TestCodeUpper(t *testing.T) {
expected := "TEST"
cc := NewCode("test")
if cc.Upper().String() != expected {
if cc, expected := NewCode("test"), "TEST"; cc.Upper().String() != expected {
t.Errorf("Currency Code Upper() error expected %s but received %s",
expected,
cc.Upper())

View File

@@ -33,14 +33,13 @@ func TestNewConversionFromString(t *testing.T) {
func TestNewConversionFromStrings(t *testing.T) {
from := "AUD"
to := "USD"
expected := "AUDUSD"
conv, err := NewConversionFromStrings(from, to)
if err != nil {
t.Error(err)
}
if conv.String() != expected {
if expected := "AUDUSD"; conv.String() != expected {
t.Errorf("NewConversion() error expected %s but received %s",
expected,
conv)
@@ -50,14 +49,13 @@ func TestNewConversionFromStrings(t *testing.T) {
func TestNewConversion(t *testing.T) {
from := NewCode("AUD")
to := NewCode("USD")
expected := "AUDUSD"
conv, err := NewConversion(from, to)
if err != nil {
t.Error(err)
}
if conv.String() != expected {
if expected := "AUDUSD"; conv.String() != expected {
t.Errorf("NewConversion() error expected %s but received %s",
expected,
conv)
@@ -79,8 +77,7 @@ func TestConversionIsInvalid(t *testing.T) {
}
to = AUD
conv, err = NewConversion(from, to)
if err == nil {
if _, err = NewConversion(from, to); err == nil {
t.Error("Expected error")
}
}
@@ -100,8 +97,7 @@ func TestConversionIsFiatPair(t *testing.T) {
}
to = LTC
conv, err = NewConversion(from, to)
if err == nil {
if _, err = NewConversion(from, to); err == nil {
t.Error("Expected error")
}
}
@@ -159,17 +155,16 @@ func TestConversionsRatesSystem(t *testing.T) {
p := SuperDuperConversionSystem.m[USD.Item][AUD.Item]
// inverse * to a rate
pi := SuperDuperConversionSystem.m[AUD.Item][USD.Item]
r := *p * 1000
expectedRate := 1396.9317581
if r != expectedRate {
if r := *p * 1000; r != expectedRate {
t.Errorf("Convert() error expected %.13f but received %.13f",
expectedRate,
r)
}
inverseR := *pi * expectedRate
expectedInverseRate := float64(1000)
if inverseR != expectedInverseRate {
if inverseR := *pi * expectedRate; inverseR != expectedInverseRate {
t.Errorf("Convert() error expected %.13f but received %.13f",
expectedInverseRate,
inverseR)

View File

@@ -93,7 +93,7 @@ func CopyPairFormat(p Pair, pairs []Pair, exact bool) Pair {
return pairs[x]
}
}
return Pair{Base: NewCode(""), Quote: NewCode("")}
return Pair{}
}
// FormatPairs formats a string array to a list of currency pairs with the

View File

@@ -63,8 +63,7 @@ func (c *CurrencyConverter) GetRates(baseCurrency, symbols string) (map[string]f
}
currLen := len(completedStrings)
mod := currLen % 2
if mod == 0 {
if mod := currLen % 2; mod == 0 {
processBatch(currLen)
return rates, nil
}

View File

@@ -74,8 +74,7 @@ func TestConvert(t *testing.T) {
t.Skip()
}
_, err := c.Convert("AUD", "USD")
if err != nil {
if _, err := c.Convert("AUD", "USD"); err != nil {
t.Fatal(err)
}
}
@@ -96,8 +95,7 @@ func TestGetCountries(t *testing.T) {
t.Skip()
}
_, err := c.GetCountries()
if err != nil {
if _, err := c.GetCountries(); err != nil {
t.Fatal(err)
}
}

View File

@@ -211,8 +211,7 @@ func TestGetRates(t *testing.T) {
t.Skip("API key not set, skipping test")
}
_, err := e.GetRates("EUR", "")
if err != nil {
if _, err := e.GetRates("EUR", ""); err != nil {
t.Fatalf("failed to GetRates. Err: %s", err)
}
}

View File

@@ -19,6 +19,7 @@ var f Fixer
var isSetup bool
func setup(t *testing.T) {
t.Helper()
if !isSetup {
err := f.Setup(base.Settings{})
if err != nil {

View File

@@ -88,8 +88,7 @@ func TestGetOHLC(t *testing.T) {
func TestGetUsageStats(t *testing.T) {
t.Parallel()
_, err := o.GetUsageStats(false)
if err == nil {
if _, err := o.GetUsageStats(false); err == nil {
t.Error("GetUsageStats() Expected error")
}
}

View File

@@ -10,6 +10,7 @@ import (
var p PairsManager
func initTest(t *testing.T) {
t.Helper()
spotAvailable, err := NewPairsFromStrings([]string{"BTC-USD", "LTC-USD"})
if err != nil {
t.Fatal(err)

View File

@@ -16,13 +16,11 @@ func TestLower(t *testing.T) {
if err != nil {
t.Fatal(err)
}
actual := pair.Lower()
expected, err := NewPairFromString(defaultPair)
if err != nil {
t.Fatal(err)
}
if actual.String() != expected.Lower().String() {
if actual := pair.Lower(); actual.String() != expected.Lower().String() {
t.Errorf("Lower(): %s was not equal to expected value: %s",
actual,
expected.Lower())
@@ -35,12 +33,11 @@ func TestUpper(t *testing.T) {
if err != nil {
t.Fatal(err)
}
actual := pair.Upper()
expected, err := NewPairFromString(defaultPair)
if err != nil {
t.Fatal(err)
}
if actual.String() != expected.String() {
if actual := pair.Upper(); actual.String() != expected.String() {
t.Errorf("Upper(): %s was not equal to expected value: %s",
actual, expected)
}
@@ -126,9 +123,7 @@ func TestIsFiatPair(t *testing.T) {
func TestString(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := defaultPair
expected := pair.String()
if actual != expected {
if actual, expected := defaultPair, pair.String(); actual != expected {
t.Errorf("String(): %s was not equal to expected value: %s",
actual, expected)
}
@@ -137,9 +132,7 @@ func TestString(t *testing.T) {
func TestFirstCurrency(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := pair.Base
expected := BTC
if actual != expected {
if actual, expected := pair.Base, BTC; actual != expected {
t.Errorf(
"GetFirstCurrency(): %s was not equal to expected value: %s",
actual, expected,
@@ -150,9 +143,7 @@ func TestFirstCurrency(t *testing.T) {
func TestSecondCurrency(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := pair.Quote
expected := USD
if actual != expected {
if actual, expected := pair.Quote, USD; actual != expected {
t.Errorf(
"GetSecondCurrency(): %s was not equal to expected value: %s",
actual, expected,
@@ -163,9 +154,7 @@ func TestSecondCurrency(t *testing.T) {
func TestPair(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := pair.String()
expected := defaultPair
if actual != expected {
if actual, expected := pair.String(), defaultPair; actual != expected {
t.Errorf(
"Pair(): %s was not equal to expected value: %s",
actual, expected,
@@ -282,9 +271,7 @@ func TestEqualIncludeReciprocal(t *testing.T) {
func TestSwap(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := pair.Swap().String()
expected := "USDBTC"
if actual != expected {
if actual, expected := pair.Swap().String(), "USDBTC"; actual != expected {
t.Errorf(
"TestSwap: %s was not equal to expected value: %s",
actual, expected,
@@ -308,9 +295,7 @@ func TestEmpty(t *testing.T) {
func TestNewPair(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := pair.String()
expected := defaultPair
if actual != expected {
if expected, actual := defaultPair, pair.String(); actual != expected {
t.Errorf(
"Pair(): %s was not equal to expected value: %s",
actual, expected,

View File

@@ -185,11 +185,8 @@ func (p Pairs) FindDifferences(pairs Pairs) (newPairs, removedPairs Pairs) {
// GetRandomPair returns a random pair from a list of pairs
func (p Pairs) GetRandomPair() Pair {
pairsLen := len(p)
if pairsLen == 0 {
return Pair{Base: NewCode(""), Quote: NewCode("")}
if pairsLen := len(p); pairsLen != 0 {
return p[rand.Intn(pairsLen)] // nolint:gosec // basic number generation required, no need for crypo/rand
}
return p[rand.Intn(pairsLen)] // nolint:gosec // basic number generation required, no need for crypo/rand
return Pair{}
}

View File

@@ -82,7 +82,6 @@ func (s *Storage) RunUpdater(overrides BotOverrides, settings *MainConfiguration
if err != nil {
log.Errorf(log.Global,
"Unable to setup CoinMarketCap analysis. Error: %s", err)
c = nil
settings.CryptocurrencyProvider.Enabled = false
} else {
s.currencyAnalysis = c

View File

@@ -3,13 +3,12 @@ package currency
import "testing"
func TestGetSymbolByCurrencyName(t *testing.T) {
expected := "₩"
actual, err := GetSymbolByCurrencyName(KPW)
if err != nil {
t.Errorf("TestGetSymbolByCurrencyName error: %s", err)
}
if actual != expected {
if expected := "₩"; actual != expected {
t.Errorf("TestGetSymbolByCurrencyName differing values")
}

View File

@@ -30,17 +30,17 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
[SQLBoiler](https://github.com/thrasher-corp/sqlboiler)
```shell script
go get -u github.com/thrasher-corp/sqlboiler
go install github.com/thrasher-corp/sqlboiler
```
[Postgres Driver](https://github.com/thrasher-corp/sqlboiler/drivers/sqlboiler-psql)
```shell script
go get -u github.com/thrasher-corp/sqlboiler/drivers/sqlboiler-psql
go install github.com/thrasher-corp/sqlboiler/drivers/sqlboiler-psql
```
[SQLite Driver](https://github.com/thrasher-corp/sqlboiler-sqlite3)
```shell script
go get -u github.com/thrasher-corp/sqlboiler-sqlite3
go install github.com/thrasher-corp/sqlboiler-sqlite3
```
##### Configuration

View File

@@ -241,25 +241,19 @@ func TestSeries(t *testing.T) {
t.Errorf("unexpected number of results received: %v", len(ret.Candles))
}
ret, err = Series("", "", "", 0, "", start, end)
_, err = Series("", "", "", 0, "", start, end)
if !errors.Is(err, errInvalidInput) {
t.Fatal(err)
}
ret, err = Series(testExchanges[0].Name,
_, err = Series(testExchanges[0].Name,
"BTC", "MOON",
864000, "spot",
start, end)
if err != nil {
if !errors.Is(err, errInvalidInput) {
if !errors.Is(err, ErrNoCandleDataFound) {
t.Fatal(err)
}
}
if err != nil && !errors.Is(err, errInvalidInput) && !errors.Is(err, ErrNoCandleDataFound) {
t.Fatal(err)
}
err = testhelpers.CloseDatabase(dbConn)
if err != nil {
if err = testhelpers.CloseDatabase(dbConn); err != nil {
t.Error(err)
}
})

View File

@@ -177,8 +177,7 @@ func seed() error {
func TestLoadCSV(t *testing.T) {
testData := filepath.Join("..", "..", "..", "testdata", "exchangelist.csv")
_, err := LoadCSV(testData)
if err != nil {
if _, err := LoadCSV(testData); err != nil {
t.Fatal(err)
}
}

View File

@@ -97,6 +97,7 @@ func TestTrades(t *testing.T) {
}
func tradeSQLTester(t *testing.T) {
t.Helper()
var trades, trades2 []Data
firstTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
for i := 0; i < 20; i++ {

View File

@@ -151,6 +151,7 @@ func seedWithdrawData() {
}
}
func withdrawHelper(t *testing.T) {
t.Helper()
seedWithdrawData()
_, err := GetEventByUUID(withdraw.DryRunID.String())

View File

@@ -292,7 +292,10 @@ func (d *Dispatcher) subscribe(id uuid.UUID) (chan interface{}, error) {
}
// Get an unused channel from the channel pool
unusedChan := d.outbound.Get().(chan interface{})
unusedChan, ok := d.outbound.Get().(chan interface{})
if !ok {
return nil, errors.New("unable to type assert unusedChan")
}
// Lock for writing to the route list
d.rMtx.Lock()
@@ -356,11 +359,11 @@ func (d *Dispatcher) getNewID() (uuid.UUID, error) {
// Check to see if it already exists
d.rMtx.RLock()
_, ok := d.routes[newID]
d.rMtx.RUnlock()
if ok {
if _, ok := d.routes[newID]; ok {
d.rMtx.RUnlock()
return newID, errors.New("dispatcher collision detected, uuid already exists")
}
d.rMtx.RUnlock()
// Write the key into system
d.rMtx.Lock()

View File

@@ -462,7 +462,7 @@ func (f *FTX) SendAuthHTTPRequest(ctx context.Context, method, path string, data
// within time receive windows. NOTE: This is not always necessary and the above
// SendHTTPRequest example will suffice.
generate := func() (*request.Item, error) {
ts := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
ts := strconv.FormatInt(time.Now().UnixMilli(), 10)
var body io.Reader
var hmac, payload []byte
var err error
@@ -1028,8 +1028,7 @@ https://docs.ftx.com/#private-channels
```go
// WsAuth sends an authentication message to receive auth data
func (f *FTX) WsAuth() error {
intNonce := time.Now().UnixNano() / 1000000
strNonce := strconv.FormatInt(intNonce, 10)
strNonce := strconv.FormatInt(time.Now().UnixMilli(), 10)
hmac := crypto.GetHMAC(
crypto.HashSHA256,
[]byte(strNonce+"websocket_login"),

View File

@@ -234,6 +234,7 @@ func TestGetAllActiveAccounts(t *testing.T) {
}
func makeHTTPGetRequest(t *testing.T, response interface{}) *http.Response {
t.Helper()
w := httptest.NewRecorder()
err := writeResponse(w, response)

View File

@@ -51,8 +51,7 @@ func SetupDatabaseConnectionManager(cfg *database.Config) (*DatabaseConnectionMa
cfg: *cfg,
dbConn: database.DB,
}
err := m.dbConn.SetConfig(cfg)
if err != nil {
if err := m.dbConn.SetConfig(cfg); err != nil {
return nil, err
}
@@ -177,8 +176,7 @@ func (m *DatabaseConnectionManager) checkConnection() error {
return database.ErrNoDatabaseProvided
}
err := m.dbConn.Ping()
if err != nil {
if err := m.dbConn.Ping(); err != nil {
m.dbConn.SetConnected(false)
return err
}

View File

@@ -455,7 +455,7 @@ ranges:
lookup = append(lookup, *result)
job.Results[result.IntervalStartDate] = lookup
}
completed := true
completed := true // nolint:ifshort,nolintlint // false positive and triggers only on Windows
allResultsSuccessful := true
allResultsFailed := true
completionCheck:
@@ -553,7 +553,7 @@ timesToFetch:
job.Results[result.IntervalStartDate] = lookup
}
completed := true
completed := true // nolint:ifshort,nolintlint // false positive and triggers only on Windows
allResultsSuccessful := true
allResultsFailed := true
completionCheck:
@@ -709,7 +709,7 @@ func (m *DataHistoryManager) processCandleData(job *DataHistoryJob, exch exchang
if err != nil {
r.Result += "could not get candles: " + err.Error() + ". "
r.Status = dataHistoryStatusFailed
return r, nil
return r, nil // nolint:nilerr // error is returned in the job result
}
job.rangeHolder.SetHasDataFromCandles(candles.Candles)
for i := range job.rangeHolder.Ranges[intervalIndex].Intervals {
@@ -758,13 +758,13 @@ func (m *DataHistoryManager) processTradeData(job *DataHistoryJob, exch exchange
if err != nil {
r.Result += "could not get trades: " + err.Error() + ". "
r.Status = dataHistoryStatusFailed
return r, nil
return r, nil // nolint:nilerr // error is returned in the job result
}
candles, err := trade.ConvertTradesToCandles(job.Interval, trades...)
if err != nil {
r.Result += "could not convert candles to trades: " + err.Error() + ". "
r.Status = dataHistoryStatusFailed
return r, nil
return r, nil // nolint:nilerr // error is returned in the job result
}
job.rangeHolder.SetHasDataFromCandles(candles.Candles)
for i := range job.rangeHolder.Ranges[intervalIndex].Intervals {
@@ -825,13 +825,13 @@ func (m *DataHistoryManager) convertTradesToCandles(job *DataHistoryJob, startRa
if err != nil {
r.Result = "could not get trades in range: " + err.Error()
r.Status = dataHistoryStatusFailed
return r, nil
return r, nil // nolint:nilerr // error is returned in the job result
}
candles, err := trade.ConvertTradesToCandles(job.Interval, trades...)
if err != nil {
r.Result = "could not convert trades in range: " + err.Error()
r.Status = dataHistoryStatusFailed
return r, nil
return r, nil // nolint:nilerr // error is returned in the job result
}
candles.SourceJobID = job.ID
err = m.saveCandlesInBatches(job, &candles, r)
@@ -864,13 +864,13 @@ func (m *DataHistoryManager) convertCandleData(job *DataHistoryJob, startRange,
if err != nil {
r.Result = "could not get candles in range: " + err.Error()
r.Status = dataHistoryStatusFailed
return r, nil
return r, nil // nolint:nilerr // error is returned in the job result
}
newCandles, err := kline.ConvertToNewInterval(&candles, job.ConversionInterval)
if err != nil {
r.Result = "could not convert candles in range: " + err.Error()
r.Status = dataHistoryStatusFailed
return r, nil
return r, nil // nolint:nilerr // error is returned in the job result
}
newCandles.SourceJobID = job.ID
err = m.saveCandlesInBatches(job, &candles, r)
@@ -912,14 +912,14 @@ func (m *DataHistoryManager) validateCandles(job *DataHistoryJob, exch exchange.
if err != nil {
r.Result = "could not get API candles: " + err.Error()
r.Status = dataHistoryStatusFailed
return r, nil
return r, nil // nolint:nilerr // error is returned in the job result
}
apiCandles.ValidationJobID = job.ID
dbCandles, err := m.candleLoader(job.Exchange, job.Pair, job.Asset, job.Interval, startRange, endRange)
if err != nil {
r.Result = "could not get database candles: " + err.Error()
r.Status = dataHistoryStatusFailed
return r, nil
return r, nil // nolint:nilerr // error is returned in the job result
}
if len(dbCandles.Candles) == 0 {
r.Result = fmt.Sprintf("missing database candles for period %v-%v", startRange, endRange)

View File

@@ -655,6 +655,7 @@ func TestCompareJobsToData(t *testing.T) {
}
func TestRunJob(t *testing.T) {
t.Parallel()
testCases := []*DataHistoryJob{
{
Nickname: "TestRunJobDataHistoryCandleDataType",
@@ -923,6 +924,7 @@ func TestConverters(t *testing.T) {
// test helper functions
func createDHM(t *testing.T) (*DataHistoryManager, *datahistoryjob.DataHistoryJob) {
t.Helper()
em := SetupExchangeManager()
exch, err := em.NewExchangeByName(testExchange)
if !errors.Is(err, nil) {

View File

@@ -708,8 +708,7 @@ func (bot *Engine) Stop() {
// Wait for services to gracefully shutdown
bot.ServicesWG.Wait()
err := gctlog.CloseLogger()
if err != nil {
if err := gctlog.CloseLogger(); err != nil {
log.Printf("Failed to close logger. Error: %v\n", err)
}
}

View File

@@ -36,6 +36,7 @@ import (
var testExchange = "Bitstamp"
func CreateTestBot(t *testing.T) *Engine {
t.Helper()
cFormat := &currency.PairFormat{Uppercase: true}
cp1 := currency.NewPair(currency.BTC, currency.USD)
cp2 := currency.NewPair(currency.BTC, currency.USDT)
@@ -86,11 +87,9 @@ func CreateTestBot(t *testing.T) *Engine {
},
},
}}}
err := bot.LoadExchange(testExchange, nil)
if err != nil {
if err := bot.LoadExchange(testExchange, nil); err != nil {
t.Fatalf("SetupTest: Failed to load exchange: %s", err)
}
return bot
}
@@ -117,6 +116,7 @@ func TestGetRPCEndpoints(t *testing.T) {
}
func TestSetSubsystem(t *testing.T) {
t.Parallel()
testCases := []struct {
Subsystem string
Engine *Engine

View File

@@ -182,6 +182,7 @@ func TestOrderManagerStop(t *testing.T) {
}
func OrdersSetup(t *testing.T) *OrderManager {
t.Helper()
var wg sync.WaitGroup
em := SetupExchangeManager()
exch, err := em.NewExchangeByName(testExchange)
@@ -377,8 +378,7 @@ func TestExists(t *testing.T) {
Exchange: testExchange,
ID: "TestExists",
}
err := m.orderStore.add(o)
if err != nil {
if err := m.orderStore.add(o); err != nil {
t.Error(err)
}
b := m.orderStore.exists(o)
@@ -551,8 +551,7 @@ func TestCancelAllOrders(t *testing.T) {
ID: "TestCancelAllOrders",
Status: order.New,
}
err := m.orderStore.add(o)
if err != nil {
if err := m.orderStore.add(o); err != nil {
t.Error(err)
}

View File

@@ -109,8 +109,7 @@ func (s *RPCServer) authenticateClient(ctx context.Context) (context.Context, er
// StartRPCServer starts a gRPC server with TLS auth
func StartRPCServer(engine *Engine) {
targetDir := utils.GetTLSDir(engine.Settings.DataDir)
err := checkCerts(targetDir)
if err != nil {
if err := checkCerts(targetDir); err != nil {
log.Errorf(log.GRPCSys, "gRPC checkCerts failed. err: %s\n", err)
return
}
@@ -678,7 +677,15 @@ func (s *RPCServer) GetAccountInfoStream(r *gctrpc.GetAccountInfoRequest, stream
return errDispatchSystem
}
acc := (*data.(*interface{})).(account.Holdings)
d := *data.(*interface{})
if d == nil {
return errors.New("unable to type assert data")
}
acc, ok := d.(account.Holdings)
if !ok {
return errors.New("unable to type assert account holdings data")
}
var accounts []*gctrpc.Account
for x := range acc.Accounts {
@@ -1977,7 +1984,16 @@ func (s *RPCServer) GetExchangeOrderbookStream(r *gctrpc.GetExchangeOrderbookStr
return errDispatchSystem
}
ob := (*data.(*interface{})).(orderbook.Base)
d := *data.(*interface{})
if d == nil {
return errors.New("unable to type assert data")
}
ob, ok := d.(orderbook.Base)
if !ok {
return errors.New("unable to type assert orderbook data")
}
bids := make([]*gctrpc.OrderbookItem, len(ob.Bids))
for i := range ob.Bids {
bids[i] = &gctrpc.OrderbookItem{
@@ -2050,7 +2066,16 @@ func (s *RPCServer) GetTickerStream(r *gctrpc.GetTickerStreamRequest, stream gct
if !ok {
return errDispatchSystem
}
t := (*data.(*interface{})).(ticker.Price)
d := *data.(*interface{})
if d == nil {
return errors.New("unable to type assert data")
}
t, ok := d.(ticker.Price)
if !ok {
return errors.New("unable to type assert ticker data")
}
err := stream.Send(&gctrpc.TickerResponse{
Pair: &gctrpc.CurrencyPair{
@@ -2099,7 +2124,16 @@ func (s *RPCServer) GetExchangeTickerStream(r *gctrpc.GetExchangeTickerStreamReq
if !ok {
return errDispatchSystem
}
t := (*data.(*interface{})).(ticker.Price)
d := *data.(*interface{})
if d == nil {
return errors.New("unable to type assert data")
}
t, ok := d.(ticker.Price)
if !ok {
return errors.New("unable to type assert ticker data")
}
err := stream.Send(&gctrpc.TickerResponse{
Pair: &gctrpc.CurrencyPair{
@@ -2355,7 +2389,11 @@ func (s *RPCServer) GCTScriptStatus(_ context.Context, _ *gctrpc.GCTScriptStatus
}
gctscript.AllVMSync.Range(func(k, v interface{}) bool {
vm := v.(*gctscript.VM)
vm, ok := v.(*gctscript.VM)
if !ok {
log.Errorf(log.GRPCSys, "Unable to type assert gctscript.VM")
return false
}
resp.Scripts = append(resp.Scripts, &gctrpc.GCTScript{
UUID: vm.ID.String(),
Name: vm.ShortName(),
@@ -2376,6 +2414,7 @@ func (s *RPCServer) GCTScriptQuery(_ context.Context, r *gctrpc.GCTScriptQueryRe
UUID, err := uuid.FromString(r.Script.UUID)
if err != nil {
// nolint:nilerr // error is returned in the GCTScriptQueryResponse
return &gctrpc.GCTScriptQueryResponse{Status: MsgStatusError, Data: err.Error()}, nil
}
@@ -2415,9 +2454,8 @@ func (s *RPCServer) GCTScriptExecute(_ context.Context, r *gctrpc.GCTScriptExecu
}
script := filepath.Join(r.Script.Path, r.Script.Name)
err := gctVM.Load(script)
if err != nil {
return &gctrpc.GenericResponse{
if err := gctVM.Load(script); err != nil {
return &gctrpc.GenericResponse{ // nolint:nilerr // error is returned in the generic response
Status: MsgStatusError,
Data: err.Error(),
}, nil
@@ -2439,7 +2477,7 @@ func (s *RPCServer) GCTScriptStop(_ context.Context, r *gctrpc.GCTScriptStopRequ
UUID, err := uuid.FromString(r.Script.UUID)
if err != nil {
return &gctrpc.GenericResponse{Status: MsgStatusError, Data: err.Error()}, nil
return &gctrpc.GenericResponse{Status: MsgStatusError, Data: err.Error()}, nil // nolint:nilerr // error is returned in the generic response
}
if v, f := gctscript.AllVMSync.Load(UUID); f {
@@ -2603,7 +2641,7 @@ func (s *RPCServer) GCTScriptStopAll(context.Context, *gctrpc.GCTScriptStopAllRe
err := s.gctScriptManager.ShutdownAll()
if err != nil {
return &gctrpc.GenericResponse{Status: "error", Data: err.Error()}, nil
return &gctrpc.GenericResponse{Status: "error", Data: err.Error()}, nil // nolint:nilerr // error is returned in the generic response
}
return &gctrpc.GenericResponse{
@@ -2621,6 +2659,7 @@ func (s *RPCServer) GCTScriptAutoLoadToggle(_ context.Context, r *gctrpc.GCTScri
if r.Status {
err := s.gctScriptManager.Autoload(r.Script, true)
if err != nil {
// nolint:nilerr // error is returned in the generic response
return &gctrpc.GenericResponse{Status: "error", Data: err.Error()}, nil
}
return &gctrpc.GenericResponse{Status: "success", Data: "script " + r.Script + " removed from autoload list"}, nil
@@ -2628,7 +2667,7 @@ func (s *RPCServer) GCTScriptAutoLoadToggle(_ context.Context, r *gctrpc.GCTScri
err := s.gctScriptManager.Autoload(r.Script, false)
if err != nil {
return &gctrpc.GenericResponse{Status: "error", Data: err.Error()}, nil
return &gctrpc.GenericResponse{Status: "error", Data: err.Error()}, nil // nolint:nilerr // error is returned in the generic response
}
return &gctrpc.GenericResponse{Status: "success", Data: "script " + r.Script + " added to autoload list"}, nil
}
@@ -2726,7 +2765,7 @@ func (s *RPCServer) UpdateExchangeSupportedPairs(ctx context.Context, r *gctrpc.
return nil, err
}
base := exch.GetBase()
base := exch.GetBase() // nolint:ifshort,nolintlint // false positive and triggers only on Windows
if base == nil {
return nil, errExchangeBaseNotFound
}

View File

@@ -1557,8 +1557,7 @@ func TestGetActiveDataHistoryJobs(t *testing.T) {
Interval: kline.OneMin,
}
err := m.UpsertJob(dhj, false)
if !errors.Is(err, nil) {
if err := m.UpsertJob(dhj, false); !errors.Is(err, nil) {
t.Fatalf("received %v, expected %v", err, nil)
}

View File

@@ -98,8 +98,7 @@ func (m *WithdrawManager) WithdrawalEventByID(id string) (*withdraw.Response, er
if m == nil {
return nil, ErrNilSubsystem
}
v := withdraw.Cache.Get(id)
if v != nil {
if v := withdraw.Cache.Get(id); v != nil {
return v.(*withdraw.Response), nil
}

View File

@@ -26,10 +26,10 @@ func TestWait(t *testing.T) {
wg.Wait()
wg.Add(100)
isLeaky(&wait, nil, t)
isLeaky(t, &wait, nil)
wait.Alert()
wg.Wait()
isLeaky(&wait, nil, t)
isLeaky(t, &wait, nil)
// use kick
ch := make(chan struct{})
@@ -46,11 +46,11 @@ func TestWait(t *testing.T) {
}
wg.Wait()
wg.Add(100)
isLeaky(&wait, ch, t)
isLeaky(t, &wait, ch)
close(ch)
wg.Wait()
ch = make(chan struct{})
isLeaky(&wait, ch, t)
isLeaky(t, &wait, ch)
// late receivers
wg.Add(100)
@@ -70,15 +70,15 @@ func TestWait(t *testing.T) {
}
wg.Wait()
wg.Add(100)
isLeaky(&wait, ch, t)
isLeaky(t, &wait, ch)
wait.Alert()
wg.Wait()
isLeaky(&wait, ch, t)
isLeaky(t, &wait, ch)
}
// isLeaky tests to see if the wait functionality is returning an abnormal
// channel that is operational when it shouldn't be.
func isLeaky(a *Notice, ch chan struct{}, t *testing.T) {
func isLeaky(t *testing.T, a *Notice, ch chan struct{}) {
t.Helper()
check := a.Wait(ch)
time.Sleep(time.Millisecond * 5) // When we call wait a routine for hold is

View File

@@ -62,8 +62,7 @@ func TestIsValid(t *testing.T) {
}
func TestNew(t *testing.T) {
_, err := New("Spota")
if err == nil {
if _, err := New("Spota"); err == nil {
t.Fatal("TestNew returned an unexpected result")
}

View File

@@ -374,51 +374,59 @@ func (b *Binance) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([
path := candleStick + "?" + params.Encode()
if err := b.SendHTTPRequest(ctx,
err = b.SendHTTPRequest(ctx,
exchange.RestSpotSupplementary,
path,
spotDefaultRate,
&resp); err != nil {
return klineData, err
&resp)
if err != nil {
return nil, err
}
for _, responseData := range resp.([]interface{}) {
responseData, ok := resp.([]interface{})
if !ok {
return nil, errors.New("unable to type assert responseData")
}
for x := range responseData {
individualData, ok := responseData[x].([]interface{})
if !ok {
return nil, errors.New("unable to type assert individualData")
}
if len(individualData) != 12 {
return nil, errors.New("unexpected kline data length")
}
var candle CandleStick
for i, individualData := range responseData.([]interface{}) {
switch i {
case 0:
tempTime := individualData.(float64)
var err error
candle.OpenTime, err = convert.TimeFromUnixTimestampFloat(tempTime)
if err != nil {
return klineData, err
}
case 1:
candle.Open, _ = strconv.ParseFloat(individualData.(string), 64)
case 2:
candle.High, _ = strconv.ParseFloat(individualData.(string), 64)
case 3:
candle.Low, _ = strconv.ParseFloat(individualData.(string), 64)
case 4:
candle.Close, _ = strconv.ParseFloat(individualData.(string), 64)
case 5:
candle.Volume, _ = strconv.ParseFloat(individualData.(string), 64)
case 6:
tempTime := individualData.(float64)
var err error
candle.CloseTime, err = convert.TimeFromUnixTimestampFloat(tempTime)
if err != nil {
return klineData, err
}
case 7:
candle.QuoteAssetVolume, _ = strconv.ParseFloat(individualData.(string), 64)
case 8:
candle.TradeCount = individualData.(float64)
case 9:
candle.TakerBuyAssetVolume, _ = strconv.ParseFloat(individualData.(string), 64)
case 10:
candle.TakerBuyQuoteAssetVolume, _ = strconv.ParseFloat(individualData.(string), 64)
}
if candle.OpenTime, err = convert.TimeFromUnixTimestampFloat(individualData[0]); err != nil {
return nil, err
}
if candle.Open, err = convert.FloatFromString(individualData[1]); err != nil {
return nil, err
}
if candle.High, err = convert.FloatFromString(individualData[2]); err != nil {
return nil, err
}
if candle.Low, err = convert.FloatFromString(individualData[3]); err != nil {
return nil, err
}
if candle.Close, err = convert.FloatFromString(individualData[4]); err != nil {
return nil, err
}
if candle.Volume, err = convert.FloatFromString(individualData[5]); err != nil {
return nil, err
}
if candle.CloseTime, err = convert.TimeFromUnixTimestampFloat(individualData[6]); err != nil {
return nil, err
}
if candle.QuoteAssetVolume, err = convert.FloatFromString(individualData[7]); err != nil {
return nil, err
}
if candle.TradeCount, ok = individualData[8].(float64); !ok {
return nil, errors.New("unable to type assert trade count")
}
if candle.TakerBuyAssetVolume, err = convert.FloatFromString(individualData[9]); err != nil {
return nil, err
}
if candle.TakerBuyQuoteAssetVolume, err = convert.FloatFromString(individualData[10]); err != nil {
return nil, err
}
klineData = append(klineData, candle)
}
@@ -784,7 +792,7 @@ func (b *Binance) SendAuthHTTPRequest(ctx context.Context, ePath exchange.URL, m
}
if params.Get("recvWindow") == "" {
params.Set("recvWindow", strconv.FormatInt(convert.RecvWindow(defaultRecvWindow), 10))
params.Set("recvWindow", strconv.FormatInt(defaultRecvWindow.Milliseconds(), 10))
}
interim := json.RawMessage{}

View File

@@ -1,4 +1,5 @@
//+build !mock_test_off
//go:build !mock_test_off
// +build !mock_test_off
// This will build if build tag mock_test_off is not parsed and will try to mock
// all tests in _test.go

View File

@@ -1622,6 +1622,7 @@ func TestGetAggregatedTradesBatched(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if tt.mock != mockTests {
t.Skip()
}
@@ -1677,6 +1678,7 @@ func TestGetAggregatedTradesErrors(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, err := b.GetAggregatedTrades(context.Background(), tt.args)
if err == nil {
t.Errorf("Binance.GetAggregatedTrades() error = %v, wantErr true", err)
@@ -2550,8 +2552,8 @@ func TestWsOrderExecutionReport(t *testing.T) {
Side: order.Buy,
Status: order.New,
AssetType: asset.Spot,
Date: time.Unix(0, 1616627567900*int64(time.Millisecond)),
LastUpdated: time.Unix(0, 1616627567900*int64(time.Millisecond)),
Date: time.UnixMilli(1616627567900),
LastUpdated: time.UnixMilli(1616627567900),
Pair: currency.NewPair(currency.BTC, currency.USDT),
}
// empty the channel. otherwise mock_test will fail
@@ -2583,8 +2585,7 @@ func TestWsOrderExecutionReport(t *testing.T) {
func TestWsOutboundAccountPosition(t *testing.T) {
t.Parallel()
payload := []byte(`{"stream":"jTfvpakT2yT0hVIo5gYWVihZhdM2PrBgJUZ5PyfZ4EVpCkx4Uoxk5timcrQc","data":{"e":"outboundAccountPosition","E":1616628815745,"u":1616628815745,"B":[{"a":"BTC","f":"0.00225109","l":"0.00123000"},{"a":"BNB","f":"0.00000000","l":"0.00000000"},{"a":"USDT","f":"54.43390661","l":"0.00000000"}]}}`)
err := b.wsHandleData(payload)
if err != nil {
if err := b.wsHandleData(payload); err != nil {
t.Fatal(err)
}
}

View File

@@ -371,7 +371,7 @@ func (b *Binance) FetchTradablePairs(ctx context.Context, a asset.Item) ([]strin
case asset.CoinMarginedFutures:
cInfo, err := b.FuturesExchangeInfo(ctx)
if err != nil {
return pairs, nil
return pairs, err
}
for z := range cInfo.Symbols {
if cInfo.Symbols[z].ContractStatus == "TRADING" {
@@ -385,7 +385,7 @@ func (b *Binance) FetchTradablePairs(ctx context.Context, a asset.Item) ([]strin
case asset.USDTMarginedFutures:
uInfo, err := b.UExchangeInfo(ctx)
if err != nil {
return pairs, nil
return pairs, err
}
for u := range uInfo.Symbols {
if uInfo.Symbols[u].Status == "TRADING" {
@@ -751,8 +751,7 @@ func (b *Binance) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (
}
acc.AssetType = assetType
info.Accounts = append(info.Accounts, acc)
err := account.Process(&info)
if err != nil {
if err := account.Process(&info); err != nil {
return account.Holdings{}, err
}
return info, nil

View File

@@ -10,6 +10,7 @@ import (
)
func TestRateLimit_Limit(t *testing.T) {
t.Parallel()
symbol := "BTC-USDT"
testTable := map[string]struct {
@@ -56,6 +57,7 @@ func TestRateLimit_Limit(t *testing.T) {
}
func TestRateLimit_LimitStatic(t *testing.T) {
t.Parallel()
testTable := map[string]request.EndpointLimit{
"Default": spotDefaultRate,
"Historical Trades": spotHistoricalTradesRate,

View File

@@ -4,8 +4,6 @@ import (
"encoding/json"
"strconv"
"time"
"github.com/thrasher-corp/gocryptotrader/common/convert"
)
// binanceTime provides an internal conversion helper
@@ -16,7 +14,7 @@ func (t *binanceTime) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &timestamp); err != nil {
return err
}
*t = binanceTime(time.Unix(0, timestamp*int64(time.Millisecond)))
*t = binanceTime(time.UnixMilli(timestamp))
return nil
}
@@ -27,7 +25,7 @@ func (t binanceTime) Time() time.Time {
// timeString gets the time as Binance timestamp
func timeString(t time.Time) string {
return strconv.FormatInt(convert.UnixMillis(t), 10)
return strconv.FormatInt(t.UnixMilli(), 10)
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
@@ -74,11 +72,8 @@ func (a *NewOrderResponse) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
// there can be an empty response, then `a` is set to nil
if aux != nil {
a.TransactionTime = aux.TransactionTime.Time()
} else {
a = nil
}
return nil
}

View File

@@ -319,16 +319,18 @@ func (b *Bitfinex) GetV2FundingInfo(ctx context.Context, key string) (MarginFund
if len(fundingData) < 4 {
return response, fmt.Errorf("%v GetV2FundingInfo: invalid length of fundingData", b.Name)
}
for x := 0; x < 3; x++ {
_, ok := fundingData[x].(float64)
if !ok {
return response, fmt.Errorf("type conversion failed for x = %d", x)
}
if response.Data.YieldLoan, ok = fundingData[0].(float64); !ok {
return response, errors.New("type conversion failed for YieldLoan")
}
if response.Data.YieldLend, ok = fundingData[1].(float64); !ok {
return response, errors.New("type conversion failed for YieldLend")
}
if response.Data.DurationLoan, ok = fundingData[2].(float64); !ok {
return response, errors.New("type conversion failed for DurationLoan")
}
if response.Data.DurationLend, ok = fundingData[3].(float64); !ok {
return response, errors.New("type conversion failed for DurationLend")
}
response.Data.YieldLoan = fundingData[0].(float64)
response.Data.YieldLend = fundingData[1].(float64)
response.Data.DurationLoan = fundingData[2].(float64)
response.Data.DurationLend = fundingData[3].(float64)
return response, nil
}
@@ -637,7 +639,10 @@ func (b *Bitfinex) GetTrades(ctx context.Context, currencyPair string, limit, ti
var history []Trade
for i := range resp {
amount := resp[i][2].(float64)
amount, ok := resp[i][2].(float64)
if !ok {
return nil, errors.New("unable to type assert amount")
}
side := order.Buy.String()
if amount < 0 {
side = order.Sell.String()
@@ -693,10 +698,21 @@ func (b *Bitfinex) GetOrderbook(ctx context.Context, symbol, precision string, l
var b Book
if len(response[x]) > 3 {
// Funding currency
b.Amount = response[x][3].(float64)
b.Rate = response[x][2].(float64)
b.Period = response[x][1].(float64)
b.OrderID = int64(response[x][0].(float64))
var ok bool
if b.Amount, ok = response[x][3].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert amount")
}
if b.Rate, ok = response[x][2].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert rate")
}
if b.Period, ok = response[x][1].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert period")
}
orderID, ok := response[x][0].(float64)
if !ok {
return Orderbook{}, errors.New("unable to type assert orderID")
}
b.OrderID = int64(orderID)
if b.Amount > 0 {
o.Asks = append(o.Asks, b)
} else {
@@ -705,9 +721,18 @@ func (b *Bitfinex) GetOrderbook(ctx context.Context, symbol, precision string, l
}
} else {
// Trading currency
b.Amount = response[x][2].(float64)
b.Price = response[x][1].(float64)
b.OrderID = int64(response[x][0].(float64))
var ok bool
if b.Amount, ok = response[x][2].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert amount")
}
if b.Price, ok = response[x][1].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert price")
}
orderID, ok := response[x][0].(float64)
if !ok {
return Orderbook{}, errors.New("unable to type assert order ID")
}
b.OrderID = int64(orderID)
if b.Amount > 0 {
o.Bids = append(o.Bids, b)
} else {
@@ -721,10 +746,21 @@ func (b *Bitfinex) GetOrderbook(ctx context.Context, symbol, precision string, l
var b Book
if len(response[x]) > 3 {
// Funding currency
b.Amount = response[x][3].(float64)
b.Count = int64(response[x][2].(float64))
b.Period = response[x][1].(float64)
b.Rate = response[x][0].(float64)
var ok bool
if b.Amount, ok = response[x][3].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert amount")
}
count, ok := response[x][2].(float64)
if !ok {
return Orderbook{}, errors.New("unable to type assert count")
}
b.Count = int64(count)
if b.Period, ok = response[x][1].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert period")
}
if b.Rate, ok = response[x][0].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert rate")
}
if b.Amount > 0 {
o.Asks = append(o.Asks, b)
} else {
@@ -733,9 +769,18 @@ func (b *Bitfinex) GetOrderbook(ctx context.Context, symbol, precision string, l
}
} else {
// Trading currency
b.Amount = response[x][2].(float64)
b.Count = int64(response[x][1].(float64))
b.Price = response[x][0].(float64)
var ok bool
if b.Amount, ok = response[x][2].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert amount")
}
count, ok := response[x][1].(float64)
if !ok {
return Orderbook{}, errors.New("unable to type assert count")
}
b.Count = int64(count)
if b.Price, ok = response[x][0].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert price")
}
if b.Amount > 0 {
o.Bids = append(o.Bids, b)
} else {
@@ -940,12 +985,34 @@ func (b *Bitfinex) GetLeaderboard(ctx context.Context, key, timeframe, symbol st
var result []LeaderboardEntry
for x := range resp {
r := resp[x].([]interface{})
r, ok := resp[x].([]interface{})
if !ok {
return nil, errors.New("unable to type assert leaderboard")
}
if len(r) < 10 {
return nil, errors.New("unexpected leaderboard data length")
}
tm, ok := r[0].(float64)
if !ok {
return nil, errors.New("unable to type assert time")
}
username, ok := r[2].(string)
if !ok {
return nil, errors.New("unable to type assert username")
}
ranking, ok := r[3].(float64)
if !ok {
return nil, errors.New("unable to type assert ranking")
}
value, ok := r[6].(float64)
if !ok {
return nil, errors.New("unable to type assert value")
}
result = append(result, LeaderboardEntry{
Timestamp: time.Unix(0, int64(r[0].(float64))*int64(time.Millisecond)),
Username: r[2].(string),
Ranking: int(r[3].(float64)),
Value: r[6].(float64),
Timestamp: time.UnixMilli(int64(tm)),
Username: username,
Ranking: int(ranking),
Value: value,
TwitterHandle: parseTwitterHandle(r[9]),
})
}

View File

@@ -1067,9 +1067,9 @@ func TestWsAuth(t *testing.T) {
}
func runAuth(t *testing.T) {
t.Helper()
setupWs()
err := b.WsSendAuth()
if err != nil {
if err := b.WsSendAuth(); err != nil {
t.Error(err)
}
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
@@ -1118,8 +1118,7 @@ func TestWsCancelOrder(t *testing.T) {
if !wsAuthExecuted {
runAuth(t)
}
err := b.WsCancelOrder(1234)
if err != nil {
if err := b.WsCancelOrder(1234); err != nil {
t.Error(err)
}
}
@@ -1150,8 +1149,7 @@ func TestWsCancelAllOrders(t *testing.T) {
if !wsAuthExecuted {
runAuth(t)
}
err := b.WsCancelAllOrders()
if err != nil {
if err := b.WsCancelAllOrders(); err != nil {
t.Error(err)
}
}
@@ -1198,8 +1196,7 @@ func TestWsCancelOffer(t *testing.T) {
if !wsAuthExecuted {
runAuth(t)
}
err := b.WsCancelOffer(1234)
if err != nil {
if err := b.WsCancelOffer(1234); err != nil {
t.Error(err)
}
}

View File

@@ -14,6 +14,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
@@ -159,7 +160,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
)
}
case "auth":
status := d["status"].(string)
status, ok := d["status"].(string)
if !ok {
return errors.New("unable to type assert status")
}
if status == "OK" {
b.Websocket.DataHandler <- d
b.WsAddSubscriptionChannel(0, "account", "N/A")
@@ -266,24 +270,27 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
switch id := obSnapBundle[0].(type) {
case []interface{}:
for i := range obSnapBundle {
data := obSnapBundle[i].([]interface{})
data, ok := obSnapBundle[i].([]interface{})
if !ok {
return errors.New("type assertion failed for orderbok item data")
}
id, okAssert := data[0].(float64)
if !okAssert {
return errors.New("type assertion failed for orderbook item data")
return errors.New("type assertion failed for orderbook id data")
}
pricePeriod, okAssert := data[1].(float64)
if !okAssert {
return errors.New("type assertion failed for orderbook item data")
return errors.New("type assertion failed for orderbook price data")
}
rateAmount, okAssert := data[2].(float64)
if !okAssert {
return errors.New("type assertion failed for orderbook item data")
return errors.New("type assertion failed for orderbook rate data")
}
if len(data) == 4 {
fundingRate = true
amount, okFunding := data[3].(float64)
if !okFunding {
return errors.New("type assertion failed for orderbook item data")
return errors.New("type assertion failed for orderbook funding data")
}
newOrderbook = append(newOrderbook, WebsocketBook{
ID: int64(id),
@@ -297,26 +304,25 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
Amount: rateAmount})
}
}
err := b.WsInsertSnapshot(pair, chanAsset, newOrderbook, fundingRate)
if err != nil {
if err = b.WsInsertSnapshot(pair, chanAsset, newOrderbook, fundingRate); err != nil {
return fmt.Errorf("inserting snapshot error: %s",
err)
}
case float64:
pricePeriod, okSnap := obSnapBundle[1].(float64)
if !okSnap {
return errors.New("type assertion failed for orderbook snapshot data")
return errors.New("type assertion failed for orderbook price snapshot data")
}
amountRate, okSnap := obSnapBundle[2].(float64)
if !okSnap {
return errors.New("type assertion failed for orderbook snapshot data")
return errors.New("type assertion failed for orderbook amount snapshot data")
}
if len(obSnapBundle) == 4 {
fundingRate = true
var amount float64
amount, okSnap = obSnapBundle[3].(float64)
if !okSnap {
return errors.New("type assertion failed for orderbook snapshot data")
return errors.New("type assertion failed for orderbook amount snapshot data")
}
newOrderbook = append(newOrderbook, WebsocketBook{
ID: int64(id),
@@ -330,8 +336,7 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
Amount: amountRate})
}
err := b.WsUpdateOrderbook(pair, chanAsset, newOrderbook, chanID, int64(sequenceNo), fundingRate)
if err != nil {
if err = b.WsUpdateOrderbook(pair, chanAsset, newOrderbook, chanID, int64(sequenceNo), fundingRate); err != nil {
return fmt.Errorf("updating orderbook error: %s",
err)
}
@@ -347,37 +352,73 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
switch candleData := candleBundle[0].(type) {
case []interface{}:
for i := range candleBundle {
element := candleBundle[i].([]interface{})
b.Websocket.DataHandler <- stream.KlineData{
Timestamp: time.Unix(0, int64(element[0].(float64))*int64(time.Millisecond)),
Exchange: b.Name,
AssetType: chanAsset,
Pair: pair,
OpenPrice: element[1].(float64),
ClosePrice: element[2].(float64),
HighPrice: element[3].(float64),
LowPrice: element[4].(float64),
Volume: element[5].(float64),
var element []interface{}
element, ok = candleBundle[i].([]interface{})
if !ok {
return errors.New("type assertion for element data")
}
if len(element) < 6 {
return errors.New("invalid candleBundle length")
}
var klineData stream.KlineData
if klineData.Timestamp, err = convert.TimeFromUnixTimestampFloat(element[0]); err != nil {
return fmt.Errorf("unable to convert timestamp: %w", err)
}
if klineData.OpenPrice, ok = element[1].(float64); !ok {
return errors.New("unable to type assert OpenPrice")
}
if klineData.ClosePrice, ok = element[2].(float64); !ok {
return errors.New("unable to type assert ClosePrice")
}
if klineData.HighPrice, ok = element[3].(float64); !ok {
return errors.New("unable to type assert HighPrice")
}
if klineData.LowPrice, ok = element[4].(float64); !ok {
return errors.New("unable to type assert LowPrice")
}
if klineData.Volume, ok = element[5].(float64); !ok {
return errors.New("unable to type assert volume")
}
klineData.Exchange = b.Name
klineData.AssetType = chanAsset
klineData.Pair = pair
b.Websocket.DataHandler <- klineData
}
case float64:
b.Websocket.DataHandler <- stream.KlineData{
Timestamp: time.Unix(0, int64(candleData)*int64(time.Millisecond)),
Exchange: b.Name,
AssetType: chanAsset,
Pair: pair,
OpenPrice: candleBundle[1].(float64),
ClosePrice: candleBundle[2].(float64),
HighPrice: candleBundle[3].(float64),
LowPrice: candleBundle[4].(float64),
Volume: candleBundle[5].(float64),
if len(candleBundle) < 6 {
return errors.New("invalid candleBundle length")
}
var klineData stream.KlineData
if klineData.Timestamp, err = convert.TimeFromUnixTimestampFloat(candleData); err != nil {
return fmt.Errorf("unable to convert timestamp: %w", err)
}
if klineData.OpenPrice, ok = candleBundle[1].(float64); !ok {
return errors.New("unable to type assert OpenPrice")
}
if klineData.ClosePrice, ok = candleBundle[2].(float64); !ok {
return errors.New("unable to type assert ClosePrice")
}
if klineData.HighPrice, ok = candleBundle[3].(float64); !ok {
return errors.New("unable to type assert HighPrice")
}
if klineData.LowPrice, ok = candleBundle[4].(float64); !ok {
return errors.New("unable to type assert LowPrice")
}
if klineData.Volume, ok = candleBundle[5].(float64); !ok {
return errors.New("unable to type assert volume")
}
klineData.Exchange = b.Name
klineData.AssetType = chanAsset
klineData.Pair = pair
b.Websocket.DataHandler <- klineData
}
}
return nil
case wsTicker:
tickerData := d[1].([]interface{})
tickerData, ok := d[1].([]interface{})
if !ok {
return errors.New("type assertion for tickerData")
}
if len(tickerData) == 10 {
b.Websocket.DataHandler <- &ticker.Price{
ExchangeName: b.Name,
@@ -421,9 +462,15 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
var tradeHolder []WebsocketTrade
switch len(d) {
case 2:
snapshot := d[1].([]interface{})
snapshot, ok := d[1].([]interface{})
if !ok {
return errors.New("unable to type assert snapshot data")
}
for i := range snapshot {
elem := snapshot[i].([]interface{})
elem, ok := snapshot[i].([]interface{})
if !ok {
return errors.New("unable to type assert snapshot element data")
}
if len(elem) == 5 {
tradeHolder = append(tradeHolder, WebsocketTrade{
ID: int64(elem[0].(float64)),
@@ -446,7 +493,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
d[1].(string) != wsTradeExecutionUpdate {
return nil
}
data := d[2].([]interface{})
data, ok := d[2].([]interface{})
if !ok {
return errors.New("data type assertion error")
}
if len(data) == 5 {
tradeHolder = append(tradeHolder, WebsocketTrade{
ID: int64(data[0].(float64)),
@@ -479,7 +529,7 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
trades = append(trades, trade.Data{
TID: strconv.FormatInt(tradeHolder[i].ID, 10),
CurrencyPair: pair,
Timestamp: time.Unix(0, tradeHolder[i].Timestamp*int64(time.Millisecond)),
Timestamp: time.UnixMilli(tradeHolder[i].Timestamp),
Price: price,
Amount: newAmount,
Exchange: b.Name,
@@ -496,9 +546,15 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
case wsHeartbeat, pong:
return nil
case wsNotification:
notification := d[2].([]interface{})
notification, ok := d[2].([]interface{})
if !ok {
return errors.New("unable to type assert notification data")
}
if data, ok := notification[4].([]interface{}); ok {
channelName := notification[1].(string)
channelName, ok := notification[1].(string)
if !ok {
return errors.New("unable to type assert channelName")
}
switch {
case strings.Contains(channelName, wsFundingOrderNewRequest),
strings.Contains(channelName, wsFundingOrderUpdateRequest),
@@ -527,18 +583,26 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
respRaw)
}
}
if notification[5] != nil &&
strings.EqualFold(notification[5].(string), wsError) {
return fmt.Errorf("%s - Error %s",
b.Name,
notification[6].(string))
if notification[5] != nil {
if wsErr, ok := notification[5].(string); ok {
if strings.EqualFold(wsErr, wsError) {
if errMsg, ok := notification[6].(string); ok {
return fmt.Errorf("%s - Error %s",
b.Name,
errMsg)
}
return fmt.Errorf("%s - unhandled error message: %v", b.Name,
notification[6])
}
}
}
case wsOrderSnapshot:
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
positionData := snapBundle[i].([]interface{})
b.wsHandleOrder(positionData)
if positionData, ok := snapBundle[i].([]interface{}); ok {
b.wsHandleOrder(positionData)
}
}
}
}
@@ -551,7 +615,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
positionData := snapBundle[i].([]interface{})
positionData, ok := snapBundle[i].([]interface{})
if !ok {
return errors.New("unable to type assert wsPositionSnapshot positionData")
}
position := WebsocketPosition{
Pair: positionData[0].(string),
Status: positionData[1].(string),
@@ -606,7 +673,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
data := snapBundle[i].([]interface{})
data, ok := snapBundle[i].([]interface{})
if !ok {
return errors.New("unable to type assert wsFundingOrderSnapshot snapBundle data")
}
offer := WsFundingOffer{
ID: int64(data[0].(float64)),
Symbol: data[1].(string),
@@ -639,7 +709,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
data := snapBundle[i].([]interface{})
data, ok := snapBundle[i].([]interface{})
if !ok {
return errors.New("unable to type assert wsFundingCreditSnapshot snapBundle data")
}
credit := WsCredit{
ID: int64(data[0].(float64)),
Symbol: data[1].(string),
@@ -695,7 +768,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
data := snapBundle[i].([]interface{})
data, ok := snapBundle[i].([]interface{})
if !ok {
return errors.New("unable to type assert wsFundingLoanSnapshot snapBundle data")
}
credit := WsCredit{
ID: int64(data[0].(float64)),
Symbol: data[1].(string),
@@ -749,10 +825,13 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
data := snapBundle[i].([]interface{})
data, ok := snapBundle[i].([]interface{})
if !ok {
return errors.New("unable to type assert wsWalletSnapshot snapBundle data")
}
var balanceAvailable float64
if _, ok := data[4].(float64); ok {
balanceAvailable = data[4].(float64)
if v, ok := data[4].(float64); ok {
balanceAvailable = v
}
wallet := WsWallet{
Type: data[0].(string),
@@ -769,8 +848,8 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
case wsWalletUpdate:
if data, ok := d[2].([]interface{}); ok && len(data) > 0 {
var balanceAvailable float64
if _, ok := data[4].(float64); ok {
balanceAvailable = data[4].(float64)
if v, ok := data[4].(float64); ok {
balanceAvailable = v
}
b.Websocket.DataHandler <- WsWallet{
Type: data[0].(string),
@@ -791,7 +870,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if data, ok := d[2].([]interface{}); ok && len(data) > 0 {
if data[0].(string) == "base" {
if infoBase, ok := d[2].([]interface{}); ok && len(infoBase) > 0 {
baseData := data[1].([]interface{})
baseData, ok := data[1].([]interface{})
if !ok {
return errors.New("unable to type assert wsMarginInfoUpdate baseData")
}
b.Websocket.DataHandler <- WsMarginInfoBase{
UserProfitLoss: baseData[0].(float64),
UserSwaps: baseData[1].(float64),
@@ -804,7 +886,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
case wsFundingInfoUpdate:
if data, ok := d[2].([]interface{}); ok && len(data) > 0 {
if data[0].(string) == "sym" {
symbolData := data[1].([]interface{})
symbolData, ok := data[1].([]interface{})
if !ok {
return errors.New("unable to type assert wsFundingInfoUpdate symbolData")
}
b.Websocket.DataHandler <- WsFundingInfo{
YieldLoan: symbolData[0].(float64),
YieldLend: symbolData[1].(float64),
@@ -839,53 +924,86 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
func (b *Bitfinex) wsHandleFundingOffer(data []interface{}) {
var fo WsFundingOffer
if data[0] != nil {
fo.ID = int64(data[0].(float64))
if id, ok := data[0].(float64); ok {
fo.ID = int64(id)
}
}
if data[1] != nil {
fo.Symbol = data[1].(string)[1:]
if sym, ok := data[1].(string); ok {
fo.Symbol = sym[1:]
}
}
if data[2] != nil {
fo.Created = int64(data[2].(float64))
if created, ok := data[2].(float64); ok {
fo.Created = int64(created)
}
}
if data[3] != nil {
fo.Updated = int64(data[0].(float64))
if updated, ok := data[3].(float64); ok {
fo.Updated = int64(updated)
}
}
if data[15] != nil {
fo.Period = int64(data[15].(float64))
if period, ok := data[15].(float64); ok {
fo.Period = int64(period)
}
}
if data[4] != nil {
fo.Amount = data[4].(float64)
if amount, ok := data[4].(float64); ok {
fo.Amount = amount
}
}
if data[5] != nil {
fo.OriginalAmount = data[5].(float64)
if origAmount, ok := data[5].(float64); ok {
fo.OriginalAmount = origAmount
}
}
if data[6] != nil {
fo.Type = data[6].(string)
if fType, ok := data[6].(string); ok {
fo.Type = fType
}
}
if data[9] != nil {
fo.Flags = data[9].(float64)
if flags, ok := data[9].(float64); ok {
fo.Flags = flags
}
}
if data[9] != nil {
fo.Status = data[10].(string)
if data[9] != nil && data[10] != nil {
if status, ok := data[10].(string); ok {
fo.Status = status
}
}
if data[9] != nil {
fo.Rate = data[14].(float64)
if data[9] != nil && data[14] != nil {
if rate, ok := data[14].(float64); ok {
fo.Rate = rate
}
}
if data[16] != nil {
fo.Notify = data[16].(float64) == 1
if notify, ok := data[16].(float64); ok {
fo.Notify = notify == 1
}
}
if data[17] != nil {
fo.Hidden = data[17].(float64) == 1
if hidden, ok := data[17].(float64); ok {
fo.Hidden = hidden == 1
}
}
if data[18] != nil {
fo.Insure = data[18].(float64) == 1
if insure, ok := data[18].(float64); ok {
fo.Insure = insure == 1
}
}
if data[19] != nil {
fo.Renew = data[19].(float64) == 1
if renew, ok := data[19].(float64); ok {
fo.Renew = renew == 1
}
}
if data[20] != nil {
fo.RateReal = data[20].(float64)
if rateReal, ok := data[20].(float64); ok {
fo.RateReal = rateReal
}
}
b.Websocket.DataHandler <- fo
@@ -896,54 +1014,74 @@ func (b *Bitfinex) wsHandleOrder(data []interface{}) {
var err error
od.Exchange = b.Name
if data[0] != nil {
od.ID = strconv.FormatFloat(data[0].(float64), 'f', -1, 64)
if id, ok := data[0].(float64); ok {
od.ID = strconv.FormatFloat(id, 'f', -1, 64)
}
}
if data[16] != nil {
od.Price = data[16].(float64)
if price, ok := data[16].(float64); ok {
od.Price = price
}
}
if data[7] != nil {
od.Amount = data[7].(float64)
if amount, ok := data[7].(float64); ok {
od.Amount = amount
}
}
if data[6] != nil {
od.RemainingAmount = data[6].(float64)
if remainingAmount, ok := data[6].(float64); ok {
od.RemainingAmount = remainingAmount
}
}
if data[7] != nil && data[6] != nil {
od.ExecutedAmount = data[7].(float64) - data[6].(float64)
if executedAmount, ok := data[7].(float64); ok {
od.ExecutedAmount = executedAmount - od.RemainingAmount
}
}
if data[4] != nil {
od.Date = time.Unix(int64(data[4].(float64))*1000, 0)
if date, ok := data[4].(float64); ok {
od.Date = time.Unix(int64(date)*1000, 0)
}
}
if data[5] != nil {
od.LastUpdated = time.Unix(int64(data[5].(float64))*1000, 0)
if lastUpdated, ok := data[5].(float64); ok {
od.LastUpdated = time.Unix(int64(lastUpdated)*1000, 0)
}
}
if data[2] != nil {
od.Pair, od.AssetType, err = b.GetRequestFormattedPairAndAssetType(data[3].(string)[1:])
if err != nil {
b.Websocket.DataHandler <- err
return
if p, ok := data[3].(string); ok {
od.Pair, od.AssetType, err = b.GetRequestFormattedPairAndAssetType(p[1:])
if err != nil {
b.Websocket.DataHandler <- err
return
}
}
}
if data[8] != nil {
oType, err := order.StringToOrderType(data[8].(string))
if err != nil {
b.Websocket.DataHandler <- order.ClassificationError{
Exchange: b.Name,
OrderID: od.ID,
Err: err,
if ordType, ok := data[8].(string); ok {
oType, err := order.StringToOrderType(ordType)
if err != nil {
b.Websocket.DataHandler <- order.ClassificationError{
Exchange: b.Name,
OrderID: od.ID,
Err: err,
}
}
od.Type = oType
}
od.Type = oType
}
if data[13] != nil {
oStatus, err := order.StringToOrderStatus(data[13].(string))
if err != nil {
b.Websocket.DataHandler <- order.ClassificationError{
Exchange: b.Name,
OrderID: od.ID,
Err: err,
if ordStatus, ok := data[13].(string); ok {
oStatus, err := order.StringToOrderStatus(ordStatus)
if err != nil {
b.Websocket.DataHandler <- order.ClassificationError{
Exchange: b.Name,
OrderID: od.ID,
Err: err,
}
}
od.Status = oStatus
}
od.Status = oStatus
}
b.Websocket.DataHandler <- &od
}
@@ -1242,19 +1380,45 @@ func (b *Bitfinex) WsNewOrder(data *WsNewOrderRequest) (string, error) {
if err != nil {
return "", err
}
responseDataDetail := respData[2].([]interface{})
responseOrderDetail := responseDataDetail[4].([]interface{})
var orderID string
if responseOrderDetail[0] != nil && responseOrderDetail[0].(float64) > 0 {
orderID = strconv.FormatFloat(responseOrderDetail[0].(float64), 'f', -1, 64)
}
errCode := responseDataDetail[6].(string)
errorMessage := responseDataDetail[7].(string)
if len(respData) < 3 {
return "", errors.New("unexpected respData length")
}
responseDataDetail, ok := respData[2].([]interface{})
if !ok {
return "", errors.New("unable to type assert respData")
}
if len(responseDataDetail) < 4 {
return "", errors.New("invalid responseDataDetail length")
}
responseOrderDetail, ok := responseDataDetail[4].([]interface{})
if !ok {
return "", errors.New("unable to type assert responseOrderDetail")
}
var orderID string
if responseOrderDetail[0] != nil {
if ordID, ordOK := responseOrderDetail[0].(float64); ordOK && ordID > 0 {
orderID = strconv.FormatFloat(ordID, 'f', -1, 64)
}
}
var errorMessage, errCode string
if len(responseDataDetail) > 6 {
errCode, ok = responseDataDetail[6].(string)
if !ok {
return "", errors.New("unable to type assert errCode")
}
}
if len(responseDataDetail) > 7 {
errorMessage, ok = responseDataDetail[7].(string)
if !ok {
return "", errors.New("unable to type assert errorMessage")
}
}
if strings.EqualFold(errCode, wsError) {
return orderID, errors.New(b.Name + " - " + errCode + ": " + errorMessage)
}
return orderID, nil
}
@@ -1274,13 +1438,29 @@ func (b *Bitfinex) WsModifyOrder(data *WsUpdateOrderRequest) error {
if err != nil {
return err
}
responseOrderData := responseData[2].([]interface{})
errCode := responseOrderData[6].(string)
errorMessage := responseOrderData[7].(string)
if len(responseData) < 3 {
return errors.New("unexpected responseData length")
}
responseOrderData, ok := responseData[2].([]interface{})
if !ok {
return errors.New("unable to type assert responseOrderData")
}
var errorMessage, errCode string
if len(responseOrderData) > 6 {
errCode, ok = responseOrderData[6].(string)
if !ok {
return errors.New("unable to type assert errCode")
}
}
if len(responseOrderData) > 7 {
errorMessage, ok = responseOrderData[7].(string)
if !ok {
return errors.New("unable to type assert errorMessage")
}
}
if strings.EqualFold(errCode, wsError) {
return errors.New(b.Name + " - " + errCode + ": " + errorMessage)
}
return nil
}
@@ -1311,13 +1491,29 @@ func (b *Bitfinex) WsCancelOrder(orderID int64) error {
if err != nil {
return err
}
responseOrderData := responseData[2].([]interface{})
errCode := responseOrderData[6].(string)
errorMessage := responseOrderData[7].(string)
if len(responseData) < 3 {
return errors.New("unexpected responseData length")
}
responseOrderData, ok := responseData[2].([]interface{})
if !ok {
return errors.New("unable to type assert responseOrderData")
}
var errorMessage, errCode string
if len(responseOrderData) > 6 {
errCode, ok = responseOrderData[6].(string)
if !ok {
return errors.New("unable to type assert errCode")
}
}
if len(responseOrderData) > 7 {
errorMessage, ok = responseOrderData[7].(string)
if !ok {
return errors.New("unable to type assert errorMessage")
}
}
if strings.EqualFold(errCode, wsError) {
return errors.New(b.Name + " - " + errCode + ": " + errorMessage)
}
return nil
}
@@ -1352,11 +1548,25 @@ func (b *Bitfinex) WsCancelOffer(orderID int64) error {
if err != nil {
return err
}
responseOrderData := responseData[2].([]interface{})
errCode := responseOrderData[6].(string)
var errorMessage string
if responseOrderData[7] != nil {
errorMessage = responseOrderData[7].(string)
if len(responseData) < 3 {
return errors.New("unexpected responseData length")
}
responseOrderData, ok := responseData[2].([]interface{})
if !ok {
return errors.New("unable to type assert responseOrderData")
}
var errorMessage, errCode string
if len(responseOrderData) > 6 {
errCode, ok = responseOrderData[6].(string)
if !ok {
return errors.New("unable to type assert errCode")
}
}
if len(responseOrderData) > 7 {
errorMessage, ok = responseOrderData[7].(string)
if !ok {
return errors.New("unable to type assert errorMessage")
}
}
if strings.EqualFold(errCode, wsError) {
return errors.New(b.Name + " - " + errCode + ": " + errorMessage)

View File

@@ -365,8 +365,7 @@ func (b *Bitfinex) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bitfinex) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := b.UpdateTickers(ctx, a)
if err != nil {
if err := b.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(b.Name, p, a)
@@ -567,7 +566,7 @@ allTrades:
return nil, err
}
for i := range tradeData {
tradeTS := time.Unix(0, tradeData[i].Timestamp*int64(time.Millisecond))
tradeTS := time.UnixMilli(tradeData[i].Timestamp)
if tradeTS.Before(timestampStart) && !timestampStart.IsZero() {
break allTrades
}
@@ -579,7 +578,7 @@ allTrades:
AssetType: assetType,
Price: tradeData[i].Price,
Amount: tradeData[i].Amount,
Timestamp: time.Unix(0, tradeData[i].Timestamp*int64(time.Millisecond)),
Timestamp: time.UnixMilli(tradeData[i].Timestamp),
})
if i == len(tradeData)-1 {
if ts.Equal(tradeTS) {

View File

@@ -236,7 +236,11 @@ func (b *Bithumb) GetAccountBalance(ctx context.Context, c string) (FullBalance,
return fullBalance, err
}
} else {
val = datum.(float64)
var ok bool
val, ok = datum.(float64)
if !ok {
return fullBalance, errors.New("unable to type assert datum")
}
}
switch splitTag[0] {
@@ -529,7 +533,7 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.
var intermediary json.RawMessage
err = b.SendPayload(ctx, request.Auth, func() (*request.Item, error) {
// This is time window sensitive
tnMS := time.Now().UnixNano() / int64(time.Millisecond)
tnMS := time.Now().UnixMilli()
n := strconv.FormatInt(tnMS, 10)
params.Set("endpoint", path)

View File

@@ -291,8 +291,7 @@ func (b *Bithumb) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bithumb) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := b.UpdateTickers(ctx, a)
if err != nil {
if err := b.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(b.Name, p, a)
@@ -818,60 +817,33 @@ func (b *Bithumb) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
}
for x := range candle.Data {
if len(candle.Data[x]) < 6 {
return kline.Item{}, errors.New("invalid candle length")
}
var tempCandle kline.Candle
tempTime := candle.Data[x][0].(float64)
timestamp := time.Unix(0, int64(tempTime)*int64(time.Millisecond))
if timestamp.Before(start) {
if tempCandle.Time, err = convert.TimeFromUnixTimestampFloat(candle.Data[x][0]); err != nil {
return kline.Item{}, fmt.Errorf("unable to convert timestamp: %w", err)
}
if tempCandle.Time.Before(start) {
continue
}
if timestamp.After(end) {
if tempCandle.Time.After(end) {
break
}
tempCandle.Time = timestamp
open, ok := candle.Data[x][1].(string)
if !ok {
return kline.Item{}, errors.New("open conversion failed")
if tempCandle.Open, err = convert.FloatFromString(candle.Data[x][1]); err != nil {
return kline.Item{}, fmt.Errorf("kline open conversion failed: %w", err)
}
tempCandle.Open, err = strconv.ParseFloat(open, 64)
if err != nil {
return kline.Item{}, err
if tempCandle.High, err = convert.FloatFromString(candle.Data[x][2]); err != nil {
return kline.Item{}, fmt.Errorf("kline high conversion failed: %w", err)
}
high, ok := candle.Data[x][2].(string)
if !ok {
return kline.Item{}, errors.New("high conversion failed")
if tempCandle.Low, err = convert.FloatFromString(candle.Data[x][3]); err != nil {
return kline.Item{}, fmt.Errorf("kline low conversion failed: %w", err)
}
tempCandle.High, err = strconv.ParseFloat(high, 64)
if err != nil {
return kline.Item{}, err
if tempCandle.Close, err = convert.FloatFromString(candle.Data[x][4]); err != nil {
return kline.Item{}, fmt.Errorf("kline close conversion failed: %w", err)
}
low, ok := candle.Data[x][3].(string)
if !ok {
return kline.Item{}, errors.New("low conversion failed")
}
tempCandle.Low, err = strconv.ParseFloat(low, 64)
if err != nil {
return kline.Item{}, err
}
closeTemp, ok := candle.Data[x][4].(string)
if !ok {
return kline.Item{}, errors.New("close conversion failed")
}
tempCandle.Close, err = strconv.ParseFloat(closeTemp, 64)
if err != nil {
return kline.Item{}, err
}
vol, ok := candle.Data[x][5].(string)
if !ok {
return kline.Item{}, errors.New("vol conversion failed")
}
tempCandle.Volume, err = strconv.ParseFloat(vol, 64)
if err != nil {
return kline.Item{}, err
if tempCandle.Volume, err = convert.FloatFromString(candle.Data[x][5]); err != nil {
return kline.Item{}, fmt.Errorf("kline volume conversion failed: %w", err)
}
ret.Candles = append(ret.Candles, tempCandle)
}

View File

@@ -442,7 +442,7 @@ func (b *Bithumb) SeedLocalCacheWithBook(p currency.Pair, o *Orderbook) error {
newOrderBook.Pair = p
newOrderBook.Asset = asset.Spot
newOrderBook.Exchange = b.Name
newOrderBook.LastUpdated = time.Unix(0, o.Data.Timestamp*int64(time.Millisecond))
newOrderBook.LastUpdated = time.UnixMilli(o.Data.Timestamp)
newOrderBook.VerifyOrderbook = b.CanVerifyOrderbook
return b.Websocket.Orderbook.LoadSnapshot(&newOrderBook)
}

View File

@@ -20,7 +20,7 @@ func TestBithumbTime(t *testing.T) {
tt := newTime.Time()
if tt.UTC().String() != "2021-08-12 03:39:50 +0000 UTC" {
t.Fatalf("expected: %s but receieved: %s",
t.Fatalf("expected: %s but received: %s",
"2021-08-12 03:39:50 +0000 UTC",
tt.UTC().String())
}

View File

@@ -320,8 +320,7 @@ func (b *Bitmex) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bitmex) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := b.UpdateTickers(ctx, a)
if err != nil {
if err := b.UpdateTickers(ctx, a); err != nil {
return nil, err
}

View File

@@ -370,7 +370,7 @@ func (b *Bittrex) SendAuthHTTPRequest(ctx context.Context, ep exchange.URL, meth
}
newRequest := func() (*request.Item, error) {
ts := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
ts := strconv.FormatInt(time.Now().UnixMilli(), 10)
path := common.EncodeURLValues(action, params)
var body io.Reader

View File

@@ -568,6 +568,7 @@ func TestModifyOrder(t *testing.T) {
}
func WithdrawCryptocurrencyFunds(t *testing.T) {
t.Helper()
withdrawCryptoRequest := withdraw.Request{
Amount: -1,
Currency: currency.BTC,

View File

@@ -156,7 +156,7 @@ func (b *Bittrex) WsAuth() error {
if err != nil {
return err
}
timestamp := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10)
hmac, err := crypto.GetHMAC(
crypto.HashSHA512,
[]byte(timestamp+randomContent.String()),

View File

@@ -950,8 +950,8 @@ func (b *Bittrex) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
year, month, day := start.Date()
curYear, curMonth, curDay := time.Now().Date()
getHistoric := false
getRecent := false
getHistoric := false // nolint:ifshort,nolintlint // false positive and triggers only on Windows
getRecent := false // nolint:ifshort,nolintlint // false positive and triggers only on Windows
switch interval {
case kline.OneMin, kline.FiveMin:

View File

@@ -704,7 +704,7 @@ func (b *BTCMarkets) SendAuthenticatedRequest(ctx context.Context, method, path
newRequest := func() (*request.Item, error) {
now := time.Now()
strTime := strconv.FormatInt(now.UTC().UnixNano()/1000000, 10)
strTime := strconv.FormatInt(now.UTC().UnixMilli(), 10)
var body io.Reader
var payload, hmac []byte

View File

@@ -343,7 +343,7 @@ func (b *BTCMarkets) Subscribe(channelsToSubscribe []stream.ChannelSubscription)
if !common.StringDataCompare(payload.Channels, authChannels[i]) {
continue
}
signTime := strconv.FormatInt(time.Now().UTC().UnixNano()/1000000, 10)
signTime := strconv.FormatInt(time.Now().UTC().UnixMilli(), 10)
strToSign := "/users/self/subscribe" + "\n" + signTime
tempSign, err := crypto.GetHMAC(crypto.HashSHA512,
[]byte(strToSign),

Some files were not shown because too many files have changed in this diff Show More