CI: Fix golangci-lint linter issues, add prealloc linter and bump version depends for Go 1.18 (#915)

* Bump CI versions

* Specifically set go version as 1.17.x bumps it to 1.18

* Another

* Adjust AppVeyor

* Part 1 of linter issues

* Part 2

* Fix various linters and improvements

* Part 3

* Finishing touches

* Tests and EqualFold

* Fix nitterinos plus bonus requester jobs bump for exchanges with large number of tests

* Fix nitterinos and bump golangci-lint timeout for AppVeyor

* Address nits, ensure all books are returned on err due to syncer regression

* Fix the wiggins

* Fix duplication

* Fix nitterinos
This commit is contained in:
Adrian Gallagher
2022-04-20 13:45:15 +10:00
committed by GitHub
parent c48e5ea90a
commit 9a4eb9de84
216 changed files with 3493 additions and 2424 deletions

View File

@@ -28,13 +28,15 @@ environment:
PSQL_SSLMODE: disable
PSQL_SKIPSQLCMD: true
PSQL_TESTDBNAME: gct_dev_ci
stack: go 1.17.x
stack: go 1.17.8 # this is not actually used on Windows images
services:
- postgresql96
init:
- SET PATH=%POSTGRES_PATH%\bin;%PATH%
- set PATH=%POSTGRES_PATH%\bin;%PATH%
- set PATH=C:\go118\bin;%PATH%
install:
- set Path=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%Path%
@@ -53,7 +55,7 @@ before_test:
test_script:
# test back-end
- go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.42.1
- go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.45.2
- '%GOPATH%\bin\golangci-lint.exe run --verbose'
- ps: >-
if($env:APPVEYOR_SCHEDULED_BUILD -eq 'true') {

View File

@@ -1,10 +1,13 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: gomod
directory: "/"
schedule:
interval: daily
time: "19:30"
interval: "weekly"
open-pull-requests-limit: 10
- package-ecosystem: npm
directory: "/web"
@@ -12,4 +15,3 @@ updates:
interval: "weekly"
# deprecated for now as it requires a more in-depth overhaul
open-pull-requests-limit: 0

View File

@@ -5,8 +5,11 @@ jobs:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
version: v1.42.1
go-version: '1.18.x'
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.45.2

View File

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

View File

@@ -1,11 +1,12 @@
run:
timeout: 6m
timeout: 8m
issues-exit-code: 1
tests: true
skip-dirs:
- vendor
- web/
- testdata
- database/models/
linters:
disable-all: true
@@ -24,12 +25,17 @@ linters:
# disabled by default linters
- asciicheck
- bidichk
- bodyclose
- containedctx
# - contextcheck
# - cyclop
- decorder
- depguard
- dogsled
# - dupl
- durationcheck
- errchkjson
- errname
# - errorlint
# - exhaustive
@@ -58,10 +64,13 @@ linters:
- gomodguard
- goprintffuncname
- gosec
- grouper
- ifshort
# - importas
# - interfacer // deprecated by its owner
# - ireturn
# - lll
# - maintidx
- makezero
# - maligned
- misspell
@@ -72,7 +81,7 @@ linters:
- noctx
- nolintlint
# - paralleltest
# - prealloc
- prealloc
- predeclared
# - promlinter
- revive

View File

@@ -1,4 +1,4 @@
FROM golang:1.17 as build
FROM golang:1.18 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.42.1
LINTPKG = github.com/golangci/golangci-lint/cmd/golangci-lint@v1.45.2
LINTBIN = $(GOPATH)/bin/golangci-lint
GCTLISTENPORT=9050
GCTPROFILERLISTENPORT=8085

View File

@@ -648,7 +648,7 @@ func (bt *BackTest) loadData(cfg *config.Config, exch gctexchange.IBotExchange,
if cfg.DataSettings.DatabaseData.Path == "" {
cfg.DataSettings.DatabaseData.Path = filepath.Join(gctcommon.GetDefaultDataDir(runtime.GOOS), "database")
}
gctdatabase.DB.DataPath = filepath.Join(cfg.DataSettings.DatabaseData.Path)
gctdatabase.DB.DataPath = cfg.DataSettings.DatabaseData.Path
err = gctdatabase.DB.SetConfig(&cfg.DataSettings.DatabaseData.Config)
if err != nil {
return nil, err

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/shopspring/decimal"
@@ -21,7 +21,7 @@ func ReadConfigFromFile(path string) (*Config, error) {
return nil, errors.New("file not found")
}
fileData, err := ioutil.ReadFile(path)
fileData, err := os.ReadFile(path)
if err != nil {
return nil, err
}

View File

@@ -13,6 +13,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/backtester/common"
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/strategies/base"
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/strategies/top2bottom2"
"github.com/thrasher-corp/gocryptotrader/common/file"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/database"
"github.com/thrasher-corp/gocryptotrader/database/drivers"
@@ -210,7 +211,7 @@ func TestGenerateConfigForDCAAPICandles(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(filepath.Join(p, "examples", "dca-api-candles.strat"), result, 0770)
err = os.WriteFile(filepath.Join(p, "examples", "dca-api-candles.strat"), result, file.DefaultPermissionOctal)
if err != nil {
t.Error(err)
}
@@ -288,7 +289,7 @@ func TestGenerateConfigForDCAAPICandlesExchangeLevelFunding(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(filepath.Join(p, "examples", "dca-api-candles-exchange-level-funding.strat"), result, 0770)
err = os.WriteFile(filepath.Join(p, "examples", "dca-api-candles-exchange-level-funding.strat"), result, file.DefaultPermissionOctal)
if err != nil {
t.Error(err)
}
@@ -356,7 +357,7 @@ func TestGenerateConfigForDCAAPITrades(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(filepath.Join(p, "examples", "dca-api-trades.strat"), result, 0770)
err = os.WriteFile(filepath.Join(p, "examples", "dca-api-trades.strat"), result, file.DefaultPermissionOctal)
if err != nil {
t.Error(err)
}
@@ -429,7 +430,7 @@ func TestGenerateConfigForDCAAPICandlesMultipleCurrencies(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(filepath.Join(p, "examples", "dca-api-candles-multiple-currencies.strat"), result, 0770)
err = os.WriteFile(filepath.Join(p, "examples", "dca-api-candles-multiple-currencies.strat"), result, file.DefaultPermissionOctal)
if err != nil {
t.Error(err)
}
@@ -503,7 +504,7 @@ func TestGenerateConfigForDCAAPICandlesSimultaneousProcessing(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(filepath.Join(p, "examples", "dca-api-candles-simultaneous-processing.strat"), result, 0770)
err = os.WriteFile(filepath.Join(p, "examples", "dca-api-candles-simultaneous-processing.strat"), result, file.DefaultPermissionOctal)
if err != nil {
t.Error(err)
}
@@ -566,7 +567,7 @@ func TestGenerateConfigForDCALiveCandles(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(filepath.Join(p, "examples", "dca-candles-live.strat"), result, 0770)
err = os.WriteFile(filepath.Join(p, "examples", "dca-candles-live.strat"), result, file.DefaultPermissionOctal)
if err != nil {
t.Error(err)
}
@@ -645,7 +646,7 @@ func TestGenerateConfigForRSIAPICustomSettings(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(filepath.Join(p, "examples", "rsi-api-candles.strat"), result, 0770)
err = os.WriteFile(filepath.Join(p, "examples", "rsi-api-candles.strat"), result, file.DefaultPermissionOctal)
if err != nil {
t.Error(err)
}
@@ -704,7 +705,7 @@ func TestGenerateConfigForDCACSVCandles(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(filepath.Join(p, "examples", "dca-csv-candles.strat"), result, 0770)
err = os.WriteFile(filepath.Join(p, "examples", "dca-csv-candles.strat"), result, file.DefaultPermissionOctal)
if err != nil {
t.Error(err)
}
@@ -759,7 +760,7 @@ func TestGenerateConfigForDCACSVTrades(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(filepath.Join(p, "examples", "dca-csv-trades.strat"), result, 0770)
err = os.WriteFile(filepath.Join(p, "examples", "dca-csv-trades.strat"), result, file.DefaultPermissionOctal)
if err != nil {
t.Error(err)
}
@@ -827,7 +828,7 @@ func TestGenerateConfigForDCADatabaseCandles(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(filepath.Join(p, "examples", "dca-database-candles.strat"), result, 0770)
err = os.WriteFile(filepath.Join(p, "examples", "dca-database-candles.strat"), result, file.DefaultPermissionOctal)
if err != nil {
t.Error(err)
}
@@ -956,7 +957,7 @@ func TestGenerateConfigForTop2Bottom2(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(filepath.Join(p, "examples", "t2b2-api-candles-exchange-funding.strat"), result, 0770)
err = os.WriteFile(filepath.Join(p, "examples", "t2b2-api-candles-exchange-funding.strat"), result, file.DefaultPermissionOctal)
if err != nil {
t.Error(err)
}

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
@@ -19,6 +18,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/backtester/config"
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/strategies"
gctcommon "github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/file"
"github.com/thrasher-corp/gocryptotrader/database"
dbPSQL "github.com/thrasher-corp/gocryptotrader/database/drivers/postgres"
dbsqlite3 "github.com/thrasher-corp/gocryptotrader/database/drivers/sqlite3"
@@ -141,7 +141,7 @@ func main() {
if path == "" {
path = wd
}
err = ioutil.WriteFile(path, resp, 0770)
err = os.WriteFile(path, resp, file.DefaultPermissionOctal)
if err != nil {
log.Fatal(err)
}
@@ -235,10 +235,10 @@ func parseExchangeSettings(reader *bufio.Reader, cfg *config.Config) error {
func parseStrategySettings(cfg *config.Config, reader *bufio.Reader) error {
fmt.Println("Firstly, please select which strategy you wish to use")
strats := strategies.GetStrategies()
var strategiesToUse []string
strategiesToUse := make([]string, len(strats))
for i := range strats {
fmt.Printf("%v. %s\n", i+1, strats[i].Name())
strategiesToUse = append(strategiesToUse, strats[i].Name())
strategiesToUse[i] = strats[i].Name()
}
var err error
cfg.StrategySettings.Name, err = parseStratName(quickParse(reader), strategiesToUse)

View File

@@ -58,7 +58,7 @@ func (d *DataFromKline) AppendResults(ki *gctkline.Item) {
if d.addedTimes == nil {
d.addedTimes = make(map[time.Time]bool)
}
var klineData []common.DataEventHandler
var gctCandles []gctkline.Candle
for i := range ki.Candles {
if _, ok := d.addedTimes[ki.Candles[i].Time]; !ok {
@@ -66,10 +66,11 @@ func (d *DataFromKline) AppendResults(ki *gctkline.Item) {
d.addedTimes[ki.Candles[i].Time] = true
}
}
var candleTimes []time.Time
klineData := make([]common.DataEventHandler, len(gctCandles))
candleTimes := make([]time.Time, len(gctCandles))
for i := range gctCandles {
klineData = append(klineData, &kline.Kline{
klineData[i] = &kline.Kline{
Base: event.Base{
Offset: int64(i + 1),
Exchange: ki.Exchange,
@@ -84,8 +85,8 @@ func (d *DataFromKline) AppendResults(ki *gctkline.Item) {
Close: decimal.NewFromFloat(gctCandles[i].Close),
Volume: decimal.NewFromFloat(gctCandles[i].Volume),
ValidationIssues: gctCandles[i].ValidationIssues,
})
candleTimes = append(candleTimes, gctCandles[i].Time)
}
candleTimes[i] = gctCandles[i].Time
}
for i := range d.RangeHolder.Ranges {
for j := range d.RangeHolder.Ranges[i].Intervals {

View File

@@ -135,8 +135,7 @@ func TestStreamOpen(t *testing.T) {
a := asset.Spot
p := currency.NewPair(currency.BTC, currency.USDT)
d := DataFromKline{}
bad := d.StreamOpen()
if len(bad) > 0 {
if bad := d.StreamOpen(); len(bad) > 0 {
t.Error("expected no stream")
}
d.SetStream([]common.DataEventHandler{
@@ -156,8 +155,7 @@ func TestStreamOpen(t *testing.T) {
},
})
d.Next()
open := d.StreamOpen()
if len(open) == 0 {
if open := d.StreamOpen(); len(open) == 0 {
t.Error("expected open")
}
}
@@ -168,8 +166,7 @@ func TestStreamVolume(t *testing.T) {
a := asset.Spot
p := currency.NewPair(currency.BTC, currency.USDT)
d := DataFromKline{}
bad := d.StreamVol()
if len(bad) > 0 {
if bad := d.StreamVol(); len(bad) > 0 {
t.Error("expected no stream")
}
d.SetStream([]common.DataEventHandler{
@@ -189,8 +186,7 @@ func TestStreamVolume(t *testing.T) {
},
})
d.Next()
open := d.StreamVol()
if len(open) == 0 {
if open := d.StreamVol(); len(open) == 0 {
t.Error("expected volume")
}
}
@@ -201,8 +197,7 @@ func TestStreamClose(t *testing.T) {
a := asset.Spot
p := currency.NewPair(currency.BTC, currency.USDT)
d := DataFromKline{}
bad := d.StreamClose()
if len(bad) > 0 {
if bad := d.StreamClose(); len(bad) > 0 {
t.Error("expected no stream")
}
d.SetStream([]common.DataEventHandler{
@@ -222,8 +217,7 @@ func TestStreamClose(t *testing.T) {
},
})
d.Next()
open := d.StreamClose()
if len(open) == 0 {
if open := d.StreamClose(); len(open) == 0 {
t.Error("expected close")
}
}
@@ -234,8 +228,7 @@ func TestStreamHigh(t *testing.T) {
a := asset.Spot
p := currency.NewPair(currency.BTC, currency.USDT)
d := DataFromKline{}
bad := d.StreamHigh()
if len(bad) > 0 {
if bad := d.StreamHigh(); len(bad) > 0 {
t.Error("expected no stream")
}
d.SetStream([]common.DataEventHandler{
@@ -255,8 +248,7 @@ func TestStreamHigh(t *testing.T) {
},
})
d.Next()
open := d.StreamHigh()
if len(open) == 0 {
if open := d.StreamHigh(); len(open) == 0 {
t.Error("expected high")
}
}
@@ -269,8 +261,7 @@ func TestStreamLow(t *testing.T) {
d := DataFromKline{
RangeHolder: &gctkline.IntervalRangeHolder{},
}
bad := d.StreamLow()
if len(bad) > 0 {
if bad := d.StreamLow(); len(bad) > 0 {
t.Error("expected no stream")
}
d.SetStream([]common.DataEventHandler{
@@ -290,8 +281,7 @@ func TestStreamLow(t *testing.T) {
},
})
d.Next()
open := d.StreamLow()
if len(open) == 0 {
if open := d.StreamLow(); len(open) == 0 {
t.Error("expected low")
}
}

View File

@@ -229,12 +229,11 @@ func (e *Exchange) placeOrder(ctx context.Context, price, amount decimal.Decimal
return "", err
}
var orderID string
p, _ := price.Float64()
a, _ := amount.Float64()
fee, _ := f.ExchangeFee.Float64()
p := price.InexactFloat64()
fee := f.ExchangeFee.InexactFloat64()
o := &gctorder.Submit{
Price: p,
Amount: a,
Amount: amount.InexactFloat64(),
Fee: fee,
Exchange: f.Exchange,
ID: u.String(),
@@ -255,11 +254,10 @@ func (e *Exchange) placeOrder(ctx context.Context, price, amount decimal.Decimal
return orderID, err
}
} else {
rate, _ := f.Amount.Float64()
submitResponse := gctorder.SubmitResponse{
IsOrderPlaced: true,
OrderID: u.String(),
Rate: rate,
Rate: f.Amount.InexactFloat64(),
Fee: fee,
Cost: p,
FullyMatched: true,

View File

@@ -32,11 +32,9 @@ func EstimateSlippagePercentage(maximumSlippageRate, minimumSlippageRate decimal
// CalculateSlippageByOrderbook will analyse a provided orderbook and return the result of attempting to
// place the order on there
func CalculateSlippageByOrderbook(ob *orderbook.Base, side gctorder.Side, amountOfFunds, feeRate decimal.Decimal) (price, amount decimal.Decimal) {
funds, _ := amountOfFunds.Float64()
fee, _ := feeRate.Float64()
result := ob.SimulateOrder(funds, side == gctorder.Buy)
result := ob.SimulateOrder(amountOfFunds.InexactFloat64(), side == gctorder.Buy)
rate := (result.MinimumPrice - result.MaximumPrice) / result.MaximumPrice
price = decimal.NewFromFloat(result.MinimumPrice * (rate + 1))
amount = decimal.NewFromFloat(result.Amount * (1 - fee))
amount = decimal.NewFromFloat(result.Amount * (1 - feeRate.InexactFloat64()))
return
}

View File

@@ -55,10 +55,10 @@ func (c *CurrencyPairStatistic) CalculateResults(riskFreeRate decimal.Decimal) e
returnsPerCandle := make([]decimal.Decimal, len(c.Events))
benchmarkRates := make([]decimal.Decimal, len(c.Events))
var allDataEvents []common.DataEventHandler
allDataEvents := make([]common.DataEventHandler, len(c.Events))
for i := range c.Events {
returnsPerCandle[i] = c.Events[i].Holdings.ChangeInTotalValuePercent
allDataEvents = append(allDataEvents, c.Events[i].DataEvent)
allDataEvents[i] = c.Events[i].DataEvent
if i == 0 {
continue
}

View File

@@ -159,7 +159,7 @@ func (s *Strategy) SetDefaults() {
// the decision to handle missing data occurs at the strategy level, not all strategies
// may wish to modify data
func (s *Strategy) massageMissingData(data []decimal.Decimal, t time.Time) ([]float64, error) {
var resp []float64
resp := make([]float64, len(data))
var missingDataStreak int64
for i := range data {
if data[i].IsZero() && i > int(s.rsiPeriod.IntPart()) {
@@ -174,8 +174,7 @@ func (s *Strategy) massageMissingData(data []decimal.Decimal, t time.Time) ([]fl
t.Format(gctcommon.SimpleTimeFormat),
base.ErrTooMuchBadData)
}
d, _ := data[i].Float64()
resp = append(resp, d)
resp[i] = data[i].InexactFloat64()
}
return resp, nil
}

View File

@@ -11,8 +11,7 @@ import (
func TestGetStrategies(t *testing.T) {
t.Parallel()
resp := GetStrategies()
if len(resp) < 2 {
if resp := GetStrategies(); len(resp) < 2 {
t.Error("expected at least 2 strategies to be loaded")
}
}

View File

@@ -92,7 +92,7 @@ func (s *Strategy) OnSimultaneousSignals(d []data.Handler, f funding.IFundTransf
if len(d) < 4 {
return nil, errStrategyCurrencyRequirements
}
var mfiFundEvents []mfiFundEvent
mfiFundEvents := make([]mfiFundEvent, 0, len(d))
var resp []signal.Event
for i := range d {
if d == nil {
@@ -233,7 +233,7 @@ func (s *Strategy) SetDefaults() {
// the decision to handle missing data occurs at the strategy level, not all strategies
// may wish to modify data
func (s *Strategy) massageMissingData(data []decimal.Decimal, t time.Time) ([]float64, error) {
var resp []float64
resp := make([]float64, len(data))
var missingDataStreak int64
for i := range data {
if data[i].IsZero() && i > int(s.mfiPeriod.IntPart()) {
@@ -248,8 +248,7 @@ func (s *Strategy) massageMissingData(data []decimal.Decimal, t time.Time) ([]fl
t.Format(gctcommon.SimpleTimeFormat),
base.ErrTooMuchBadData)
}
d, _ := data[i].Float64()
resp = append(resp, d)
resp[i] = data[i].InexactFloat64()
}
return resp, nil
}

View File

@@ -65,8 +65,7 @@ func TestEvent_GetTime(t *testing.T) {
func TestEvent_IsEvent(t *testing.T) {
t.Parallel()
e := &Base{}
y := e.IsEvent()
if !y {
if y := e.IsEvent(); !y {
t.Error("it is an event")
}
}

View File

@@ -199,7 +199,7 @@ func (f *FundManager) GenerateReport() *Report {
UsingExchangeLevelFunding: f.usingExchangeLevelFunding,
DisableUSDTracking: f.disableUSDTracking,
}
var items []ReportItem
items := make([]ReportItem, len(f.items))
for i := range f.items {
item := ReportItem{
Exchange: f.items[i].exchange,
@@ -243,7 +243,7 @@ func (f *FundManager) GenerateReport() *Report {
item.PairedWith = f.items[i].pairedWith.currency
}
items = append(items, item)
items[i] = item
}
report.Items = items
return &report

View File

@@ -46,9 +46,7 @@ func (d *Data) GenerateReport() error {
d.HoldingsOverTimeChart = d.CreateHoldingsOverTimeChart()
tmpl := template.Must(
template.ParseFiles(
filepath.Join(d.TemplatePath),
),
template.ParseFiles(d.TemplatePath),
)
var nickName string
if d.Config.Nickname != "" {
@@ -89,31 +87,33 @@ func (d *Data) CreateUSDTotalsChart() []TotalsChart {
if d.Statistics.FundingStatistics == nil || d.Statistics.FundingStatistics.Report.DisableUSDTracking {
return nil
}
var response []TotalsChart
var usdTotalChartPlot []ChartPlot
usdTotalChartPlot := make([]ChartPlot, len(d.Statistics.FundingStatistics.TotalUSDStatistics.HoldingValues))
for i := range d.Statistics.FundingStatistics.TotalUSDStatistics.HoldingValues {
usdTotalChartPlot = append(usdTotalChartPlot, ChartPlot{
usdTotalChartPlot[i] = ChartPlot{
Value: d.Statistics.FundingStatistics.TotalUSDStatistics.HoldingValues[i].Value.InexactFloat64(),
UnixMilli: d.Statistics.FundingStatistics.TotalUSDStatistics.HoldingValues[i].Time.UTC().UnixMilli(),
})
}
}
response = append(response, TotalsChart{
response := make([]TotalsChart, len(d.Statistics.FundingStatistics.Items)+1)
response[0] = TotalsChart{
Name: "Total USD value",
DataPoints: usdTotalChartPlot,
})
}
for i := range d.Statistics.FundingStatistics.Items {
var plots []ChartPlot
plots := make([]ChartPlot, len(d.Statistics.FundingStatistics.Items[i].ReportItem.Snapshots))
for j := range d.Statistics.FundingStatistics.Items[i].ReportItem.Snapshots {
plots = append(plots, ChartPlot{
plots[j] = ChartPlot{
Value: d.Statistics.FundingStatistics.Items[i].ReportItem.Snapshots[j].USDValue.InexactFloat64(),
UnixMilli: d.Statistics.FundingStatistics.Items[i].ReportItem.Snapshots[j].Time.UTC().UnixMilli(),
})
}
}
response = append(response, TotalsChart{
response[i+1] = TotalsChart{
Name: fmt.Sprintf("%v %v %v USD value", d.Statistics.FundingStatistics.Items[i].ReportItem.Exchange, d.Statistics.FundingStatistics.Items[i].ReportItem.Asset, d.Statistics.FundingStatistics.Items[i].ReportItem.Currency),
DataPoints: plots,
})
}
}
return response
@@ -125,19 +125,19 @@ func (d *Data) CreateHoldingsOverTimeChart() []TotalsChart {
if d.Statistics.FundingStatistics == nil {
return nil
}
var response []TotalsChart
response := make([]TotalsChart, len(d.Statistics.FundingStatistics.Items))
for i := range d.Statistics.FundingStatistics.Items {
var plots []ChartPlot
plots := make([]ChartPlot, len(d.Statistics.FundingStatistics.Items[i].ReportItem.Snapshots))
for j := range d.Statistics.FundingStatistics.Items[i].ReportItem.Snapshots {
plots = append(plots, ChartPlot{
plots[j] = ChartPlot{
Value: d.Statistics.FundingStatistics.Items[i].ReportItem.Snapshots[j].Available.InexactFloat64(),
UnixMilli: d.Statistics.FundingStatistics.Items[i].ReportItem.Snapshots[j].Time.UTC().UnixMilli(),
})
}
}
response = append(response, TotalsChart{
response[i] = TotalsChart{
Name: fmt.Sprintf("%v %v %v holdings", d.Statistics.FundingStatistics.Items[i].ReportItem.Exchange, d.Statistics.FundingStatistics.Items[i].ReportItem.Asset, d.Statistics.FundingStatistics.Items[i].ReportItem.Currency),
DataPoints: plots,
})
}
}
return response
@@ -177,7 +177,7 @@ func (d *Data) enhanceCandles() error {
Asset: lookup.Asset,
Pair: lookup.Pair,
Interval: lookup.Interval,
Watermark: fmt.Sprintf("%v - %v - %v", strings.Title(lookup.Exchange), lookup.Asset.String(), strings.ToUpper(lookup.Pair.String())),
Watermark: fmt.Sprintf("%s - %s - %s", strings.Title(lookup.Exchange), lookup.Asset.String(), lookup.Pair.Upper()), // nolint // Title usage
}
statsForCandles :=

View File

@@ -40,7 +40,7 @@ func TestGenerateReport(t *testing.T) {
d := Data{
Config: &config.Config{},
OutputPath: filepath.Join("..", "results"),
TemplatePath: filepath.Join("tpl.gohtml"),
TemplatePath: "tpl.gohtml",
OriginalCandles: []*gctkline.Item{
{
Candles: []gctkline.Candle{

View File

@@ -6,7 +6,7 @@ import (
"errors"
"flag"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"os"
@@ -18,6 +18,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
gctfile "github.com/thrasher-corp/gocryptotrader/common/file"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
"github.com/thrasher-corp/gocryptotrader/log"
@@ -304,9 +305,9 @@ func checkExistingExchanges(exchName string) bool {
// checkMissingExchanges checks if any supported exchanges are missing api checker functionality
func checkMissingExchanges() []string {
var tempArray []string
tempArray := make([]string, len(usageData.Exchanges))
for x := range usageData.Exchanges {
tempArray = append(tempArray, usageData.Exchanges[x].Name)
tempArray[x] = usageData.Exchanges[x].Name
}
supportedExchs := exchange.Exchanges
for z := 0; z < len(supportedExchs); {
@@ -322,7 +323,7 @@ func checkMissingExchanges() []string {
// readFileData reads the file data from the given json file
func readFileData(fileName string) (Config, error) {
var c Config
data, err := ioutil.ReadFile(fileName)
data, err := os.ReadFile(fileName)
if err != nil {
return c, err
}
@@ -448,7 +449,7 @@ func checkUpdates(fileName string) error {
unsup := checkMissingExchanges()
log.Warnf(log.Global, "The following exchanges are not supported by apichecker: %v\n", unsup)
log.Debugf(log.Global, "Saving the updates to the following file: %s\n", fileName)
return ioutil.WriteFile(fileName, file, 0770)
return os.WriteFile(fileName, file, gctfile.DefaultPermissionOctal)
}
// checkChangeLog checks the exchanges which support changelog updates.json
@@ -559,9 +560,9 @@ func addExch(exchName, checkType string, data interface{}, isUpdate bool) error
return err
}
}
return ioutil.WriteFile(jsonFile, file, 0770)
return os.WriteFile(jsonFile, file, gctfile.DefaultPermissionOctal)
}
return ioutil.WriteFile(testJSONFile, file, 0770)
return os.WriteFile(testJSONFile, file, gctfile.DefaultPermissionOctal)
}
// fillData fills exchange data based on the given checkType
@@ -749,7 +750,7 @@ func htmlScrapeHitBTC(htmlData *HTMLScrapingData) ([]string, error) {
}
defer temp.Body.Close()
a, err := ioutil.ReadAll(temp.Body)
a, err := io.ReadAll(temp.Body)
if err != nil {
return nil, err
}
@@ -784,7 +785,7 @@ func htmlScrapeBTCMarkets(htmlData *HTMLScrapingData) ([]string, error) {
return nil, err
}
defer temp.Body.Close()
tempData, err := ioutil.ReadAll(temp.Body)
tempData, err := io.ReadAll(temp.Body)
if err != nil {
return resp, err
}
@@ -862,7 +863,7 @@ func htmlScrapeANX(htmlData *HTMLScrapingData) ([]string, error) {
}
defer temp.Body.Close()
a, err := ioutil.ReadAll(temp.Body)
a, err := io.ReadAll(temp.Body)
if err != nil {
return nil, err
}
@@ -901,7 +902,7 @@ func htmlScrapeExmo(htmlData *HTMLScrapingData) ([]string, error) {
}
defer httpResp.Body.Close()
a, err := ioutil.ReadAll(httpResp.Body)
a, err := io.ReadAll(httpResp.Body)
if err != nil {
return nil, err
}
@@ -1010,7 +1011,7 @@ func htmlScrapeBitstamp(htmlData *HTMLScrapingData) ([]string, error) {
}
defer temp.Body.Close()
a, err := ioutil.ReadAll(temp.Body)
a, err := io.ReadAll(temp.Body)
if err != nil {
return nil, err
}
@@ -1145,7 +1146,7 @@ func htmlScrapeLocalBitcoins(htmlData *HTMLScrapingData) ([]string, error) {
}
defer temp.Body.Close()
a, err := ioutil.ReadAll(temp.Body)
a, err := io.ReadAll(temp.Body)
if err != nil {
return nil, err
}
@@ -1284,7 +1285,7 @@ func updateFile(name string) error {
if err != nil {
return err
}
return ioutil.WriteFile(name, file, 0770)
return os.WriteFile(name, file, gctfile.DefaultPermissionOctal)
}
// SendGetReq sends get req
@@ -1690,7 +1691,7 @@ func htmlScrapeBitfinex(htmlData *HTMLScrapingData) ([]string, error) {
}
defer temp.Body.Close()
a, err := ioutil.ReadAll(temp.Body)
a, err := io.ReadAll(temp.Body)
if err != nil {
return nil, err
}
@@ -1775,7 +1776,7 @@ func sendHTTPGetRequest(path string, headers map[string]string) (*http.Response,
req, err := http.NewRequestWithContext(context.TODO(),
http.MethodGet,
path,
nil)
http.NoBody)
if err != nil {
return nil, err
}

View File

@@ -2,12 +2,12 @@ package main
import (
"encoding/json"
"io/ioutil"
"os"
"reflect"
"testing"
"github.com/thrasher-corp/gocryptotrader/common/convert"
gctfile "github.com/thrasher-corp/gocryptotrader/common/file"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/log"
)
@@ -86,7 +86,7 @@ func removeTestFileVars() error {
if err != nil {
return err
}
return ioutil.WriteFile(testJSONFile, file, 0770)
return os.WriteFile(testJSONFile, file, gctfile.DefaultPermissionOctal)
}
func canTestTrello() bool {
@@ -439,8 +439,7 @@ func TestUpdate(t *testing.T) {
func TestCheckMissingExchanges(t *testing.T) {
t.Parallel()
a := checkMissingExchanges()
if len(a) > len(exchange.Exchanges) {
if a := checkMissingExchanges(); len(a) > len(exchange.Exchanges) {
t.Fatal("invalid response")
}
}

View File

@@ -3,8 +3,8 @@ package main
import (
"encoding/json"
"flag"
"io/ioutil"
"log"
"os"
"github.com/thrasher-corp/gocryptotrader/common/file"
"github.com/thrasher-corp/gocryptotrader/config"
@@ -38,7 +38,7 @@ func main() {
key = string(result)
}
fileData, err := ioutil.ReadFile(inFile)
fileData, err := os.ReadFile(inFile)
if err != nil {
log.Fatalf("Unable to read input file %s. Error: %s.", inFile, err)
}

View File

@@ -30,8 +30,8 @@ func main() {
wg.Wait()
log.Println("Done.")
var cfgs []config.Exchange
exchanges := engine.Bot.GetExchanges()
cfgs := make([]config.Exchange, 0, len(exchanges))
for x := range exchanges {
var cfg *config.Exchange
cfg, err = exchanges[x].GetDefaultConfig()

View File

@@ -51,11 +51,11 @@ func seedExchangeFromDefaultList(c *cli.Context) error {
if err != nil {
return err
}
var allExchanges []exchangeDB.Details
allExchanges := make([]exchangeDB.Details, len(exchange.Exchanges))
for x := range exchange.Exchanges {
allExchanges = append(allExchanges, exchangeDB.Details{
allExchanges[x] = exchangeDB.Details{
Name: exchange.Exchanges[x],
})
}
}
err = exchangeDB.InsertMany(allExchanges)
if err != nil {

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/core"
@@ -44,7 +43,7 @@ func main() {
workingDir, err = os.Getwd()
if err != nil {
log.Println("error getting current working path")
workingDir = filepath.Join(".")
workingDir = "."
}
fmt.Println("GoCryptoTrader database seeding tool")

View File

@@ -7,7 +7,6 @@ import (
"flag"
"fmt"
"html/template"
"io/ioutil"
"log"
"net/http"
"os"
@@ -329,7 +328,7 @@ func GetConfiguration() (Config, error) {
configFilePath := filepath.Join(toolDir, "config.json")
if file.Exists(configFilePath) {
config, err := ioutil.ReadFile(configFilePath)
config, err := os.ReadFile(configFilePath)
if err != nil {
return c, err
}
@@ -360,7 +359,7 @@ func GetConfiguration() (Config, error) {
return c, err
}
if err := ioutil.WriteFile(configFilePath, data, 0770); err != nil {
if err := os.WriteFile(configFilePath, data, file.DefaultPermissionOctal); err != nil {
return c, err
}
@@ -485,7 +484,7 @@ func GetPackageName(name string, capital bool) string {
i = len(newStrings) - 1
}
if capital {
return strings.Replace(strings.Title(newStrings[i]), "_", " ", -1)
return strings.Replace(strings.Title(newStrings[i]), "_", " ", -1) // nolint // ignore staticcheck strings.Title warning
}
return newStrings[i]
}
@@ -540,7 +539,7 @@ func UpdateDocumentation(details DocumentationDetails) {
continue
}
if name == engineFolder {
d, err := ioutil.ReadDir(details.Directories[i])
d, err := os.ReadDir(details.Directories[i])
if err != nil {
fmt.Println("Excluding file:", err)
}

View File

@@ -12,6 +12,7 @@ import (
"strings"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/file"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/core"
"github.com/thrasher-corp/gocryptotrader/currency"
@@ -138,14 +139,14 @@ func makeExchange(exchangeDirectory string, configTestFile *config.Config, exch
if !os.IsNotExist(err) {
return nil, errors.New("directory already exists")
}
err = os.MkdirAll(exchangeDirectory, 0770)
err = os.MkdirAll(exchangeDirectory, file.DefaultPermissionOctal)
if err != nil {
return nil, err
}
fmt.Printf("Output directory: %s\n", exchangeDirectory)
exch.CapitalName = strings.Title(exch.Name)
exch.CapitalName = strings.Title(exch.Name) // nolint:staticcheck // Ignore Title usage warning
exch.Variable = exch.Name[0:2]
newExchConfig := &config.Exchange{}
newExchConfig.Name = exch.CapitalName
@@ -214,7 +215,7 @@ func makeExchange(exchangeDirectory string, configTestFile *config.Config, exch
outputFile := filepath.Join(exchangeDirectory, filename)
newFile(outputFile)
var f *os.File
f, err = os.OpenFile(outputFile, os.O_WRONLY, 0770)
f, err = os.OpenFile(outputFile, os.O_WRONLY, file.DefaultPermissionOctal)
if err != nil {
return nil, err
}

View File

@@ -334,18 +334,20 @@ func ({{.Variable}} *{{.CapitalName}}) UpdateOrderbook(ctx context.Context, pair
return book, err
}
book.Bids = make([]orderbook.Item, len(orderbookNew.Bids))
for x := range orderbookNew.Bids {
book.Bids = append(book.Bids, orderbook.Item{
book.Bids[x] = orderbook.Item{
Amount: orderbookNew.Bids[x].Quantity,
Price: orderbookNew.Bids[x].Price,
})
}
}
book.Asks = make([]orderbook.Item, len(orderbookNew.Asks))
for x := range orderbookNew.Asks {
book.Asks = append(book.Asks, orderbook.Item{
book.Asks[x] = orderbook.Item{
Amount: orderBookNew.Asks[x].Quantity,
Price: orderBookNew.Asks[x].Price,
})
}
}
*/

View File

@@ -6,7 +6,6 @@ import (
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
@@ -283,7 +282,7 @@ func parseOrderType(orderType string) order.Type {
}
func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config) []ExchangeAssetPairResponses {
var response []ExchangeAssetPairResponses
response := make([]ExchangeAssetPairResponses, 0)
testOrderSide := parseOrderSide(config.OrderSubmission.OrderSide)
testOrderType := parseOrderType(config.OrderSubmission.OrderType)
assetTypes := base.GetAssetTypes(false)
@@ -835,13 +834,13 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
}
func jsonifyInterface(params []interface{}) json.RawMessage {
response, _ := json.MarshalIndent(params, "", " ")
response, _ := json.MarshalIndent(params, "", " ") // nolint:errchkjson // TODO: ignore this for now
return response
}
func loadConfig() (Config, error) {
var config Config
keys, err := ioutil.ReadFile("wrapperconfig.json")
keys, err := os.ReadFile("wrapperconfig.json")
if err != nil {
return config, err
}

View File

@@ -3,7 +3,7 @@ package main
import (
"errors"
"fmt"
"io/ioutil"
"io"
"math"
"os"
"path/filepath"
@@ -4226,7 +4226,7 @@ func gctScriptUpload(c *cli.Context) error {
defer closeConn(conn, cancel)
client := gctrpc.NewGoCryptoTraderClient(conn)
data, err := ioutil.ReadAll(file)
data, err := io.ReadAll(file)
if err != nil {
return err
}

View File

@@ -198,7 +198,7 @@ func enableDisableExchangePair(c *cli.Context) error {
pairList := strings.Split(pairs, ",")
var validPairs []*gctrpc.CurrencyPair
validPairs := make([]*gctrpc.CurrencyPair, len(pairList))
for i := range pairList {
if !validPair(pairList[i]) {
return errInvalidPair
@@ -209,11 +209,11 @@ func enableDisableExchangePair(c *cli.Context) error {
return err
}
validPairs = append(validPairs, &gctrpc.CurrencyPair{
validPairs[i] = &gctrpc.CurrencyPair{
Delimiter: p.Delimiter,
Base: p.Base.String(),
Quote: p.Quote.String(),
})
}
}
conn, cancel, err := setupClient(c)

View File

@@ -4,10 +4,10 @@ import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/thrasher-corp/gocryptotrader/common/file"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/core"
"github.com/thrasher-corp/gocryptotrader/database"
@@ -57,7 +57,7 @@ func main() {
}
path := filepath.Join(outputFolder, "sqlboiler.json")
err = ioutil.WriteFile(path, jsonOutput, 0770)
err = os.WriteFile(path, jsonOutput, file.DefaultPermissionOctal)
if err != nil {
fmt.Printf("Write failed: %v", err)
os.Exit(1)

View File

@@ -2,6 +2,8 @@ package cache
import (
"testing"
"github.com/thrasher-corp/gocryptotrader/common/convert"
)
func TestCache(t *testing.T) {
@@ -16,12 +18,11 @@ func TestCache(t *testing.T) {
if v == nil {
t.Fatal("expected cache to contain \"hello\" key")
}
if v.(string) != "world" {
if convert.InterfaceToStringOrZeroValue(v) != "world" {
t.Fatal("expected \"hello\" key to contain value \"world\"")
}
r := lruCache.Remove("hello")
if !r {
if r := lruCache.Remove("hello"); !r {
t.Fatal("expected \"hello\" key to be removed from cache")
}
@@ -77,39 +78,39 @@ func TestAdd(t *testing.T) {
if v == nil {
t.Fatal("expected cache to contain \"2\" key")
}
if v.(int) != 2 {
if convert.InterfaceToIntOrZeroValue(v) != 2 {
t.Fatal("expected \"2\" key to contain value \"2\"")
}
k, v := lruCache.getNewest()
if k.(int) != 2 {
if convert.InterfaceToIntOrZeroValue(k) != 2 {
t.Fatal("expected latest key to be 2")
}
if v.(int) != 2 {
if convert.InterfaceToIntOrZeroValue(v) != 2 {
t.Fatal("expected latest value to be 2")
}
lruCache.Add(3, 3)
k, _ = lruCache.getNewest()
if k.(int) != 3 {
if convert.InterfaceToIntOrZeroValue(k) != 3 {
t.Fatal("expected latest key to be 3")
}
k, _ = lruCache.getOldest()
if k.(int) != 2 {
if convert.InterfaceToIntOrZeroValue(k) != 2 {
t.Fatal("expected oldest key to be 2")
}
k, v = lruCache.getOldest()
if k.(int) != 2 {
if convert.InterfaceToIntOrZeroValue(k) != 2 {
t.Fatal("expected oldest key to be 2")
}
if v.(int) != 2 {
if convert.InterfaceToIntOrZeroValue(v) != 2 {
t.Fatal("expected latest value to be 2")
}
lruCache.Add(2, 2)
k, _ = lruCache.getNewest()
if k.(int) != 2 {
if convert.InterfaceToIntOrZeroValue(k) != 2 {
t.Fatal("expected latest key to be 2")
}
k, _ = lruCache.getOldest()
if k.(int) != 3 {
if convert.InterfaceToIntOrZeroValue(k) != 3 {
t.Fatal("expected oldest key to be 3")
}
}

20
common/cache/lru.go vendored
View File

@@ -24,7 +24,9 @@ func NewLRUCache(capacity uint64) *LRU {
func (l *LRU) Add(key, value interface{}) {
if f, o := l.items[key]; o {
l.l.MoveToFront(f)
f.Value.(*item).value = value
if v, ok := f.Value.(*item); ok {
v.value = value
}
return
}
@@ -40,7 +42,9 @@ func (l *LRU) Add(key, value interface{}) {
func (l *LRU) Get(key interface{}) interface{} {
if i, f := l.items[key]; f {
l.l.MoveToFront(i)
return i.Value.(*item).value
if v, ok := i.Value.(*item); ok {
return v.value
}
}
return nil
}
@@ -48,7 +52,9 @@ func (l *LRU) Get(key interface{}) interface{} {
// GetOldest returns the oldest entry
func (l *LRU) getOldest() (key, value interface{}) {
if x := l.l.Back(); x != nil {
return x.Value.(*item).key, x.Value.(*item).value
if v, ok := x.Value.(*item); ok {
return v.key, v.value
}
}
return
}
@@ -56,7 +62,9 @@ func (l *LRU) getOldest() (key, value interface{}) {
// GetNewest returns the newest entry
func (l *LRU) getNewest() (key, value interface{}) {
if x := l.l.Front(); x != nil {
return x.Value.(*item).key, x.Value.(*item).value
if v, ok := x.Value.(*item); ok {
return v.key, v.value
}
}
return
}
@@ -99,5 +107,7 @@ func (l *LRU) removeOldestEntry() {
// removeElement element from the cache
func (l *LRU) removeElement(e *list.Element) {
l.l.Remove(e)
delete(l.items, e.Value.(*item).key)
if v, ok := e.Value.(*item); ok {
delete(l.items, v.key)
}
}

View File

@@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
@@ -18,6 +17,7 @@ import (
"sync"
"time"
"github.com/thrasher-corp/gocryptotrader/common/file"
"github.com/thrasher-corp/gocryptotrader/log"
)
@@ -257,7 +257,7 @@ func SendHTTPRequest(ctx context.Context, method, urlPath string, headers map[st
}
defer resp.Body.Close()
contents, err := ioutil.ReadAll(resp.Body)
contents, err := io.ReadAll(resp.Body)
if verbose {
log.Debugf(log.Global, "HTTP status: %s, Code: %v",
@@ -348,7 +348,7 @@ func CreateDir(dir string) error {
}
log.Warnf(log.Global, "Directory %s does not exist.. creating.\n", dir)
return os.MkdirAll(dir, 0770)
return os.MkdirAll(dir, file.DefaultPermissionOctal)
}
// ChangePermission lists all the directories and files in an array
@@ -357,8 +357,8 @@ func ChangePermission(directory string) error {
if err != nil {
return err
}
if info.Mode().Perm() != 0770 {
return os.Chmod(path, 0770)
if info.Mode().Perm() != file.DefaultPermissionOctal {
return os.Chmod(path, file.DefaultPermissionOctal)
}
return nil
})

View File

@@ -14,6 +14,8 @@ import (
"strings"
"testing"
"time"
"github.com/thrasher-corp/gocryptotrader/common/file"
)
func TestSendHTTPRequest(t *testing.T) {
@@ -509,7 +511,7 @@ func TestChangePermission(t *testing.T) {
if err == nil {
t.Fatal("expected an error on non-existent path")
}
err = os.Mkdir(testDir, 0777)
err = os.Mkdir(testDir, 0o777)
if err != nil {
t.Fatalf("Mkdir failed. Err: %v", err)
}
@@ -530,7 +532,7 @@ func TestChangePermission(t *testing.T) {
if err == nil {
t.Fatal("expected an error on non-existent path")
}
err = os.Mkdir(testDir, 0777)
err = os.Mkdir(testDir, 0o777)
if err != nil {
t.Fatalf("Mkdir failed. Err: %v", err)
}
@@ -543,8 +545,8 @@ func TestChangePermission(t *testing.T) {
if err != nil {
t.Fatalf("os.Stat failed. Err: %v", err)
}
if a.Mode().Perm() != 0770 {
t.Fatalf("expected file permissions differ. expecting 0770 got %#o", a.Mode().Perm())
if a.Mode().Perm() != file.DefaultPermissionOctal {
t.Fatalf("expected file permissions differ. expecting file.DefaultPermissionOctal got %#o", a.Mode().Perm())
}
err = os.Remove(testDir)
if err != nil {

View File

@@ -119,8 +119,7 @@ func DecimalToHumanFriendlyString(number decimal.Decimal, rounding int, decPoint
neg = true
}
str := number.String()
rnd := strings.Split(str, ".")
if len(rnd) == 1 {
if rnd := strings.Split(str, "."); len(rnd) == 1 {
rounding = 0
} else if len(rnd[1]) < rounding {
rounding = len(rnd[1])
@@ -164,3 +163,27 @@ func numberToHumanFriendlyString(str string, dec int, decPoint, thousandsSep str
return s
}
// InterfaceToFloat64OrZeroValue returns the type assertion value or variable zero value
func InterfaceToFloat64OrZeroValue(r interface{}) float64 {
if v, ok := r.(float64); ok {
return v
}
return 0
}
// InterfaceToIntOrZeroValue returns the type assertion value or variable zero value
func InterfaceToIntOrZeroValue(r interface{}) int {
if v, ok := r.(int); ok {
return v
}
return 0
}
// InterfaceToStringOrZeroValue returns the type assertion value or variable zero value
func InterfaceToStringOrZeroValue(r interface{}) string {
if v, ok := r.(string); ok {
return v
}
return ""
}

View File

@@ -282,3 +282,36 @@ func TestNumberToHumanFriendlyString(t *testing.T) {
t.Error("expected no comma")
}
}
func TestInterfaceToFloat64OrZeroValue(t *testing.T) {
var x interface{}
if r := InterfaceToFloat64OrZeroValue(x); r != 0 {
t.Errorf("expected 0, got: %v", r)
}
x = float64(420)
if r := InterfaceToFloat64OrZeroValue(x); r != 420 {
t.Errorf("expected 420, got: %v", x)
}
}
func TestInterfaceToIntOrZeroValue(t *testing.T) {
var x interface{}
if r := InterfaceToIntOrZeroValue(x); r != 0 {
t.Errorf("expected 0, got: %v", r)
}
x = int(420)
if r := InterfaceToIntOrZeroValue(x); r != 420 {
t.Errorf("expected 420, got: %v", x)
}
}
func TestInterfaceToStringOrZeroValue(t *testing.T) {
var x interface{}
if r := InterfaceToStringOrZeroValue(x); r != "" {
t.Errorf("expected empty string, got: %v", r)
}
x = string("meow")
if r := InterfaceToStringOrZeroValue(x); r != "meow" {
t.Errorf("expected meow, got: %v", x)
}
}

View File

@@ -148,7 +148,7 @@ func TestGetHMAC(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if string(sha1) != string(expectedSha1) {
if !bytes.Equal(sha1, expectedSha1) {
t.Errorf("Common GetHMAC error: Expected '%x'. Actual '%x'",
expectedSha1, sha1,
)
@@ -157,7 +157,7 @@ func TestGetHMAC(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if string(sha256) != string(expectedsha256) {
if !bytes.Equal(sha256, expectedsha256) {
t.Errorf("Common GetHMAC error: Expected '%x'. Actual '%x'",
expectedsha256, sha256,
)
@@ -166,7 +166,7 @@ func TestGetHMAC(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if string(sha512) != string(expectedsha512) {
if !bytes.Equal(sha512, expectedsha512) {
t.Errorf("Common GetHMAC error: Expected '%x'. Actual '%x'",
expectedsha512, sha512,
)
@@ -175,7 +175,7 @@ func TestGetHMAC(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if string(sha512384) != string(expectedsha512384) {
if !bytes.Equal(sha512384, expectedsha512384) {
t.Errorf("Common GetHMAC error: Expected '%x'. Actual '%x'",
expectedsha512384, sha512384,
)
@@ -184,7 +184,7 @@ func TestGetHMAC(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if string(md5) != string(expectedmd5) {
if !bytes.Equal(md5, expectedmd5) {
t.Errorf("Common GetHMAC error: Expected '%x'. Actual '%x'",
expectedmd5, md5,
)

View File

@@ -8,6 +8,7 @@ import (
"path/filepath"
"strings"
"github.com/thrasher-corp/gocryptotrader/common/file"
"github.com/thrasher-corp/gocryptotrader/log"
)
@@ -52,7 +53,7 @@ func UnZip(src, dest string) (fileList []string, err error) {
continue
}
err = os.MkdirAll(filepath.Dir(fPath), 0770)
err = os.MkdirAll(filepath.Dir(fPath), file.DefaultPermissionOctal)
if err != nil {
return
}

View File

@@ -6,22 +6,25 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"io/fs"
"os"
"path/filepath"
)
// DefaultPermissionOctal is the default file and folder permission octal used throughout GCT
const DefaultPermissionOctal fs.FileMode = 0o770
// Write writes selected data to a file or returns an error if it fails. This
// func also ensures that all files are set to this permission (only rw access
// for the running user and the group the user is a member of)
func Write(file string, data []byte) error {
basePath := filepath.Dir(file)
if !Exists(basePath) {
if err := os.MkdirAll(basePath, 0770); err != nil {
if err := os.MkdirAll(basePath, DefaultPermissionOctal); err != nil {
return err
}
}
return ioutil.WriteFile(file, data, 0770)
return os.WriteFile(file, data, DefaultPermissionOctal)
}
// Writer creates a writer to a file or returns an error if it fails. This
@@ -30,11 +33,11 @@ func Write(file string, data []byte) error {
func Writer(file string) (*os.File, error) {
basePath := filepath.Dir(file)
if !Exists(basePath) {
if err := os.MkdirAll(basePath, 0770); err != nil {
if err := os.MkdirAll(basePath, DefaultPermissionOctal); err != nil {
return nil, err
}
}
return os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0770)
return os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, DefaultPermissionOctal)
}
// Move moves a file from a source path to a destination path
@@ -59,7 +62,7 @@ func Move(sourcePath, destPath string) error {
destDir := filepath.Dir(destPath)
if !Exists(destDir) {
err = os.MkdirAll(destDir, 0770)
err = os.MkdirAll(destDir, DefaultPermissionOctal)
if err != nil {
return err
}

View File

@@ -56,7 +56,7 @@ func TestWrite(t *testing.T) {
func TestMove(t *testing.T) {
tester := func(in, out string, write bool) error {
if write {
if err := ioutil.WriteFile(in, []byte("GoCryptoTrader"), 0770); err != nil {
if err := os.WriteFile(in, []byte("GoCryptoTrader"), DefaultPermissionOctal); err != nil {
return err
}
}
@@ -65,7 +65,7 @@ func TestMove(t *testing.T) {
return err
}
contents, err := ioutil.ReadFile(out)
contents, err := os.ReadFile(out)
if err != nil {
return err
}
@@ -124,7 +124,7 @@ func TestExists(t *testing.T) {
t.Error("non-existent file should not exist")
}
tmpFile := filepath.Join(os.TempDir(), "gct-test.txt")
if err := ioutil.WriteFile(tmpFile, []byte("hello world"), os.ModeAppend); err != nil {
if err := os.WriteFile(tmpFile, []byte("hello world"), os.ModeAppend); err != nil {
t.Fatal(err)
}
if e := Exists(tmpFile); !e {
@@ -258,7 +258,7 @@ func TestWriter(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if data, err := ioutil.ReadFile(got.Name()); err != nil || string(data) != testData {
if data, err := os.ReadFile(got.Name()); err != nil || string(data) != testData {
t.Errorf("Could not write the file, or contents were wrong: expected = %s, got =%s", testData, string(data))
}
})
@@ -274,7 +274,7 @@ func TestWriterNoPermissionFails(t *testing.T) {
t.Fatal(err)
}
defer os.RemoveAll(temp)
err = os.Chmod(temp, 0555)
err = os.Chmod(temp, 0o555)
if err != nil {
t.Fatal(err)
}

View File

@@ -89,9 +89,9 @@ func InformationRatio(returnsRates, benchmarkRates []float64, averageValues, ave
if len(benchmarkRates) != len(returnsRates) {
return 0, errInformationBadLength
}
var diffs []float64
diffs := make([]float64, len(returnsRates))
for i := range returnsRates {
diffs = append(diffs, returnsRates[i]-benchmarkRates[i])
diffs[i] = returnsRates[i] - benchmarkRates[i]
}
stdDev, err := PopulationStandardDeviation(diffs)
if err != nil {
@@ -135,11 +135,11 @@ func SampleStandardDeviation(values []float64) (float64, error) {
if err != nil {
return 0, err
}
var superMean []float64
superMean := make([]float64, len(values))
var combined float64
for i := range values {
result := math.Pow(values[i]-mean, 2)
superMean = append(superMean, result)
superMean[i] = result
combined += result
}
avg := combined / (float64(len(superMean)) - 1)
@@ -232,9 +232,9 @@ func SharpeRatio(movementPerCandle []float64, riskFreeRatePerInterval, average f
if totalIntervals == 0 {
return 0, errZeroValue
}
var excessReturns []float64
excessReturns := make([]float64, len(movementPerCandle))
for i := range movementPerCandle {
excessReturns = append(excessReturns, movementPerCandle[i]-riskFreeRatePerInterval)
excessReturns[i] = movementPerCandle[i] - riskFreeRatePerInterval
}
standardDeviation, err := PopulationStandardDeviation(excessReturns)
if err != nil {
@@ -284,9 +284,9 @@ func DecimalInformationRatio(returnsRates, benchmarkRates []decimal.Decimal, ave
if len(benchmarkRates) != len(returnsRates) {
return decimal.Zero, errInformationBadLength
}
var diffs []decimal.Decimal
diffs := make([]decimal.Decimal, len(returnsRates))
for i := range returnsRates {
diffs = append(diffs, returnsRates[i].Sub(benchmarkRates[i]))
diffs[i] = returnsRates[i].Sub(benchmarkRates[i])
}
stdDev, err := DecimalPopulationStandardDeviation(diffs)
if err != nil && !errors.Is(err, ErrInexactConversion) {
@@ -339,11 +339,11 @@ func DecimalSampleStandardDeviation(values []decimal.Decimal) (decimal.Decimal,
if err != nil {
return decimal.Zero, err
}
var superMean []decimal.Decimal
superMean := make([]decimal.Decimal, len(values))
var combined decimal.Decimal
for i := range values {
pow := values[i].Sub(mean).Pow(decimal.NewFromInt(2))
superMean = append(superMean, pow)
superMean[i] = pow
combined.Add(pow)
}
avg := combined.Div(decimal.NewFromInt(int64(len(superMean))).Sub(decimal.NewFromInt(1)))
@@ -380,9 +380,7 @@ func DecimalGeometricMean(values []decimal.Decimal) (decimal.Decimal, error) {
// DecimalPow is lovely because shopspring decimal cannot
// handle ^0.x and instead returns 1
func DecimalPow(x, y decimal.Decimal) decimal.Decimal {
fX, _ := x.Float64()
fY, _ := y.Float64()
pow := math.Pow(fX, fY)
pow := math.Pow(x.InexactFloat64(), y.InexactFloat64())
return decimal.NewFromFloat(pow)
}
@@ -405,7 +403,7 @@ func DecimalFinancialGeometricMean(values []decimal.Decimal) (decimal.Decimal, e
// as we cannot have negative or zero value geometric numbers
// adding a 1 to the percentage movements allows for differentiation between
// negative numbers (eg -0.1 translates to 0.9) and positive numbers (eg 0.1 becomes 1.1)
modVal, _ := values[i].Add(decimal.NewFromInt(1)).Float64()
modVal := values[i].Add(decimal.NewFromInt(1)).InexactFloat64()
product *= modVal
}
prod := 1 / float64(len(values))
@@ -461,9 +459,9 @@ func DecimalSharpeRatio(movementPerCandle []decimal.Decimal, riskFreeRatePerInte
if totalIntervals.IsZero() {
return decimal.Zero, errZeroValue
}
var excessReturns []decimal.Decimal
excessReturns := make([]decimal.Decimal, len(movementPerCandle))
for i := range movementPerCandle {
excessReturns = append(excessReturns, movementPerCandle[i].Sub(riskFreeRatePerInterval))
excessReturns[i] = movementPerCandle[i].Sub(riskFreeRatePerInterval)
}
standardDeviation, err := DecimalPopulationStandardDeviation(excessReturns)
if err != nil && !errors.Is(err, ErrInexactConversion) {

View File

@@ -184,9 +184,9 @@ func TestInformationRatio(t *testing.T) {
t.Error(avgComparison)
}
var eachDiff []float64
eachDiff := make([]float64, len(figures))
for i := range figures {
eachDiff = append(eachDiff, figures[i]-comparisonFigures[i])
eachDiff[i] = figures[i] - comparisonFigures[i]
}
stdDev, err := PopulationStandardDeviation(eachDiff)
if err != nil {
@@ -583,9 +583,9 @@ func TestDecimalInformationRatio(t *testing.T) {
t.Error(avgComparison)
}
var eachDiff []decimal.Decimal
eachDiff := make([]decimal.Decimal, len(figures))
for i := range figures {
eachDiff = append(eachDiff, figures[i].Sub(comparisonFigures[i]))
eachDiff[i] = figures[i].Sub(comparisonFigures[i])
}
stdDev, err := DecimalPopulationStandardDeviation(eachDiff)
if err != nil && !errors.Is(err, ErrInexactConversion) {
@@ -703,14 +703,13 @@ func TestDecimalStandardDeviation2(t *testing.T) {
if err != nil {
t.Error(err)
}
var superMean []decimal.Decimal
superMean := make([]decimal.Decimal, len(r))
for i := range r {
result := r[i].Sub(mean).Pow(decimal.NewFromInt(2))
superMean = append(superMean, result)
superMean[i] = result
}
superMeany := superMean[0].Add(superMean[1].Add(superMean[2].Add(superMean[3].Add(superMean[4].Add(superMean[5]))))).Div(decimal.NewFromInt(5))
fSuperMeany, _ := superMeany.Float64()
manualCalculation := decimal.NewFromFloat(math.Sqrt(fSuperMeany))
manualCalculation := decimal.NewFromFloat(math.Sqrt(superMeany.InexactFloat64()))
var codeCalcu decimal.Decimal
codeCalcu, err = DecimalSampleStandardDeviation(r)
if err != nil {

View File

@@ -108,8 +108,11 @@ func TestSetup(t *testing.T) {
for idx, provider := range ic {
exp := testConfigs[idx].shouldConnectCalled
act := provider.(*CommunicationProvider).ConnectCalled
if exp != act {
act, ok := provider.(*CommunicationProvider)
if !ok {
t.Fatal("unable to type assert provider")
}
if exp != act.ConnectCalled {
t.Fatalf("provider should be enabled and not be connected: exp=%v, act=%v", exp, act)
}
}
@@ -139,8 +142,11 @@ func TestPushEvent(t *testing.T) {
for idx, provider := range ic {
exp := testConfigs[idx].PushEventCalled
act := provider.(*CommunicationProvider).PushEventCalled
if exp != act {
act, ok := provider.(*CommunicationProvider)
if !ok {
t.Fatal("unable to type assert provider")
}
if exp != act.PushEventCalled {
t.Fatalf("provider should be enabled and connected: exp=%v, act=%v", exp, act)
}
}

View File

@@ -47,7 +47,7 @@ type Slack struct {
WebsocketConn *websocket.Conn
Connected bool
Shutdown bool
sync.Mutex
mu sync.Mutex
}
// IsConnected returns whether or not the connection is connected
@@ -91,9 +91,9 @@ func (s *Slack) BuildURL(token string) string {
// GetChannelsString returns a list of all channels on the slack workspace
func (s *Slack) GetChannelsString() []string {
var channels []string
channels := make([]string, len(s.Details.Channels))
for i := range s.Details.Channels {
channels = append(channels, s.Details.Channels[i].NameNormalized)
channels[i] = s.Details.Channels[i].NameNormalized
}
return channels
}
@@ -355,8 +355,8 @@ func (s *Slack) WebsocketKeepAlive() {
// WebsocketSend sends a message via the websocket connection
func (s *Slack) WebsocketSend(eventType, text string) error {
s.Lock()
defer s.Unlock()
s.mu.Lock()
defer s.mu.Unlock()
newMessage := SendMessage{
ID: time.Now().Unix(),
Type: eventType,

View File

@@ -206,7 +206,10 @@ func TestHandlePresenceChange(t *testing.T) {
t.Error("slack handlePresenceChange(), unmarshalled malformed json")
}
data, _ := json.Marshal(pres)
data, err := json.Marshal(pres)
if err != nil {
t.Fatal(err)
}
err = s.handlePresenceChange(data)
if err != nil {
t.Errorf("slack handlePresenceChange() Error: %s", err)
@@ -235,7 +238,10 @@ func TestHandleMessageResponse(t *testing.T) {
var msg Message
msg.User = "1337"
msg.Text = "Hello World!"
resp, _ := json.Marshal(msg)
resp, err := json.Marshal(msg)
if err != nil {
t.Fatal(err)
}
err = s.handleMessageResponse(resp, data)
if err != nil {
@@ -243,7 +249,10 @@ func TestHandleMessageResponse(t *testing.T) {
}
msg.Text = "!notacommand"
resp, _ = json.Marshal(msg)
resp, err = json.Marshal(msg)
if err != nil {
t.Fatal(err)
}
err = s.handleMessageResponse(resp, data)
if err == nil {
@@ -286,7 +295,10 @@ func TestHandleReconnectResponse(t *testing.T) {
}
testURL.URL = "https://www.thrasher.io"
data, _ := json.Marshal(testURL)
data, err := json.Marshal(testURL)
if err != nil {
t.Fatal(err)
}
err = s.handleReconnectResponse(data)
if err != nil || s.ReconnectURL != "https://www.thrasher.io" {

View File

@@ -42,15 +42,13 @@ func (s *SMSGlobal) Setup(cfg *base.CommunicationsConfig) {
s.Password = cfg.SMSGlobalConfig.Password
s.SendFrom = cfg.SMSGlobalConfig.From
var contacts []Contact
contacts := make([]Contact, len(cfg.SMSGlobalConfig.Contacts))
for x := range cfg.SMSGlobalConfig.Contacts {
contacts = append(contacts,
Contact{
Name: cfg.SMSGlobalConfig.Contacts[x].Name,
Number: cfg.SMSGlobalConfig.Contacts[x].Number,
Enabled: cfg.SMSGlobalConfig.Contacts[x].Enabled,
},
)
contacts[x] = Contact{
Name: cfg.SMSGlobalConfig.Contacts[x].Name,
Number: cfg.SMSGlobalConfig.Contacts[x].Number,
Enabled: cfg.SMSGlobalConfig.Contacts[x].Enabled,
}
log.Debugf(log.CommunicationMgr, "SMSGlobal: SMS Contact: %s. Number: %s. Enabled: %v\n",
cfg.SMSGlobalConfig.Contacts[x].Name,
cfg.SMSGlobalConfig.Contacts[x].Number,

View File

@@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"runtime"
@@ -1420,7 +1419,7 @@ func GetFilePath(configFile string) (configPath string, isImplicitDefaultPath bo
// config directory as `File` or `EncryptedFile` depending on whether the config
// is encrypted
func migrateConfig(configFile, targetDir string) (string, error) {
data, err := ioutil.ReadFile(configFile)
data, err := os.ReadFile(configFile)
if err != nil {
return "", err
}
@@ -1518,7 +1517,7 @@ func ReadConfig(configReader io.Reader, keyProvider func() ([]byte, error)) (*Co
// readEncryptedConf reads encrypted configuration and requests key from provider
func readEncryptedConfWithKey(reader *bufio.Reader, keyProvider func() ([]byte, error)) (*Config, error) {
fileData, err := ioutil.ReadAll(reader)
fileData, err := io.ReadAll(reader)
if err != nil {
return nil, err
}

View File

@@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"github.com/thrasher-corp/gocryptotrader/common"
@@ -137,7 +136,7 @@ func (c *Config) decryptConfigData(configReader io.Reader, key []byte) ([]byte,
return nil, err
}
origKey := key
configData, err := ioutil.ReadAll(configReader)
configData, err := io.ReadAll(configReader)
if err != nil {
return nil, err
}

View File

@@ -179,11 +179,11 @@ func TestEncryptTwiceReusesSaltButNewCipher(t *testing.T) {
if err != nil {
t.Fatalf("Problem storing config in file %s: %s\n", enc2, err)
}
data1, err := ioutil.ReadFile(enc1)
data1, err := os.ReadFile(enc1)
if err != nil {
t.Fatalf("Problem reading file %s: %s\n", enc1, err)
}
data2, err := ioutil.ReadFile(enc2)
data2, err := os.ReadFile(enc2)
if err != nil {
t.Fatalf("Problem reading file %s: %s\n", enc2, err)
}
@@ -281,7 +281,7 @@ func TestReadConfigWithPrompt(t *testing.T) {
}
// Verify results
data, err := ioutil.ReadFile(testConfigFile)
data, err := os.ReadFile(testConfigFile)
if err != nil {
t.Fatalf("Problem reading saved file at %s: %s\n", testConfigFile, err)
}
@@ -349,7 +349,7 @@ func TestSaveConfigToFileWithErrorInPasswordPrompt(t *testing.T) {
if err != nil {
t.Fatal(err)
}
data, err := ioutil.ReadFile(targetFile)
data, err := os.ReadFile(targetFile)
if err != nil {
t.Fatal(err)
}

View File

@@ -920,7 +920,7 @@ func TestSupportsPair(t *testing.T) {
},
},
}
assetType := asset.Spot // nolint // ifshort false positive
assetType := asset.Spot
if cfg.SupportsPair("asdf",
currency.NewPair(currency.BTC, currency.USD), assetType) {
t.Error(

View File

@@ -74,7 +74,7 @@ type Checker struct {
shutdown chan struct{}
wg sync.WaitGroup
connected bool
sync.Mutex
mu sync.Mutex
}
// Shutdown cleanly shutsdown monitor routine
@@ -136,12 +136,12 @@ func (c *Checker) connectionTest() {
for i := range c.DNSList {
err := c.CheckDNS(c.DNSList[i])
if err == nil {
c.Lock()
c.mu.Lock()
if !c.connected {
log.Debugln(log.Global, ConnRe)
c.connected = true
}
c.Unlock()
c.mu.Unlock()
return
}
}
@@ -149,22 +149,22 @@ func (c *Checker) connectionTest() {
for i := range c.DomainList {
err := c.CheckHost(c.DomainList[i])
if err == nil {
c.Lock()
c.mu.Lock()
if !c.connected {
log.Debugln(log.Global, ConnRe)
c.connected = true
}
c.Unlock()
c.mu.Unlock()
return
}
}
c.Lock()
c.mu.Lock()
if c.connected {
log.Warnln(log.Global, ConnLost)
c.connected = false
}
c.Unlock()
c.mu.Unlock()
}
// CheckDNS checks current dns for connectivity
@@ -185,8 +185,8 @@ func (c *Checker) CheckHost(host string) error {
// IsConnected returns if there is internet connectivity
func (c *Checker) IsConnected() bool {
c.Lock()
c.mu.Lock()
isConnected := c.connected
c.Unlock()
c.mu.Unlock()
return isConnected
}

View File

@@ -354,7 +354,11 @@ func TestBaseCode(t *testing.T) {
len(full.UnsetCurrency))
}
if full.LastMainUpdate.(int64) != -62135596800 {
lastMainUpdate, ok := full.LastMainUpdate.(int64)
if !ok {
t.Error("unable to type assert LastMainUpdate")
}
if lastMainUpdate != -62135596800 {
t.Errorf("BaseCode GetFullCurrencyData() error expected -62135596800 but received %d",
full.LastMainUpdate)
}

View File

@@ -75,9 +75,9 @@ func (c *Coinmarketcap) GetCryptocurrencyInfo(currencyID ...int64) (CryptoCurren
return resp.Data, err
}
var currStr []string
currStr := make([]string, len(currencyID))
for i := range currencyID {
currStr = append(currStr, strconv.FormatInt(currencyID[i], 10))
currStr[i] = strconv.FormatInt(currencyID[i], 10)
}
val := url.Values{}
@@ -315,9 +315,9 @@ func (c *Coinmarketcap) GetCryptocurrencyLatestQuotes(currencyID ...int64) (Cryp
return resp.Data, err
}
var currStr []string
for _, d := range currencyID {
currStr = append(currStr, strconv.FormatInt(d, 10))
currStr := make([]string, len(currencyID))
for i := range currencyID {
currStr[i] = strconv.FormatInt(currencyID[i], 10)
}
val := url.Values{}
@@ -387,9 +387,9 @@ func (c *Coinmarketcap) GetExchangeInfo(exchangeID ...int64) (ExchangeInfo, erro
return resp.Data, err
}
var exchStr []string
for _, d := range exchangeID {
exchStr = append(exchStr, strconv.FormatInt(d, 10))
exchStr := make([]string, len(exchangeID))
for x := range exchangeID {
exchStr[x] = strconv.FormatInt(exchangeID[x], 10)
}
val := url.Values{}
@@ -524,9 +524,9 @@ func (c *Coinmarketcap) GetExchangeLatestQuotes(exchangeID ...int64) (ExchangeLa
return resp.Data, err
}
var exchStr []string
for _, d := range exchangeID {
exchStr = append(exchStr, strconv.FormatInt(d, 10))
exchStr := make([]string, len(exchangeID))
for x := range exchangeID {
exchStr[x] = strconv.FormatInt(exchangeID[x], 10)
}
val := url.Values{}

View File

@@ -38,9 +38,9 @@ func (c *CurrencyConverter) GetRates(baseCurrency, symbols string) (map[string]f
return c.Convert(baseCurrency, symbols)
}
var completedStrings []string
completedStrings := make([]string, len(splitSymbols))
for x := range splitSymbols {
completedStrings = append(completedStrings, baseCurrency+"_"+splitSymbols[x])
completedStrings[x] = baseCurrency + "_" + splitSymbols[x]
}
if (c.APIKey != "" && c.APIKey != "Key") || len(completedStrings) == 2 {
@@ -126,7 +126,7 @@ func (c *CurrencyConverter) GetSupportedCurrencies() ([]string, error) {
return nil, err
}
var currencies []string
currencies := make([]string, 0, len(result.Results))
for key := range result.Results {
currencies = append(currencies, key)
}

View File

@@ -66,7 +66,7 @@ func (c *CurrencyLayer) GetSupportedCurrencies() ([]string, error) {
return nil, errors.New(resp.Error.Info)
}
var currencies []string
currencies := make([]string, 0, len(resp.Currencies))
for key := range resp.Currencies {
currencies = append(currencies, key)
}

View File

@@ -229,7 +229,7 @@ func (e *ExchangeRateHost) GetSupportedCurrencies() ([]string, error) {
return nil, err
}
var symbols []string
symbols := make([]string, 0, len(s.Symbols))
for x := range s.Symbols {
symbols = append(symbols, x)
}

View File

@@ -84,8 +84,7 @@ func TestGetSupportedSymbols(t *testing.T) {
if err != nil {
t.Fatal(err)
}
_, ok := r.Symbols["AUD"]
if !ok {
if _, ok := r.Symbols["AUD"]; !ok {
t.Error("should contain AUD")
}
}

View File

@@ -45,9 +45,10 @@ func (e *ExchangeRates) cleanCurrencies(baseCurrency, symbols string) string {
e.supportedCurrencies = supportedCurrencies
}
}
var cleanedCurrencies []string
symbols = strings.Replace(symbols, "RUR", "RUB", -1)
var s = strings.Split(symbols, ",")
cleanedCurrencies := make([]string, 0, len(s))
for _, x := range s {
// first make sure that the baseCurrency is not in the symbols list
// if it is set
@@ -244,7 +245,7 @@ func (e *ExchangeRates) GetSupportedCurrencies() ([]string, error) {
return nil, err
}
var supportedCurrencies []string
supportedCurrencies := make([]string, 0, len(symbols))
for x := range symbols {
supportedCurrencies = append(supportedCurrencies, x)
}

View File

@@ -55,7 +55,7 @@ func (f *Fixer) GetSupportedCurrencies() ([]string, error) {
return nil, errors.New(resp.Error.Type + resp.Error.Info)
}
var currencies []string
currencies := make([]string, 0, len(resp.Map))
for key := range resp.Map {
currencies = append(currencies, key)
}

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"time"
@@ -51,7 +51,7 @@ var (
func (s *Storage) SetDefaults() {
s.defaultBaseCurrency = USD
s.baseCurrency = s.defaultBaseCurrency
var fiatCurrencies []Code
fiatCurrencies := make([]Code, 0, len(symbols))
for item := range symbols {
if item == USDT.Item {
continue
@@ -125,7 +125,7 @@ func (s *Storage) RunUpdater(overrides BotOverrides, settings *Config, filePath
}
}
var fxSettings []base.Settings
fxSettings := make([]base.Settings, 0, len(settings.ForexProviders))
var primaryProvider bool
for i := range settings.ForexProviders {
enabled := (settings.ForexProviders[i].Name == "CurrencyConverter" && overrides.CurrencyConverter) ||
@@ -331,7 +331,7 @@ func (s *Storage) ForeignExchangeUpdater() {
// SeedCurrencyAnalysisData sets a new instance of a coinmarketcap data.
func (s *Storage) SeedCurrencyAnalysisData() error {
if s.currencyCodes.LastMainUpdate.IsZero() {
b, err := ioutil.ReadFile(s.path)
b, err := os.ReadFile(s.path)
if err != nil {
return s.FetchCurrencyAnalysisData()
}

View File

@@ -19,7 +19,7 @@ func Event(id, msgtype, message string) {
return
}
ctx := context.Background()
ctx := context.TODO()
ctx = boil.SkipTimestamps(ctx)
tx, err := database.DB.SQL.BeginTx(ctx, nil)
@@ -76,7 +76,7 @@ func GetEvent(startTime, endTime time.Time, order string, limit int) (interface{
orderByQuery := qm.OrderBy(orderByQueryString)
limitQuery := qm.Limit(limit)
ctx := context.Background()
ctx := context.TODO()
if repository.GetSQLDialect() == database.DBSQLite3 {
return modelSQLite.AuditEvents(query, orderByQuery, limitQuery).All(ctx, database.DB.SQL)
}

View File

@@ -45,7 +45,7 @@ func Series(exchangeName, base, quote string, interval int64, asset string, star
queries = append(queries, qm.Where("exchange_name_id = ?", exchangeUUID.String()))
if repository.GetSQLDialect() == database.DBSQLite3 {
queries = append(queries, qm.Where("timestamp between ? and ?", start.UTC().Format(time.RFC3339), end.UTC().Format(time.RFC3339)))
retCandle, errC := modelSQLite.Candles(queries...).All(context.Background(), database.DB.SQL)
retCandle, errC := modelSQLite.Candles(queries...).All(context.TODO(), database.DB.SQL)
if errC != nil {
return out, errC
}
@@ -68,7 +68,7 @@ func Series(exchangeName, base, quote string, interval int64, asset string, star
}
} else {
queries = append(queries, qm.Where("timestamp between ? and ?", start.UTC(), end.UTC()))
retCandle, errC := modelPSQL.Candles(queries...).All(context.Background(), database.DB.SQL)
retCandle, errC := modelPSQL.Candles(queries...).All(context.TODO(), database.DB.SQL)
if errC != nil {
return out, errC
}
@@ -108,7 +108,7 @@ func DeleteCandles(in *Item) (int64, error) {
return 0, errNoCandleData
}
ctx := context.Background()
ctx := context.TODO()
queries := []qm.QueryMod{
qm.Where("base = ?", strings.ToUpper(in.Base)),
qm.Where("quote = ?", strings.ToUpper(in.Quote)),
@@ -126,7 +126,7 @@ func DeleteCandles(in *Item) (int64, error) {
}
func deleteSQLite(ctx context.Context, queries []qm.QueryMod) (int64, error) {
retCandle, err := modelSQLite.Candles(queries...).All(context.Background(), database.DB.SQL)
retCandle, err := modelSQLite.Candles(queries...).All(ctx, database.DB.SQL)
if err != nil {
return 0, err
}
@@ -153,7 +153,7 @@ func deleteSQLite(ctx context.Context, queries []qm.QueryMod) (int64, error) {
}
func deletePostgres(ctx context.Context, queries []qm.QueryMod) (int64, error) {
retCandle, err := modelPSQL.Candles(queries...).All(context.Background(), database.DB.SQL)
retCandle, err := modelPSQL.Candles(queries...).All(ctx, database.DB.SQL)
if err != nil {
return 0, err
}
@@ -189,7 +189,7 @@ func Insert(in *Item) (uint64, error) {
return 0, errNoCandleData
}
ctx := context.Background()
ctx := context.TODO()
tx, err := database.DB.SQL.BeginTx(ctx, nil)
if err != nil {
return 0, err

View File

@@ -38,7 +38,7 @@ func Setup(db database.IDatabase) (*DBService, error) {
// Upsert inserts or updates jobs into the database
func (db *DBService) Upsert(jobs ...*DataHistoryJob) error {
ctx := context.Background()
ctx := context.TODO()
tx, err := db.sql.BeginTx(ctx, nil)
if err != nil {
@@ -156,7 +156,7 @@ func (db *DBService) GetPrerequisiteJob(nickname string) (*DataHistoryJob, error
// SetRelationshipByID removes a relationship in the event of a changed
// relationship during upsertion
func (db *DBService) SetRelationshipByID(prerequisiteJobID, followingJobID string, status int64) error {
ctx := context.Background()
ctx := context.TODO()
if strings.EqualFold(prerequisiteJobID, followingJobID) {
return errCannotSetSamePrerequisite
}
@@ -191,7 +191,7 @@ func (db *DBService) SetRelationshipByID(prerequisiteJobID, followingJobID strin
// SetRelationshipByNickname removes a relationship in the event of a changed
// relationship during upsertion
func (db *DBService) SetRelationshipByNickname(prerequisiteNickname, followingNickname string, status int64) error {
ctx := context.Background()
ctx := context.TODO()
if strings.EqualFold(prerequisiteNickname, followingNickname) {
return errCannotSetSamePrerequisite
}
@@ -331,7 +331,7 @@ func upsertPostgres(ctx context.Context, tx *sql.Tx, jobs ...*DataHistoryJob) er
return nil
}
func (db *DBService) getByNicknameSQLite(nickname string) (*DataHistoryJob, error) {
result, err := sqlite3.Datahistoryjobs(qm.Where("nickname = ?", strings.ToLower(nickname))).One(context.Background(), db.sql)
result, err := sqlite3.Datahistoryjobs(qm.Where("nickname = ?", strings.ToLower(nickname))).One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
@@ -341,7 +341,7 @@ func (db *DBService) getByNicknameSQLite(nickname string) (*DataHistoryJob, erro
func (db *DBService) getByNicknamePostgres(nickname string) (*DataHistoryJob, error) {
query := postgres.Datahistoryjobs(qm.Where("nickname = ?", strings.ToLower(nickname)))
result, err := query.One(context.Background(), db.sql)
result, err := query.One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
@@ -349,7 +349,7 @@ func (db *DBService) getByNicknamePostgres(nickname string) (*DataHistoryJob, er
}
func (db *DBService) getByIDSQLite(id string) (*DataHistoryJob, error) {
result, err := sqlite3.Datahistoryjobs(qm.Where("id = ?", id)).One(context.Background(), db.sql)
result, err := sqlite3.Datahistoryjobs(qm.Where("id = ?", id)).One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
@@ -359,7 +359,7 @@ func (db *DBService) getByIDSQLite(id string) (*DataHistoryJob, error) {
func (db *DBService) getByIDPostgres(id string) (*DataHistoryJob, error) {
query := postgres.Datahistoryjobs(qm.Where("id = ?", id))
result, err := query.One(context.Background(), db.sql)
result, err := query.One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
@@ -368,13 +368,13 @@ func (db *DBService) getByIDPostgres(id string) (*DataHistoryJob, error) {
}
func (db *DBService) getJobsBetweenSQLite(startDate, endDate time.Time) ([]DataHistoryJob, error) {
var jobs []DataHistoryJob
query := sqlite3.Datahistoryjobs(qm.Where("created BETWEEN ? AND ? ", startDate.UTC().Format(time.RFC3339), endDate.UTC().Format(time.RFC3339)))
results, err := query.All(context.Background(), db.sql)
results, err := query.All(context.TODO(), db.sql)
if err != nil {
return jobs, err
return nil, err
}
jobs := make([]DataHistoryJob, 0, len(results))
for i := range results {
job, err := db.createSQLiteDataHistoryJobResponse(results[i])
if err != nil {
@@ -387,13 +387,13 @@ func (db *DBService) getJobsBetweenSQLite(startDate, endDate time.Time) ([]DataH
}
func (db *DBService) getJobsBetweenPostgres(startDate, endDate time.Time) ([]DataHistoryJob, error) {
var jobs []DataHistoryJob
query := postgres.Datahistoryjobs(qm.Where("created BETWEEN ? AND ? ", startDate, endDate))
results, err := query.All(context.Background(), db.sql)
results, err := query.All(context.TODO(), db.sql)
if err != nil {
return jobs, err
return nil, err
}
jobs := make([]DataHistoryJob, 0, len(results))
for i := range results {
job, err := db.createPostgresDataHistoryJobResponse(results[i])
if err != nil {
@@ -410,7 +410,7 @@ func (db *DBService) getJobAndAllResultsSQLite(nickname string) (*DataHistoryJob
qm.Load(sqlite3.DatahistoryjobRels.JobDatahistoryjobresults),
qm.Load(sqlite3.DatahistoryjobRels.ExchangeName),
qm.Where("nickname = ?", strings.ToLower(nickname)))
result, err := query.One(context.Background(), db.sql)
result, err := query.One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
@@ -422,7 +422,7 @@ func (db *DBService) getJobAndAllResultsPostgres(nickname string) (*DataHistoryJ
query := postgres.Datahistoryjobs(
qm.Load(postgres.DatahistoryjobRels.JobDatahistoryjobresults),
qm.Where("nickname = ?", strings.ToLower(nickname)))
result, err := query.One(context.Background(), db.sql)
result, err := query.One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
@@ -435,12 +435,12 @@ func (db *DBService) getAllIncompleteJobsAndResultsSQLite() ([]DataHistoryJob, e
qm.Load(sqlite3.DatahistoryjobRels.ExchangeName),
qm.Load(sqlite3.DatahistoryjobRels.JobDatahistoryjobresults),
qm.Where("status = ?", 0))
results, err := query.All(context.Background(), db.sql)
results, err := query.All(context.TODO(), db.sql)
if err != nil {
return nil, err
}
var jobs []DataHistoryJob
jobs := make([]DataHistoryJob, 0, len(results))
for i := range results {
job, err := db.createSQLiteDataHistoryJobResponse(results[i])
if err != nil {
@@ -457,12 +457,12 @@ func (db *DBService) getAllIncompleteJobsAndResultsPostgres() ([]DataHistoryJob,
query := postgres.Datahistoryjobs(
qm.Load(postgres.DatahistoryjobRels.JobDatahistoryjobresults),
qm.Where("status = ?", 0))
results, err := query.All(context.Background(), db.sql)
results, err := query.All(context.TODO(), db.sql)
if err != nil {
return nil, err
}
var jobs []DataHistoryJob
jobs := make([]DataHistoryJob, 0, len(results))
for i := range results {
job, err := db.createPostgresDataHistoryJobResponse(results[i])
if err != nil {
@@ -475,15 +475,15 @@ func (db *DBService) getAllIncompleteJobsAndResultsPostgres() ([]DataHistoryJob,
}
func (db *DBService) getRelatedUpcomingJobsSQLite(nickname string) ([]*DataHistoryJob, error) {
job, err := sqlite3.Datahistoryjobs(qm.Where("nickname = ?", nickname)).One(context.Background(), db.sql)
job, err := sqlite3.Datahistoryjobs(qm.Where("nickname = ?", nickname)).One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
results, err := job.JobDatahistoryjobs().All(context.Background(), db.sql)
results, err := job.JobDatahistoryjobs().All(context.TODO(), db.sql)
if err != nil {
return nil, err
}
var resp []*DataHistoryJob
resp := make([]*DataHistoryJob, 0, len(results))
for i := range results {
job, err := db.createSQLiteDataHistoryJobResponse(results[i])
if err != nil {
@@ -496,11 +496,11 @@ func (db *DBService) getRelatedUpcomingJobsSQLite(nickname string) ([]*DataHisto
func (db *DBService) getRelatedUpcomingJobsPostgres(nickname string) ([]*DataHistoryJob, error) {
q := postgres.Datahistoryjobs(qm.Load(postgres.DatahistoryjobRels.JobDatahistoryjobs), qm.Where("nickname = ?", nickname))
jobWithRelations, err := q.One(context.Background(), db.sql)
jobWithRelations, err := q.One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
var response []*DataHistoryJob
response := make([]*DataHistoryJob, 0, len(jobWithRelations.R.JobDatahistoryjobs))
for i := range jobWithRelations.R.JobDatahistoryjobs {
job, err := db.getByIDPostgres(jobWithRelations.R.JobDatahistoryjobs[i].ID)
if err != nil {
@@ -556,11 +556,11 @@ func setRelationshipByIDPostgres(ctx context.Context, tx *sql.Tx, prerequisiteJo
}
func (db *DBService) getPrerequisiteJobSQLite(nickname string) (*DataHistoryJob, error) {
result, err := sqlite3.Datahistoryjobs(qm.Where("nickname = ?", nickname)).One(context.Background(), db.sql)
result, err := sqlite3.Datahistoryjobs(qm.Where("nickname = ?", nickname)).One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
job, err := result.PrerequisiteJobDatahistoryjobs().One(context.Background(), db.sql)
job, err := result.PrerequisiteJobDatahistoryjobs().One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
@@ -569,11 +569,11 @@ func (db *DBService) getPrerequisiteJobSQLite(nickname string) (*DataHistoryJob,
}
func (db *DBService) getPrerequisiteJobPostgres(nickname string) (*DataHistoryJob, error) {
job, err := postgres.Datahistoryjobs(qm.Where("nickname = ?", nickname)).One(context.Background(), db.sql)
job, err := postgres.Datahistoryjobs(qm.Where("nickname = ?", nickname)).One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
result, err := job.PrerequisiteJobDatahistoryjobs().One(context.Background(), db.sql)
result, err := job.PrerequisiteJobDatahistoryjobs().One(context.TODO(), db.sql)
if err != nil {
return nil, err
}
@@ -631,7 +631,7 @@ func (db *DBService) createSQLiteDataHistoryJobResponse(result *sqlite3.Datahist
if result.R != nil && result.R.ExchangeName != nil {
exchange = result.R.ExchangeName
} else {
exchange, err = result.ExchangeName().One(context.Background(), db.sql)
exchange, err = result.ExchangeName().One(context.TODO(), db.sql)
if err != nil {
return nil, fmt.Errorf("could not retrieve exchange '%v' %w", result.ExchangeNameID, err)
}
@@ -639,7 +639,7 @@ func (db *DBService) createSQLiteDataHistoryJobResponse(result *sqlite3.Datahist
var secondaryExchangeName string
if result.SecondaryExchangeID.String != "" {
var secondaryExchangeResult *sqlite3.Exchange
secondaryExchangeResult, err = result.SecondaryExchange().One(context.Background(), db.sql)
secondaryExchangeResult, err = result.SecondaryExchange().One(context.TODO(), db.sql)
if err != nil {
return nil, fmt.Errorf("could not retrieve secondary exchange '%v' %w", result.SecondaryExchangeID, err)
}
@@ -661,7 +661,7 @@ func (db *DBService) createSQLiteDataHistoryJobResponse(result *sqlite3.Datahist
return nil, err
}
prereqJob, err := result.PrerequisiteJobDatahistoryjobs().One(context.Background(), db.sql)
prereqJob, err := result.PrerequisiteJobDatahistoryjobs().One(context.TODO(), db.sql)
if err != nil && err != sql.ErrNoRows {
return nil, err
}
@@ -735,7 +735,7 @@ func (db *DBService) createPostgresDataHistoryJobResponse(result *postgres.Datah
if result.R != nil && result.R.ExchangeName != nil {
exchange = result.R.ExchangeName
} else {
exchange, err = result.ExchangeName().One(context.Background(), db.sql)
exchange, err = result.ExchangeName().One(context.TODO(), db.sql)
if err != nil {
return nil, fmt.Errorf("could not retrieve exchange '%v' %w", result.ExchangeNameID, err)
}
@@ -744,7 +744,7 @@ func (db *DBService) createPostgresDataHistoryJobResponse(result *postgres.Datah
var secondaryExchangeName string
if result.SecondaryExchangeID.String != "" {
var secondaryExchangeResult *postgres.Exchange
secondaryExchangeResult, err = result.SecondaryExchange().One(context.Background(), db.sql)
secondaryExchangeResult, err = result.SecondaryExchange().One(context.TODO(), db.sql)
if err != nil {
return nil, fmt.Errorf("could not retrieve secondary exchange '%v' %w", result.SecondaryExchangeID, err)
}
@@ -753,7 +753,7 @@ func (db *DBService) createPostgresDataHistoryJobResponse(result *postgres.Datah
}
}
prereqJob, err := result.PrerequisiteJobDatahistoryjobs().One(context.Background(), db.sql)
prereqJob, err := result.PrerequisiteJobDatahistoryjobs().One(context.TODO(), db.sql)
if err != nil && err != sql.ErrNoRows {
return nil, err
}

View File

@@ -40,7 +40,7 @@ func (db *DBService) Upsert(jobs ...*DataHistoryJobResult) error {
if len(jobs) == 0 {
return nil
}
ctx := context.Background()
ctx := context.TODO()
tx, err := db.sql.BeginTx(ctx, nil)
if err != nil {
@@ -165,11 +165,11 @@ func upsertPostgres(ctx context.Context, tx *sql.Tx, results ...*DataHistoryJobR
func (db *DBService) getByJobIDSQLite(jobID string) ([]DataHistoryJobResult, error) {
query := sqlite3.Datahistoryjobresults(qm.Where("job_id = ?", jobID))
results, err := query.All(context.Background(), db.sql)
results, err := query.All(context.TODO(), db.sql)
if err != nil {
return nil, err
}
var resp []DataHistoryJobResult
resp := make([]DataHistoryJobResult, len(results))
for i := range results {
var start, end, run time.Time
start, err = time.Parse(time.RFC3339, results[i].IntervalStartTime)
@@ -184,7 +184,7 @@ func (db *DBService) getByJobIDSQLite(jobID string) ([]DataHistoryJobResult, err
if err != nil {
return nil, err
}
resp = append(resp, DataHistoryJobResult{
resp[i] = DataHistoryJobResult{
ID: results[i].ID,
JobID: results[i].JobID,
IntervalStartDate: start,
@@ -192,7 +192,7 @@ func (db *DBService) getByJobIDSQLite(jobID string) ([]DataHistoryJobResult, err
Status: int64(results[i].Status),
Result: results[i].Result.String,
Date: run,
})
}
}
return resp, nil
@@ -200,13 +200,13 @@ func (db *DBService) getByJobIDSQLite(jobID string) ([]DataHistoryJobResult, err
func (db *DBService) getByJobIDPostgres(jobID string) ([]DataHistoryJobResult, error) {
query := postgres.Datahistoryjobresults(qm.Where("job_id = ?", jobID))
results, err := query.All(context.Background(), db.sql)
results, err := query.All(context.TODO(), db.sql)
if err != nil {
return nil, err
}
var resp []DataHistoryJobResult
resp := make([]DataHistoryJobResult, len(results))
for i := range results {
resp = append(resp, DataHistoryJobResult{
resp[i] = DataHistoryJobResult{
ID: results[i].ID,
JobID: results[i].JobID,
IntervalStartDate: results[i].IntervalStartTime,
@@ -214,20 +214,20 @@ func (db *DBService) getByJobIDPostgres(jobID string) ([]DataHistoryJobResult, e
Status: int64(results[i].Status),
Result: results[i].Result.String,
Date: results[i].RunTime,
})
}
}
return resp, nil
}
func (db *DBService) getJobResultsBetweenSQLite(jobID string, startDate, endDate time.Time) ([]DataHistoryJobResult, error) {
var results []DataHistoryJobResult
query := sqlite3.Datahistoryjobresults(qm.Where("job_id = ? AND run_time BETWEEN ? AND ? ", jobID, startDate.UTC().Format(time.RFC3339), endDate.UTC().Format(time.RFC3339)))
resp, err := query.All(context.Background(), db.sql)
resp, err := query.All(context.TODO(), db.sql)
if err != nil {
return results, err
return nil, err
}
results := make([]DataHistoryJobResult, len(resp))
for i := range resp {
var start, end, run time.Time
start, err = time.Parse(time.RFC3339, resp[i].IntervalStartTime)
@@ -242,7 +242,7 @@ func (db *DBService) getJobResultsBetweenSQLite(jobID string, startDate, endDate
if err != nil {
return nil, err
}
results = append(results, DataHistoryJobResult{
results[i] = DataHistoryJobResult{
ID: resp[i].ID,
JobID: resp[i].JobID,
IntervalStartDate: start,
@@ -250,22 +250,22 @@ func (db *DBService) getJobResultsBetweenSQLite(jobID string, startDate, endDate
Status: int64(resp[i].Status),
Result: resp[i].Result.String,
Date: run,
})
}
}
return results, nil
}
func (db *DBService) getJobResultsBetweenPostgres(jobID string, startDate, endDate time.Time) ([]DataHistoryJobResult, error) {
var jobs []DataHistoryJobResult
query := postgres.Datahistoryjobresults(qm.Where("job_id = ? AND run_time BETWEEN ? AND ? ", jobID, startDate, endDate))
results, err := query.All(context.Background(), db.sql)
results, err := query.All(context.TODO(), db.sql)
if err != nil {
return jobs, err
return nil, err
}
jobs := make([]DataHistoryJobResult, len(results))
for i := range results {
jobs = append(jobs, DataHistoryJobResult{
jobs[i] = DataHistoryJobResult{
ID: results[i].ID,
JobID: results[i].JobID,
IntervalStartDate: results[i].IntervalStartTime,
@@ -273,7 +273,7 @@ func (db *DBService) getJobResultsBetweenPostgres(jobID string, startDate, endDa
Status: int64(results[i].Status),
Result: results[i].Result.String,
Date: results[i].RunTime,
})
}
}
return jobs, nil

View File

@@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"encoding/csv"
"errors"
"io"
"os"
"strings"
@@ -37,7 +38,7 @@ func one(in, clause string) (out Details, err error) {
whereQM := qm.Where(clause+"= ?", in)
if repository.GetSQLDialect() == database.DBSQLite3 {
ret, errS := modelSQLite.Exchanges(whereQM).One(context.Background(), database.DB.SQL)
ret, errS := modelSQLite.Exchanges(whereQM).One(context.TODO(), database.DB.SQL)
if errS != nil {
return out, errS
}
@@ -47,7 +48,7 @@ func one(in, clause string) (out Details, err error) {
return out, errS
}
} else {
ret, errS := modelPSQL.Exchanges(whereQM).One(context.Background(), database.DB.SQL)
ret, errS := modelPSQL.Exchanges(whereQM).One(context.TODO(), database.DB.SQL)
if errS != nil {
return out, errS
}
@@ -67,7 +68,7 @@ func Insert(in Details) error {
return database.ErrDatabaseSupportDisabled
}
ctx := context.Background()
ctx := context.TODO()
tx, err := database.DB.SQL.BeginTx(ctx, nil)
if err != nil {
return err
@@ -100,7 +101,7 @@ func InsertMany(in []Details) error {
return database.ErrDatabaseSupportDisabled
}
ctx := context.Background()
ctx := context.TODO()
tx, err := database.DB.SQL.BeginTx(ctx, nil)
if err != nil {
return err
@@ -178,7 +179,11 @@ func UUIDByName(exchange string) (uuid.UUID, error) {
exchange = strings.ToLower(exchange)
v := exchangeCache.Get(exchange)
if v != nil {
return v.(uuid.UUID), nil
u, ok := v.(uuid.UUID)
if !ok {
return uuid.UUID{}, errors.New("unable to type assert uuid")
}
return u, nil
}
ret, err := One(exchange)
if err != nil {

View File

@@ -20,7 +20,7 @@ func Event(id, name, path string, data null.Bytes, executionType, status string,
return
}
ctx := context.Background()
ctx := context.TODO()
ctx = boil.SkipTimestamps(ctx)
tx, err := database.DB.SQL.BeginTx(ctx, nil)
if err != nil {

View File

@@ -34,7 +34,7 @@ func Insert(trades ...Data) error {
}
}
ctx := context.Background()
ctx := context.TODO()
ctx = boil.SkipTimestamps(ctx)
tx, err := database.DB.SQL.BeginTx(ctx, nil)
@@ -65,7 +65,7 @@ func Insert(trades ...Data) error {
// VerifyTradeInIntervals will query for ONE trade within each kline interval and verify if data exists
// if it does, it will set the range holder property "HasData" to true
func VerifyTradeInIntervals(exchangeName, assetType, base, quote string, irh *kline.IntervalRangeHolder) error {
ctx := context.Background()
ctx := context.TODO()
ctx = boil.SkipTimestamps(ctx)
tx, err := database.DB.SQL.BeginTx(ctx, nil)
@@ -237,7 +237,7 @@ func getByUUIDSQLite(uuid string) (Data, error) {
var td Data
var ts time.Time
query := sqlite3.Trades(qm.Where("id = ?", uuid))
result, err := query.One(context.Background(), database.DB.SQL)
result, err := query.One(context.TODO(), database.DB.SQL)
if err != nil {
return td, err
}
@@ -265,7 +265,7 @@ func getByUUIDSQLite(uuid string) (Data, error) {
func getByUUIDPostgres(uuid string) (td Data, err error) {
query := postgres.Trades(qm.Where("id = ?", uuid))
var result *postgres.Trade
result, err = query.One(context.Background(), database.DB.SQL)
result, err = query.One(context.TODO(), database.DB.SQL)
if err != nil {
return td, err
}
@@ -318,7 +318,7 @@ func getInRangeSQLite(exchangeName, assetType, base, quote string, startDate, en
q := generateQuery(wheres, startDate, endDate, true)
query := sqlite3.Trades(q...)
var result []*sqlite3.Trade
result, err = query.All(context.Background(), database.DB.SQL)
result, err = query.All(context.TODO(), database.DB.SQL)
if err != nil {
return td, err
}
@@ -361,7 +361,7 @@ func getInRangePostgres(exchangeName, assetType, base, quote string, startDate,
q := generateQuery(wheres, startDate, endDate, false)
query := postgres.Trades(q...)
var result []*postgres.Trade
result, err = query.All(context.Background(), database.DB.SQL)
result, err = query.All(context.TODO(), database.DB.SQL)
if err != nil {
return td, err
}
@@ -386,7 +386,7 @@ func getInRangePostgres(exchangeName, assetType, base, quote string, startDate,
// DeleteTrades will remove trades from the database using trade.Data
func DeleteTrades(trades ...Data) error {
ctx := context.Background()
ctx := context.TODO()
ctx = boil.SkipTimestamps(ctx)
tx, err := database.DB.SQL.BeginTx(ctx, nil)
@@ -402,9 +402,9 @@ func DeleteTrades(trades ...Data) error {
}
}()
if repository.GetSQLDialect() == database.DBSQLite3 || repository.GetSQLDialect() == database.DBSQLite {
err = deleteTradesSQLite(context.Background(), tx, trades...)
err = deleteTradesSQLite(context.TODO(), tx, trades...)
} else {
err = deleteTradesPostgres(context.Background(), tx, trades...)
err = deleteTradesPostgres(context.TODO(), tx, trades...)
}
if err != nil {
return err
@@ -414,9 +414,9 @@ func DeleteTrades(trades ...Data) error {
}
func deleteTradesSQLite(ctx context.Context, tx *sql.Tx, trades ...Data) error {
var tradeIDs []interface{}
tradeIDs := make([]interface{}, len(trades))
for i := range trades {
tradeIDs = append(tradeIDs, trades[i].ID)
tradeIDs[i] = trades[i].ID
}
query := sqlite3.Trades(qm.WhereIn(`id in ?`, tradeIDs...))
_, err := query.DeleteAll(ctx, tx)
@@ -424,9 +424,9 @@ func deleteTradesSQLite(ctx context.Context, tx *sql.Tx, trades ...Data) error {
}
func deleteTradesPostgres(ctx context.Context, tx *sql.Tx, trades ...Data) error {
var tradeIDs []interface{}
tradeIDs := make([]interface{}, len(trades))
for i := range trades {
tradeIDs = append(tradeIDs, trades[i].ID)
tradeIDs[i] = trades[i].ID
}
query := postgres.Trades(qm.WhereIn(`id in ?`, tradeIDs...))
_, err := query.DeleteAll(ctx, tx)

View File

@@ -267,7 +267,11 @@ func GetEventsByDate(exchange string, start, end time.Time, limit int) ([]*withd
}
func generateWhereQuery(columns, id []string, limit int) []qm.QueryMod {
var queries []qm.QueryMod
x := len(columns)
if limit > 0 {
x++
}
queries := make([]qm.QueryMod, 0, x)
if limit > 0 {
queries = append(queries, qm.Limit(limit))
}

View File

@@ -285,11 +285,11 @@ func (d *Dispatcher) subscribe(id uuid.UUID) (chan interface{}, error) {
// Read lock to read route list
d.rMtx.RLock()
_, ok := d.routes[id]
d.rMtx.RUnlock()
if !ok {
if _, ok := d.routes[id]; !ok {
d.rMtx.RUnlock()
return nil, errors.New("dispatcher uuid not found in route list")
}
d.rMtx.RUnlock()
// Get an unused channel from the channel pool
unusedChan, ok := d.outbound.Get().(chan interface{})
@@ -314,11 +314,11 @@ func (d *Dispatcher) unsubscribe(id uuid.UUID, usedChan chan interface{}) error
// Read lock to read route list
d.rMtx.RLock()
_, ok := d.routes[id]
d.rMtx.RUnlock()
if !ok {
if _, ok := d.routes[id]; !ok {
d.rMtx.RUnlock()
return errors.New("dispatcher uuid does not reference any channels")
}
d.rMtx.RUnlock()
// Lock for write to delete references
d.rMtx.Lock()

View File

@@ -71,7 +71,6 @@ type job struct {
type Mux struct {
// Reference to the main running dispatch service
d *Dispatcher
sync.RWMutex
}
// Pipe defines an outbound object to the desired routine

View File

@@ -112,8 +112,8 @@ func (m *apiServerManager) newRouter(isREST bool) *mux.Router {
if common.ExtractPort(m.websocketListenAddress) == 80 {
m.websocketListenAddress = common.ExtractHost(m.websocketListenAddress)
} else {
m.websocketListenAddress = strings.Join([]string{common.ExtractHost(m.websocketListenAddress),
strconv.Itoa(common.ExtractPort(m.websocketListenAddress))}, ":")
m.websocketListenAddress = common.ExtractHost(m.websocketListenAddress) + ":" +
strconv.Itoa(common.ExtractPort(m.websocketListenAddress))
}
if isREST {
@@ -302,11 +302,13 @@ func (m *apiServerManager) getIndex(w http.ResponseWriter, _ *http.Request) {
// getAllActiveOrderbooks returns all enabled exchanges orderbooks
func getAllActiveOrderbooks(m iExchangeManager) []EnabledExchangeOrderbooks {
var orderbookData []EnabledExchangeOrderbooks
exchanges, err := m.GetExchanges()
if err != nil {
log.Errorf(log.APIServerMgr, "Cannot get exchanges: %v", err)
return nil
}
orderbookData := make([]EnabledExchangeOrderbooks, 0, len(exchanges))
for x := range exchanges {
assets := exchanges[x].GetAssetTypes(true)
exchName := exchanges[x].GetName()
@@ -342,11 +344,13 @@ func getAllActiveOrderbooks(m iExchangeManager) []EnabledExchangeOrderbooks {
// getAllActiveTickers returns all enabled exchanges tickers
func getAllActiveTickers(m iExchangeManager) []EnabledExchangeCurrencies {
var tickers []EnabledExchangeCurrencies
exchanges, err := m.GetExchanges()
if err != nil {
log.Errorf(log.APIServerMgr, "Cannot get exchanges: %v", err)
return nil
}
tickers := make([]EnabledExchangeCurrencies, 0, len(exchanges))
for x := range exchanges {
assets := exchanges[x].GetAssetTypes(true)
exchName := exchanges[x].GetName()
@@ -382,11 +386,13 @@ func getAllActiveTickers(m iExchangeManager) []EnabledExchangeCurrencies {
// getAllActiveAccounts returns all enabled exchanges accounts
func getAllActiveAccounts(m iExchangeManager) []AllEnabledExchangeAccounts {
var accounts []AllEnabledExchangeAccounts
exchanges, err := m.GetExchanges()
if err != nil {
log.Errorf(log.APIServerMgr, "Cannot get exchanges: %v", err)
return nil
}
accounts := make([]AllEnabledExchangeAccounts, 0, len(exchanges))
for x := range exchanges {
assets := exchanges[x].GetAssetTypes(true)
exchName := exchanges[x].GetName()
@@ -680,12 +686,17 @@ func (m *apiServerManager) WebsocketClientHandler(w http.ResponseWriter, r *http
}
func wsAuth(client *websocketClient, data interface{}) error {
d, ok := data.([]byte)
if !ok {
return errors.New("unable to type assert data")
}
wsResp := WebsocketEventResponse{
Event: "auth",
}
var auth WebsocketAuth
err := json.Unmarshal(data.([]byte), &auth)
err := json.Unmarshal(d, &auth)
if err != nil {
wsResp.Error = err.Error()
sendErr := client.SendWebsocketMessage(wsResp)
@@ -738,11 +749,16 @@ func wsGetConfig(client *websocketClient, _ interface{}) error {
}
func wsSaveConfig(client *websocketClient, data interface{}) error {
d, ok := data.([]byte)
if !ok {
return errors.New("unable to type assert data")
}
wsResp := WebsocketEventResponse{
Event: "SaveConfig",
}
var respCfg config.Config
err := json.Unmarshal(data.([]byte), &respCfg)
err := json.Unmarshal(d, &respCfg)
if err != nil {
wsResp.Error = err.Error()
sendErr := client.SendWebsocketMessage(wsResp)
@@ -794,11 +810,16 @@ func wsGetTickers(client *websocketClient, data interface{}) error {
}
func wsGetTicker(client *websocketClient, data interface{}) error {
d, ok := data.([]byte)
if !ok {
return errors.New("unable to type assert data")
}
wsResp := WebsocketEventResponse{
Event: "GetTicker",
}
var tickerReq WebsocketOrderbookTickerRequest
err := json.Unmarshal(data.([]byte), &tickerReq)
err := json.Unmarshal(d, &tickerReq)
if err != nil {
wsResp.Error = err.Error()
sendErr := client.SendWebsocketMessage(wsResp)
@@ -849,11 +870,16 @@ func wsGetOrderbooks(client *websocketClient, data interface{}) error {
}
func wsGetOrderbook(client *websocketClient, data interface{}) error {
d, ok := data.([]byte)
if !ok {
return errors.New("unable to type assert data")
}
wsResp := WebsocketEventResponse{
Event: "GetOrderbook",
}
var orderbookReq WebsocketOrderbookTickerRequest
err := json.Unmarshal(data.([]byte), &orderbookReq)
err := json.Unmarshal(d, &orderbookReq)
if err != nil {
wsResp.Error = err.Error()
sendErr := client.SendWebsocketMessage(wsResp)

View File

@@ -3,7 +3,7 @@ package engine
import (
"encoding/json"
"errors"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
@@ -253,7 +253,7 @@ func TestConfigAllJsonResponse(t *testing.T) {
t.Error(err)
}
resp := makeHTTPGetRequest(t, c)
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Error("Body not readable", err)
}

View File

@@ -121,7 +121,7 @@ func (m *DataHistoryManager) retrieveJobs() ([]*DataHistoryJob, error) {
return nil, err
}
var response []*DataHistoryJob
response := make([]*DataHistoryJob, 0, len(dbJobs))
for i := range dbJobs {
dbJob, err := m.convertDBModelToJob(&dbJobs[i])
if err != nil {
@@ -1332,13 +1332,13 @@ func (m *DataHistoryManager) GetAllJobStatusBetween(start, end time.Time) ([]*Da
if err != nil {
return nil, err
}
var results []*DataHistoryJob
results := make([]*DataHistoryJob, len(dbJobs))
for i := range dbJobs {
dbJob, err := m.convertDBModelToJob(&dbJobs[i])
if err != nil {
return nil, err
}
results = append(results, dbJob)
results[i] = dbJob
}
return results, nil
}

View File

@@ -82,7 +82,7 @@ func (m *ExchangeManager) GetExchanges() ([]exchange.IBotExchange, error) {
}
m.m.Lock()
defer m.m.Unlock()
var exchs []exchange.IBotExchange
exchs := make([]exchange.IBotExchange, 0, len(m.exchanges))
for _, x := range m.exchanges {
exchs = append(exchs, x)
}

View File

@@ -44,7 +44,7 @@ func TestExchangeManagerGetExchanges(t *testing.T) {
if err != nil {
t.Error("no exchange manager found")
}
if exchanges != nil {
if len(exchanges) != 0 {
t.Error("unexpected value")
}
b := new(bitfinex.Bitfinex)

View File

@@ -10,7 +10,6 @@ import (
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"math/big"
"net"
"os"
@@ -326,8 +325,8 @@ func (bot *Engine) GetExchangeOTPByName(exchName string) (string, error) {
// GetAuthAPISupportedExchanges returns a list of auth api enabled exchanges
func (bot *Engine) GetAuthAPISupportedExchanges() []string {
var exchangeNames []string
exchanges := bot.GetExchanges()
exchangeNames := make([]string, 0, len(exchanges))
for x := range exchanges {
if !exchanges[x].GetAuthenticatedAPISupport(exchange.RestAuthentication) &&
!exchanges[x].GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
@@ -443,7 +442,7 @@ func (bot *Engine) MapCurrenciesByExchange(p currency.Pairs, enabledExchangesOnl
// GetExchangeNamesByCurrency returns a list of exchanges supporting
// a currency pair based on whether the exchange is enabled or not
func (bot *Engine) GetExchangeNamesByCurrency(p currency.Pair, enabled bool, assetType asset.Item) []string {
var exchanges []string
exchanges := make([]string, 0, len(bot.Config.Exchanges))
for x := range bot.Config.Exchanges {
if enabled != bot.Config.Exchanges[x].Enabled {
continue
@@ -862,7 +861,7 @@ func checkCerts(certDir string) error {
return genCert(certDir)
}
pemData, err := ioutil.ReadFile(certFile)
pemData, err := os.ReadFile(certFile)
if err != nil {
return fmt.Errorf("unable to open TLS cert file: %s", err)
}

View File

@@ -755,12 +755,9 @@ func TestGetSpecificOrderbook(t *testing.T) {
t.Parallel()
e := CreateTestBot(t)
var bids []orderbook.Item
bids = append(bids, orderbook.Item{Price: 1000, Amount: 1})
base := orderbook.Base{
Pair: currency.NewPair(currency.BTC, currency.USD),
Bids: bids,
Bids: []orderbook.Item{{Price: 1000, Amount: 1}},
Exchange: "Bitstamp",
Asset: asset.Spot,
}

View File

@@ -383,8 +383,7 @@ func TestExists(t *testing.T) {
if err := m.orderStore.add(o); err != nil {
t.Error(err)
}
b := m.orderStore.exists(o)
if !b {
if b := m.orderStore.exists(o); !b {
t.Error("Expected true")
}
}

View File

@@ -240,7 +240,7 @@ func (m *portfolioManager) seedExchangeAccountInfo(accounts []account.Holdings)
// getExchangeAccountInfo returns all the current enabled exchanges
func (m *portfolioManager) getExchangeAccountInfo(exchanges []exchange.IBotExchange) []account.Holdings {
var response []account.Holdings
response := make([]account.Holdings, 0, len(exchanges))
for x := range exchanges {
if exchanges[x] == nil || !exchanges[x].IsEnabled() {
continue

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
@@ -398,15 +397,16 @@ func (s *RPCServer) GetTicker(ctx context.Context, r *gctrpc.GetTickerRequest) (
// enabled currency pairs
func (s *RPCServer) GetTickers(ctx context.Context, _ *gctrpc.GetTickersRequest) (*gctrpc.GetTickersResponse, error) {
activeTickers := s.GetAllActiveTickers(ctx)
var tickers []*gctrpc.Tickers
tickers := make([]*gctrpc.Tickers, len(activeTickers))
for x := range activeTickers {
t := &gctrpc.Tickers{
Exchange: activeTickers[x].ExchangeName,
Tickers: make([]*gctrpc.TickerResponse, len(activeTickers[x].ExchangeValues)),
}
for y := range activeTickers[x].ExchangeValues {
val := activeTickers[x].ExchangeValues[y]
t.Tickers = append(t.Tickers, &gctrpc.TickerResponse{
t.Tickers[y] = &gctrpc.TickerResponse{
Pair: &gctrpc.CurrencyPair{
Delimiter: val.Pair.Delimiter,
Base: val.Pair.Base.String(),
@@ -420,9 +420,9 @@ func (s *RPCServer) GetTickers(ctx context.Context, _ *gctrpc.GetTickersRequest)
Ask: val.Ask,
Volume: val.Volume,
PriceAth: val.PriceATH,
})
}
}
tickers = append(tickers, t)
tickers[x] = t
}
return &gctrpc.GetTickersResponse{Tickers: tickers}, nil
@@ -489,7 +489,7 @@ func (s *RPCServer) GetOrderbooks(ctx context.Context, _ *gctrpc.GetOrderbooksRe
if err != nil {
return nil, err
}
var obResponse []*gctrpc.Orderbooks
obResponse := make([]*gctrpc.Orderbooks, 0, len(exchanges))
var obs []*gctrpc.OrderbookResponse
for x := range exchanges {
if !exchanges[x].IsEnabled() {
@@ -523,19 +523,20 @@ func (s *RPCServer) GetOrderbooks(ctx context.Context, _ *gctrpc.GetOrderbooksRe
},
AssetType: assets[y].String(),
LastUpdated: s.unixTimestamp(resp.LastUpdated),
Bids: make([]*gctrpc.OrderbookItem, len(resp.Bids)),
Asks: make([]*gctrpc.OrderbookItem, len(resp.Asks)),
}
for i := range resp.Bids {
ob.Bids = append(ob.Bids, &gctrpc.OrderbookItem{
ob.Bids[i] = &gctrpc.OrderbookItem{
Amount: resp.Bids[i].Amount,
Price: resp.Bids[i].Price,
})
}
}
for i := range resp.Asks {
ob.Asks = append(ob.Asks, &gctrpc.OrderbookItem{
ob.Asks[i] = &gctrpc.OrderbookItem{
Amount: resp.Asks[i].Amount,
Price: resp.Asks[i].Price,
})
}
}
obs = append(obs, ob)
}
@@ -600,7 +601,7 @@ func (s *RPCServer) UpdateAccountInfo(ctx context.Context, r *gctrpc.GetAccountI
}
func createAccountInfoRequest(h account.Holdings) (*gctrpc.GetAccountInfoResponse, error) {
var accounts []*gctrpc.Account
accounts := make([]*gctrpc.Account, len(h.Accounts))
for x := range h.Accounts {
var a gctrpc.Account
a.Id = h.Accounts[x].ID
@@ -621,7 +622,7 @@ func createAccountInfoRequest(h account.Holdings) (*gctrpc.GetAccountInfoRespons
Borrowed: y.Borrowed,
})
}
accounts = append(accounts, &a)
accounts[x] = &a
}
return &gctrpc.GetAccountInfoResponse{Exchange: h.Exchange, Accounts: accounts}, nil
@@ -649,20 +650,20 @@ func (s *RPCServer) GetAccountInfoStream(r *gctrpc.GetAccountInfoRequest, stream
return err
}
var accounts []*gctrpc.Account
accounts := make([]*gctrpc.Account, len(initAcc.Accounts))
for x := range initAcc.Accounts {
var subAccounts []*gctrpc.AccountCurrencyInfo
subAccounts := make([]*gctrpc.AccountCurrencyInfo, len(initAcc.Accounts[x].Currencies))
for y := range initAcc.Accounts[x].Currencies {
subAccounts = append(subAccounts, &gctrpc.AccountCurrencyInfo{
subAccounts[y] = &gctrpc.AccountCurrencyInfo{
Currency: initAcc.Accounts[x].Currencies[y].CurrencyName.String(),
TotalValue: initAcc.Accounts[x].Currencies[y].Total,
Hold: initAcc.Accounts[x].Currencies[y].Hold,
})
}
}
accounts = append(accounts, &gctrpc.Account{
accounts[x] = &gctrpc.Account{
Id: initAcc.Accounts[x].ID,
Currencies: subAccounts,
})
}
}
err = stream.Send(&gctrpc.GetAccountInfoResponse{
@@ -691,37 +692,37 @@ func (s *RPCServer) GetAccountInfoStream(r *gctrpc.GetAccountInfoRequest, stream
return errDispatchSystem
}
d := *data.(*interface{})
if d == nil {
d, ok := data.(*interface{})
if !ok {
return errors.New("unable to type assert data")
}
acc, ok := d.(account.Holdings)
dd := *d
acc, ok := dd.(account.Holdings)
if !ok {
return errors.New("unable to type assert account holdings data")
}
var accounts []*gctrpc.Account
accounts := make([]*gctrpc.Account, len(acc.Accounts))
for x := range acc.Accounts {
var subAccounts []*gctrpc.AccountCurrencyInfo
subAccounts := make([]*gctrpc.AccountCurrencyInfo, len(acc.Accounts[x].Currencies))
for y := range acc.Accounts[x].Currencies {
subAccounts = append(subAccounts, &gctrpc.AccountCurrencyInfo{
subAccounts[y] = &gctrpc.AccountCurrencyInfo{
Currency: acc.Accounts[x].Currencies[y].CurrencyName.String(),
TotalValue: acc.Accounts[x].Currencies[y].Total,
Hold: acc.Accounts[x].Currencies[y].Hold,
})
}
}
accounts = append(accounts, &gctrpc.Account{
accounts[x] = &gctrpc.Account{
Id: acc.Accounts[x].ID,
Currencies: subAccounts,
})
}
}
err := stream.Send(&gctrpc.GetAccountInfoResponse{
if err := stream.Send(&gctrpc.GetAccountInfoResponse{
Exchange: acc.Exchange,
Accounts: accounts,
})
if err != nil {
}); err != nil {
return err
}
}
@@ -734,15 +735,15 @@ func (s *RPCServer) GetConfig(_ context.Context, _ *gctrpc.GetConfigRequest) (*g
// GetPortfolio returns the portfoliomanager details
func (s *RPCServer) GetPortfolio(_ context.Context, _ *gctrpc.GetPortfolioRequest) (*gctrpc.GetPortfolioResponse, error) {
var addrs []*gctrpc.PortfolioAddress
botAddrs := s.portfolioManager.GetAddresses()
addrs := make([]*gctrpc.PortfolioAddress, len(botAddrs))
for x := range botAddrs {
addrs = append(addrs, &gctrpc.PortfolioAddress{
addrs[x] = &gctrpc.PortfolioAddress{
Address: botAddrs[x].Address,
CoinType: botAddrs[x].CoinType.String(),
Description: botAddrs[x].Description,
Balance: botAddrs[x].Balance,
})
}
}
resp := &gctrpc.GetPortfolioResponse{
@@ -838,9 +839,9 @@ func (s *RPCServer) GetForexProviders(_ context.Context, _ *gctrpc.GetForexProvi
return nil, fmt.Errorf("forex providers is empty")
}
var forexProviders []*gctrpc.ForexProvider
forexProviders := make([]*gctrpc.ForexProvider, len(providers))
for x := range providers {
forexProviders = append(forexProviders, &gctrpc.ForexProvider{
forexProviders[x] = &gctrpc.ForexProvider{
Name: providers[x].Name,
Enabled: providers[x].Enabled,
Verbose: providers[x].Verbose,
@@ -848,7 +849,7 @@ func (s *RPCServer) GetForexProviders(_ context.Context, _ *gctrpc.GetForexProvi
ApiKey: providers[x].APIKey,
ApiKeyLevel: int64(providers[x].APIKeyLvl),
PrimaryProvider: providers[x].PrimaryProvider,
})
}
}
return &gctrpc.GetForexProvidersResponse{ForexProviders: forexProviders}, nil
}
@@ -864,7 +865,7 @@ func (s *RPCServer) GetForexRates(_ context.Context, _ *gctrpc.GetForexRatesRequ
return nil, fmt.Errorf("forex rates is empty")
}
var forexRates []*gctrpc.ForexRatesConversion
forexRates := make([]*gctrpc.ForexRatesConversion, 0, len(rates))
for x := range rates {
rate, err := rates[x].GetRate()
if err != nil {
@@ -952,9 +953,9 @@ func (s *RPCServer) GetOrders(ctx context.Context, r *gctrpc.GetOrdersRequest) (
return nil, err
}
var orders []*gctrpc.OrderDetails
orders := make([]*gctrpc.OrderDetails, len(resp))
for x := range resp {
var trades []*gctrpc.TradeHistory
trades := make([]*gctrpc.TradeHistory, len(resp[x].Trades))
for i := range resp[x].Trades {
t := &gctrpc.TradeHistory{
Id: resp[x].Trades[i].TID,
@@ -969,7 +970,7 @@ func (s *RPCServer) GetOrders(ctx context.Context, r *gctrpc.GetOrdersRequest) (
if !resp[x].Trades[i].Timestamp.IsZero() {
t.CreationTime = s.unixTimestamp(resp[x].Trades[i].Timestamp)
}
trades = append(trades, t)
trades[i] = t
}
o := &gctrpc.OrderDetails{
Exchange: r.Exchange,
@@ -994,7 +995,7 @@ func (s *RPCServer) GetOrders(ctx context.Context, r *gctrpc.GetOrdersRequest) (
if !resp[x].LastUpdated.IsZero() {
o.UpdateTime = s.unixTimestamp(resp[x].LastUpdated)
}
orders = append(orders, o)
orders[x] = o
}
return &gctrpc.GetOrdersResponse{Orders: orders}, nil
@@ -1041,9 +1042,9 @@ func (s *RPCServer) GetManagedOrders(_ context.Context, r *gctrpc.GetOrdersReque
return nil, err
}
var orders []*gctrpc.OrderDetails
orders := make([]*gctrpc.OrderDetails, len(resp))
for x := range resp {
var trades []*gctrpc.TradeHistory
trades := make([]*gctrpc.TradeHistory, len(resp[x].Trades))
for i := range resp[x].Trades {
t := &gctrpc.TradeHistory{
Id: resp[x].Trades[i].TID,
@@ -1058,7 +1059,7 @@ func (s *RPCServer) GetManagedOrders(_ context.Context, r *gctrpc.GetOrdersReque
if !resp[x].Trades[i].Timestamp.IsZero() {
t.CreationTime = s.unixTimestamp(resp[x].Trades[i].Timestamp)
}
trades = append(trades, t)
trades[i] = t
}
o := &gctrpc.OrderDetails{
Exchange: r.Exchange,
@@ -1083,7 +1084,7 @@ func (s *RPCServer) GetManagedOrders(_ context.Context, r *gctrpc.GetOrdersReque
if !resp[x].LastUpdated.IsZero() {
o.UpdateTime = s.unixTimestamp(resp[x].LastUpdated)
}
orders = append(orders, o)
orders[x] = o
}
return &gctrpc.GetOrdersResponse{Orders: orders}, nil
@@ -1128,9 +1129,9 @@ func (s *RPCServer) GetOrder(ctx context.Context, r *gctrpc.GetOrderRequest) (*g
if err != nil {
return nil, fmt.Errorf("error whilst trying to retrieve info for order %s: %w", r.OrderId, err)
}
var trades []*gctrpc.TradeHistory
trades := make([]*gctrpc.TradeHistory, len(result.Trades))
for i := range result.Trades {
trades = append(trades, &gctrpc.TradeHistory{
trades[i] = &gctrpc.TradeHistory{
CreationTime: s.unixTimestamp(result.Trades[i].Timestamp),
Id: result.Trades[i].TID,
Price: result.Trades[i].Price,
@@ -1140,7 +1141,7 @@ func (s *RPCServer) GetOrder(ctx context.Context, r *gctrpc.GetOrderRequest) (*g
OrderSide: result.Trades[i].Side.String(),
Fee: result.Trades[i].Fee,
Total: result.Trades[i].Total,
})
}
}
var creationTime, updateTime int64
@@ -1217,14 +1218,14 @@ func (s *RPCServer) SubmitOrder(ctx context.Context, r *gctrpc.SubmitOrderReques
return &gctrpc.SubmitOrderResponse{}, err
}
var trades []*gctrpc.Trades
trades := make([]*gctrpc.Trades, len(resp.Trades))
for i := range resp.Trades {
trades = append(trades, &gctrpc.Trades{
trades[i] = &gctrpc.Trades{
Amount: resp.Trades[i].Amount,
Price: resp.Trades[i].Price,
Fee: resp.Trades[i].Fee,
FeeAsset: resp.Trades[i].FeeAsset,
})
}
}
return &gctrpc.SubmitOrderResponse{
@@ -1408,18 +1409,19 @@ func (s *RPCServer) CancelBatchOrders(ctx context.Context, r *gctrpc.CancelBatch
}
status := make(map[string]string)
var request []order.Cancel
orders := strings.Split(r.OrdersId, ",")
for _, orderID := range orders {
request := make([]order.Cancel, len(orders))
for x := range orders {
orderID := orders[x]
status[orderID] = order.Cancelled.String()
request = append(request, order.Cancel{
request[x] = order.Cancel{
AccountID: r.AccountId,
ID: orderID,
Side: order.Side(r.Side),
WalletAddress: r.WalletAddress,
Pair: pair,
AssetType: assetType,
})
}
}
// TODO: Change to order manager
@@ -2118,12 +2120,13 @@ func (s *RPCServer) GetExchangeOrderbookStream(r *gctrpc.GetExchangeOrderbookStr
return errDispatchSystem
}
d := *data.(*interface{})
if d == nil {
d, ok := data.(*interface{})
if !ok {
return errors.New("unable to type assert data")
}
ob, ok := d.(orderbook.Base)
dd := *d
ob, ok := dd.(orderbook.Base)
if !ok {
return errors.New("unable to type assert orderbook data")
}
@@ -2201,12 +2204,13 @@ func (s *RPCServer) GetTickerStream(r *gctrpc.GetTickerStreamRequest, stream gct
return errDispatchSystem
}
d := *data.(*interface{})
if d == nil {
d, ok := data.(*interface{})
if !ok {
return errors.New("unable to type assert data")
}
t, ok := d.(ticker.Price)
dd := *d
t, ok := dd.(ticker.Price)
if !ok {
return errors.New("unable to type assert ticker data")
}
@@ -2259,12 +2263,13 @@ func (s *RPCServer) GetExchangeTickerStream(r *gctrpc.GetExchangeTickerStreamReq
return errDispatchSystem
}
d := *data.(*interface{})
if d == nil {
d, ok := data.(*interface{})
if !ok {
return errors.New("unable to type assert data")
}
t, ok := d.(ticker.Price)
dd := *d
t, ok := dd.(ticker.Price)
if !ok {
return errors.New("unable to type assert ticker data")
}
@@ -2453,16 +2458,16 @@ func (s *RPCServer) GetHistoricCandles(ctx context.Context, r *gctrpc.GetHistori
}
func fillMissingCandlesWithStoredTrades(startTime, endTime time.Time, klineItem *kline.Item) (*kline.Item, error) {
var response kline.Item
var candleTimes []time.Time
candleTimes := make([]time.Time, len(klineItem.Candles))
for i := range klineItem.Candles {
candleTimes = append(candleTimes, klineItem.Candles[i].Time)
candleTimes[i] = klineItem.Candles[i].Time
}
ranges, err := timeperiods.FindTimeRangesContainingData(startTime, endTime, klineItem.Interval.Duration(), candleTimes)
if err != nil {
return nil, err
}
var response kline.Item
for i := range ranges {
if ranges[i].HasDataInRange {
continue
@@ -2552,24 +2557,30 @@ func (s *RPCServer) GCTScriptQuery(_ context.Context, r *gctrpc.GCTScriptQueryRe
return &gctrpc.GCTScriptQueryResponse{Status: MsgStatusError, Data: err.Error()}, nil
}
if v, f := gctscript.AllVMSync.Load(UUID); f {
resp := &gctrpc.GCTScriptQueryResponse{
Status: MsgStatusOK,
Script: &gctrpc.GCTScript{
Name: v.(*gctscript.VM).ShortName(),
UUID: v.(*gctscript.VM).ID.String(),
Path: v.(*gctscript.VM).Path,
NextRun: v.(*gctscript.VM).NextRun.String(),
},
}
data, err := v.(*gctscript.VM).Read()
if err != nil {
return nil, err
}
resp.Data = string(data)
return resp, nil
v, f := gctscript.AllVMSync.Load(UUID)
if !f {
return &gctrpc.GCTScriptQueryResponse{Status: MsgStatusError, Data: "UUID not found"}, nil
}
return &gctrpc.GCTScriptQueryResponse{Status: MsgStatusError, Data: "UUID not found"}, nil
vm, ok := v.(*gctscript.VM)
if !ok {
return nil, errors.New("unable to type assert gctscript.VM")
}
resp := &gctrpc.GCTScriptQueryResponse{
Status: MsgStatusOK,
Script: &gctrpc.GCTScript{
Name: vm.ShortName(),
UUID: vm.ID.String(),
Path: vm.Path,
NextRun: vm.NextRun.String(),
},
}
data, err := vm.Read()
if err != nil {
return nil, err
}
resp.Data = string(data)
return resp, nil
}
// GCTScriptExecute execute a script
@@ -2614,15 +2625,21 @@ func (s *RPCServer) GCTScriptStop(_ context.Context, r *gctrpc.GCTScriptStopRequ
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 {
err = v.(*gctscript.VM).Shutdown()
status := " terminated"
if err != nil {
status = " " + err.Error()
}
return &gctrpc.GenericResponse{Status: MsgStatusOK, Data: v.(*gctscript.VM).ID.String() + status}, nil
v, f := gctscript.AllVMSync.Load(UUID)
if !f {
return &gctrpc.GenericResponse{Status: MsgStatusError, Data: "no running script found"}, nil
}
return &gctrpc.GenericResponse{Status: MsgStatusError, Data: "no running script found"}, nil
vm, ok := v.(*gctscript.VM)
if !ok {
return nil, errors.New("unable to type assert gctscript.VM")
}
err = vm.Shutdown()
status := " terminated"
if err != nil {
status = " " + err.Error()
}
return &gctrpc.GenericResponse{Status: MsgStatusOK, Data: vm.ID.String() + status}, nil
}
// GCTScriptUpload upload a new script to ScriptPath
@@ -2642,7 +2659,7 @@ func (s *RPCServer) GCTScriptUpload(_ context.Context, r *gctrpc.GCTScriptUpload
return nil, fmt.Errorf("%s script found and overwrite set to false", r.ScriptName)
}
f := filepath.Join(gctscript.ScriptPath, "version_history")
err = os.MkdirAll(f, 0770)
err = os.MkdirAll(f, file.DefaultPermissionOctal)
if err != nil {
return nil, err
}
@@ -2726,7 +2743,7 @@ func (s *RPCServer) GCTScriptReadScript(_ context.Context, r *gctrpc.GCTScriptRe
if !strings.HasPrefix(filename, filepath.Clean(gctscript.ScriptPath)+string(os.PathSeparator)) {
return nil, fmt.Errorf("%s: invalid file path", filename)
}
data, err := ioutil.ReadFile(filename)
data, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
@@ -3271,9 +3288,9 @@ func (s *RPCServer) FindMissingSavedCandleIntervals(_ context.Context, r *gctrpc
Pair: r.Pair,
MissingPeriods: []string{},
}
var candleTimes []time.Time
candleTimes := make([]time.Time, len(klineItem.Candles))
for i := range klineItem.Candles {
candleTimes = append(candleTimes, klineItem.Candles[i].Time)
candleTimes[i] = klineItem.Candles[i].Time
}
var ranges []timeperiods.TimeRange
ranges, err = timeperiods.FindTimeRangesContainingData(start, end, klineItem.Interval.Duration(), candleTimes)
@@ -3373,9 +3390,9 @@ func (s *RPCServer) FindMissingSavedTradeIntervals(_ context.Context, r *gctrpc.
Pair: r.Pair,
MissingPeriods: []string{},
}
var tradeTimes []time.Time
tradeTimes := make([]time.Time, len(trades))
for i := range trades {
tradeTimes = append(tradeTimes, trades[i].Timestamp)
tradeTimes[i] = trades[i].Timestamp
}
var ranges []timeperiods.TimeRange
ranges, err = timeperiods.FindTimeRangesContainingData(start, end, time.Hour, tradeTimes)
@@ -3892,9 +3909,9 @@ func (s *RPCServer) GetActiveDataHistoryJobs(_ context.Context, _ *gctrpc.GetInf
return nil, err
}
var response []*gctrpc.DataHistoryJob
response := make([]*gctrpc.DataHistoryJob, len(jobs))
for i := range jobs {
response = append(response, &gctrpc.DataHistoryJob{
response[i] = &gctrpc.DataHistoryJob{
Id: jobs[i].ID.String(),
Nickname: jobs[i].Nickname,
Exchange: jobs[i].Exchange,
@@ -3919,7 +3936,7 @@ func (s *RPCServer) GetActiveDataHistoryJobs(_ context.Context, _ *gctrpc.GetInf
SecondaryExchangeName: jobs[i].SecondaryExchangeSource,
IssueTolerancePercentage: jobs[i].IssueTolerancePercentage,
ReplaceOnIssue: jobs[i].ReplaceOnIssue,
})
}
}
return &gctrpc.DataHistoryJobs{Results: response}, nil
}
@@ -3946,9 +3963,9 @@ func (s *RPCServer) GetDataHistoryJobsBetween(_ context.Context, r *gctrpc.GetDa
if err != nil {
return nil, err
}
var respJobs []*gctrpc.DataHistoryJob
respJobs := make([]*gctrpc.DataHistoryJob, len(jobs))
for i := range jobs {
respJobs = append(respJobs, &gctrpc.DataHistoryJob{
respJobs[i] = &gctrpc.DataHistoryJob{
Id: jobs[i].ID.String(),
Nickname: jobs[i].Nickname,
Exchange: jobs[i].Exchange,
@@ -3973,7 +3990,7 @@ func (s *RPCServer) GetDataHistoryJobsBetween(_ context.Context, r *gctrpc.GetDa
SecondaryExchangeName: jobs[i].SecondaryExchangeSource,
IssueTolerancePercentage: jobs[i].IssueTolerancePercentage,
ReplaceOnIssue: jobs[i].ReplaceOnIssue,
})
}
}
return &gctrpc.DataHistoryJobs{
Results: respJobs,
@@ -4309,17 +4326,15 @@ func (s *RPCServer) GetCollateral(ctx context.Context, r *gctrpc.GetCollateralRe
if err != nil {
return nil, err
}
var calculators []order.CollateralCalculator
var acc *account.SubAccount
var subAccounts []string
creds, err := exch.GetBase().GetCredentials(ctx)
if err != nil {
return nil, err
}
subAccounts := make([]string, len(ai.Accounts))
var acc *account.SubAccount
for i := range ai.Accounts {
subAccounts = append(subAccounts, ai.Accounts[i].ID)
subAccounts[i] = ai.Accounts[i].ID
if ai.Accounts[i].ID == "main" && creds.SubAccount == "" {
acc = &ai.Accounts[i]
break
@@ -4344,6 +4359,7 @@ func (s *RPCServer) GetCollateral(ctx context.Context, r *gctrpc.GetCollateralRe
}
}
calculators := make([]order.CollateralCalculator, 0, len(acc.Currencies))
for i := range acc.Currencies {
total := decimal.NewFromFloat(acc.Currencies[i].Total)
free := decimal.NewFromFloat(acc.Currencies[i].AvailableWithoutBorrow)

View File

@@ -99,7 +99,11 @@ func (m *WithdrawManager) WithdrawalEventByID(id string) (*withdraw.Response, er
return nil, ErrNilSubsystem
}
if v := withdraw.Cache.Get(id); v != nil {
return v.(*withdraw.Response), nil
wdResp, ok := v.(*withdraw.Response)
if !ok {
return nil, errors.New("unable to type assert withdraw.Response")
}
return wdResp, nil
}
l, err := dbwithdraw.GetEventByUUID(id)

View File

@@ -26,15 +26,13 @@ func CollectBalances(accountBalances map[string][]Balance, assetType asset.Item)
return nil, fmt.Errorf("%s, %w", assetType, asset.ErrNotSupported)
}
accounts = make([]SubAccount, len(accountBalances))
i := 0
accounts = make([]SubAccount, 0, len(accountBalances))
for accountID, balances := range accountBalances {
accounts[i] = SubAccount{
accounts = append(accounts, SubAccount{
ID: accountID,
AssetType: assetType,
Currencies: balances,
}
i++
})
}
return
}
@@ -42,16 +40,16 @@ func CollectBalances(accountBalances map[string][]Balance, assetType asset.Item)
// SubscribeToExchangeAccount subcribes to your exchange account
func SubscribeToExchangeAccount(exchange string) (dispatch.Pipe, error) {
exchange = strings.ToLower(exchange)
service.Lock()
service.mu.Lock()
acc, ok := service.accounts[exchange]
if !ok {
service.Unlock()
service.mu.Unlock()
return dispatch.Pipe{},
fmt.Errorf("%s exchange account holdings not found", exchange)
}
defer service.Unlock()
defer service.mu.Unlock()
return service.mux.Subscribe(acc.ID)
}
@@ -80,8 +78,8 @@ func GetHoldings(exch string, assetType asset.Item) (Holdings, error) {
return Holdings{}, fmt.Errorf("assetType %v is invalid", assetType)
}
service.Lock()
defer service.Unlock()
service.mu.Lock()
defer service.mu.Unlock()
h, ok := service.accounts[exch]
if !ok {
return Holdings{}, errors.New("exchange account holdings not found")
@@ -97,22 +95,22 @@ func GetHoldings(exch string, assetType asset.Item) (Holdings, error) {
// Update updates holdings with new account info
func (s *Service) Update(a *Holdings) error {
exch := strings.ToLower(a.Exchange)
s.Lock()
s.mu.Lock()
acc, ok := s.accounts[exch]
if !ok {
id, err := s.mux.GetID()
if err != nil {
s.Unlock()
s.mu.Unlock()
return err
}
s.accounts[exch] = &Account{h: a, ID: id}
s.Unlock()
s.mu.Unlock()
return nil
}
acc.h.Accounts = a.Accounts
defer s.Unlock()
defer s.mu.Unlock()
return s.mux.Publish([]uuid.UUID{acc.ID}, acc.h)
}

View File

@@ -20,7 +20,7 @@ var (
type Service struct {
accounts map[string]*Account
mux *dispatch.Mux
sync.Mutex
mu sync.Mutex
}
// Account holds a stream ID and a pointer to the exchange holdings

View File

@@ -101,14 +101,14 @@ func (a *Alphapoint) UpdateAccountInfo(ctx context.Context, assetType asset.Item
return response, err
}
var balances []account.Balance
balances := make([]account.Balance, len(acc.Currencies))
for i := range acc.Currencies {
balances = append(balances, account.Balance{
balances[i] = account.Balance{
CurrencyName: currency.NewCode(acc.Currencies[i].Name),
Total: float64(acc.Currencies[i].Balance),
Hold: float64(acc.Currencies[i].Hold),
Free: float64(acc.Currencies[i].Balance) - float64(acc.Currencies[i].Hold),
})
}
}
response.Accounts = append(response.Accounts, account.SubAccount{
@@ -181,18 +181,20 @@ func (a *Alphapoint) UpdateOrderbook(ctx context.Context, p currency.Pair, asset
return orderBook, err
}
orderBook.Bids = make(orderbook.Items, len(orderbookNew.Bids))
for x := range orderbookNew.Bids {
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
orderBook.Bids[x] = orderbook.Item{
Amount: orderbookNew.Bids[x].Quantity,
Price: orderbookNew.Bids[x].Price,
})
}
}
orderBook.Asks = make(orderbook.Items, len(orderbookNew.Asks))
for x := range orderbookNew.Asks {
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
orderBook.Asks[x] = orderbook.Item{
Amount: orderbookNew.Asks[x].Quantity,
Price: orderbookNew.Asks[x].Price,
})
}
}
orderBook.Pair = p

View File

@@ -60,9 +60,9 @@ func (a Item) String() string {
// Strings converts an asset type array to a string array
func (a Items) Strings() []string {
var assets []string
assets := make([]string, len(a))
for x := range a {
assets = append(assets, string(a[x]))
assets[x] = a[x].String()
}
return assets
}

View File

@@ -119,16 +119,15 @@ func (b *Binance) GetExchangeInfo(ctx context.Context) (ExchangeInfo, error) {
// OrderBookDataRequestParams contains the following members
// symbol: string of currency pair
// limit: returned limit amount
func (b *Binance) GetOrderBook(ctx context.Context, obd OrderBookDataRequestParams) (OrderBook, error) {
var orderbook OrderBook
func (b *Binance) GetOrderBook(ctx context.Context, obd OrderBookDataRequestParams) (*OrderBook, error) {
if err := b.CheckLimit(obd.Limit); err != nil {
return orderbook, err
return nil, err
}
params := url.Values{}
symbol, err := b.FormatSymbol(obd.Symbol, asset.Spot)
if err != nil {
return orderbook, err
return nil, err
}
params.Set("symbol", symbol)
params.Set("limit", fmt.Sprintf("%d", obd.Limit))
@@ -138,52 +137,54 @@ func (b *Binance) GetOrderBook(ctx context.Context, obd OrderBookDataRequestPara
exchange.RestSpotSupplementary,
orderBookDepth+"?"+params.Encode(),
orderbookLimit(obd.Limit), &resp); err != nil {
return orderbook, err
return nil, err
}
orderbook := OrderBook{
Bids: make([]OrderbookItem, len(resp.Bids)),
Asks: make([]OrderbookItem, len(resp.Asks)),
LastUpdateID: resp.LastUpdateID,
}
for x := range resp.Bids {
price, err := strconv.ParseFloat(resp.Bids[x][0], 64)
if err != nil {
return orderbook, err
return nil, err
}
amount, err := strconv.ParseFloat(resp.Bids[x][1], 64)
if err != nil {
return orderbook, err
return nil, err
}
orderbook.Bids = append(orderbook.Bids, OrderbookItem{
orderbook.Bids[x] = OrderbookItem{
Price: price,
Quantity: amount,
})
}
}
for x := range resp.Asks {
price, err := strconv.ParseFloat(resp.Asks[x][0], 64)
if err != nil {
return orderbook, err
return nil, err
}
amount, err := strconv.ParseFloat(resp.Asks[x][1], 64)
if err != nil {
return orderbook, err
return nil, err
}
orderbook.Asks = append(orderbook.Asks, OrderbookItem{
orderbook.Asks[x] = OrderbookItem{
Price: price,
Quantity: amount,
})
}
}
orderbook.LastUpdateID = resp.LastUpdateID
return orderbook, nil
return &orderbook, nil
}
// GetMostRecentTrades returns recent trade activity
// limit: Up to 500 results returned
func (b *Binance) GetMostRecentTrades(ctx context.Context, rtr RecentTradeRequestParams) ([]RecentTrade, error) {
var resp []RecentTrade
params := url.Values{}
symbol, err := b.FormatSymbol(rtr.Symbol, asset.Spot)
if err != nil {
@@ -194,6 +195,7 @@ func (b *Binance) GetMostRecentTrades(ctx context.Context, rtr RecentTradeReques
path := recentTrades + "?" + params.Encode()
var resp []RecentTrade
return resp, b.SendHTTPRequest(ctx,
exchange.RestSpotSupplementary, path, spotDefaultRate, &resp)
}
@@ -356,14 +358,12 @@ func (b *Binance) batchAggregateTrades(ctx context.Context, arg *AggregatedTrade
// startTime: startTime filter for kline data
// endTime: endTime filter for the kline data
func (b *Binance) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([]CandleStick, error) {
var resp interface{}
var klineData []CandleStick
params := url.Values{}
symbol, err := b.FormatSymbol(arg.Symbol, asset.Spot)
if err != nil {
return nil, err
}
params := url.Values{}
params.Set("symbol", symbol)
params.Set("interval", arg.Interval)
if arg.Limit != 0 {
@@ -377,6 +377,7 @@ func (b *Binance) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([
}
path := candleStick + "?" + params.Encode()
var resp interface{}
err = b.SendHTTPRequest(ctx,
exchange.RestSpotSupplementary,
@@ -390,6 +391,8 @@ func (b *Binance) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([
if !ok {
return nil, errors.New("unable to type assert responseData")
}
klineData := make([]CandleStick, len(responseData))
for x := range responseData {
individualData, ok := responseData[x].([]interface{})
if !ok {
@@ -432,7 +435,7 @@ func (b *Binance) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([
if candle.TakerBuyQuoteAssetVolume, err = convert.FloatFromString(individualData[10]); err != nil {
return nil, err
}
klineData = append(klineData, candle)
klineData[x] = candle
}
return klineData, nil
}

View File

@@ -82,10 +82,18 @@ func (b *Binance) FuturesExchangeInfo(ctx context.Context) (CExchangeInfo, error
}
// GetFuturesOrderbook gets orderbook data for CoinMarginedFutures,
func (b *Binance) GetFuturesOrderbook(ctx context.Context, symbol currency.Pair, limit int64) (OrderBook, error) {
var resp OrderBook
var data OrderbookData
func (b *Binance) GetFuturesOrderbook(ctx context.Context, symbol currency.Pair, limit int64) (*OrderBook, error) {
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
if err != nil {
return nil, err
}
params := url.Values{}
params.Set("symbol", symbolValue)
if limit > 0 && limit <= 1000 {
params.Set("limit", strconv.FormatInt(limit, 10))
}
rateBudget := cFuturesDefaultRate
switch {
case limit == 5, limit == 10, limit == 20, limit == 50:
@@ -97,48 +105,47 @@ func (b *Binance) GetFuturesOrderbook(ctx context.Context, symbol currency.Pair,
case limit == 1000:
rateBudget = cFuturesOrderbook1000Rate
}
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
if err != nil {
return resp, err
}
params.Set("symbol", symbolValue)
if limit > 0 && limit <= 1000 {
params.Set("limit", strconv.FormatInt(limit, 10))
}
var data OrderbookData
err = b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesOrderbook+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var resp OrderBook
var price, quantity float64
resp.Asks = make([]OrderbookItem, len(data.Asks))
for x := range data.Asks {
price, err = strconv.ParseFloat(data.Asks[x][0], 64)
if err != nil {
return resp, err
return nil, err
}
quantity, err = strconv.ParseFloat(data.Asks[x][1], 64)
if err != nil {
return resp, err
return nil, err
}
resp.Asks = append(resp.Asks, OrderbookItem{
resp.Asks[x] = OrderbookItem{
Price: price,
Quantity: quantity,
})
}
}
resp.Bids = make([]OrderbookItem, len(data.Bids))
for y := range data.Bids {
price, err = strconv.ParseFloat(data.Bids[y][0], 64)
if err != nil {
return resp, err
return nil, err
}
quantity, err = strconv.ParseFloat(data.Bids[y][1], 64)
if err != nil {
return resp, err
return nil, err
}
resp.Bids = append(resp.Bids, OrderbookItem{
resp.Bids[y] = OrderbookItem{
Price: price,
Quantity: quantity,
})
}
}
return resp, nil
return &resp, nil
}
// GetFuturesPublicTrades gets recent public trades for CoinMarginedFutures,
@@ -232,13 +239,11 @@ func (b *Binance) GetIndexAndMarkPrice(ctx context.Context, symbol, pair string)
// GetFuturesKlineData gets futures kline data for CoinMarginedFutures,
func (b *Binance) GetFuturesKlineData(ctx context.Context, symbol currency.Pair, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
var data [][10]interface{}
var resp []FuturesCandleStick
params := url.Values{}
if !symbol.IsEmpty() {
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
if err != nil {
return resp, err
return nil, err
}
params.Set("symbol", symbolValue)
}
@@ -246,453 +251,462 @@ func (b *Binance) GetFuturesKlineData(ctx context.Context, symbol currency.Pair,
params.Set("limit", strconv.FormatInt(limit, 10))
}
if !common.StringDataCompare(validFuturesIntervals, interval) {
return resp, errors.New("invalid interval parsed")
return nil, errors.New("invalid interval parsed")
}
params.Set("interval", interval)
if !startTime.IsZero() && !endTime.IsZero() {
if startTime.After(endTime) {
return resp, errors.New("startTime cannot be after endTime")
return nil, errors.New("startTime cannot be after endTime")
}
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
}
var data [][10]interface{}
rateBudget := getKlineRateBudget(limit)
err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesKlineData+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
resp := make([]FuturesCandleStick, len(data))
for x := range data {
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
floatData, ok = data[x][0].(float64)
if !ok {
return resp, errors.New("type assertion failed for open time")
return nil, errors.New("type assertion failed for open time")
}
tempData.OpenTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][1].(string)
if !ok {
return resp, errors.New("type assertion failed for open")
return nil, errors.New("type assertion failed for open")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Open = floatData
strData, ok = data[x][2].(string)
if !ok {
return resp, errors.New("type assertion failed for high")
return nil, errors.New("type assertion failed for high")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.High = floatData
strData, ok = data[x][3].(string)
if !ok {
return resp, errors.New("type assertion failed for low")
return nil, errors.New("type assertion failed for low")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Low = floatData
strData, ok = data[x][4].(string)
if !ok {
return resp, errors.New("type assertion failed for close")
return nil, errors.New("type assertion failed for close")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Close = floatData
strData, ok = data[x][5].(string)
if !ok {
return resp, errors.New("type assertion failed for volume")
return nil, errors.New("type assertion failed for volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Volume = floatData
floatData, ok = data[x][6].(float64)
if !ok {
return resp, errors.New("type assertion failed for close time")
return nil, errors.New("type assertion failed for close time")
}
tempData.CloseTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][7].(string)
if !ok {
return resp, errors.New("type assertion failed for base asset volume")
return nil, errors.New("type assertion failed for base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.BaseAssetVolume = floatData
floatData, ok = data[x][8].(float64)
if !ok {
return resp, errors.New("type assertion failed for taker buy volume")
return nil, errors.New("type assertion failed for taker buy volume")
}
tempData.TakerBuyVolume = floatData
strData, ok = data[x][9].(string)
if !ok {
return resp, errors.New("type assertion failed for taker buy base asset volume")
return nil, errors.New("type assertion failed for taker buy base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.TakerBuyBaseAssetVolume = floatData
resp = append(resp, tempData)
resp[x] = tempData
}
return resp, nil
}
// GetContinuousKlineData gets continuous kline data
func (b *Binance) GetContinuousKlineData(ctx context.Context, pair, contractType, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
var data [][10]interface{}
var resp []FuturesCandleStick
params := url.Values{}
params.Set("pair", pair)
if !common.StringDataCompare(validContractType, contractType) {
return resp, errors.New("invalid contractType")
return nil, errors.New("invalid contractType")
}
params.Set("contractType", contractType)
if limit > 0 && limit <= 1500 {
params.Set("limit", strconv.FormatInt(limit, 10))
}
if !common.StringDataCompare(validFuturesIntervals, interval) {
return resp, errors.New("invalid interval parsed")
return nil, errors.New("invalid interval parsed")
}
params.Set("interval", interval)
if !startTime.IsZero() && !endTime.IsZero() {
if startTime.After(endTime) {
return resp, errors.New("startTime cannot be after endTime")
return nil, errors.New("startTime cannot be after endTime")
}
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
}
rateBudget := getKlineRateBudget(limit)
var data [][10]interface{}
err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesContinuousKline+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
resp := make([]FuturesCandleStick, len(data))
for x := range data {
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
floatData, ok = data[x][0].(float64)
if !ok {
return resp, errors.New("type assertion failed for open time")
return nil, errors.New("type assertion failed for open time")
}
tempData.OpenTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][1].(string)
if !ok {
return resp, errors.New("type assertion failed for open")
return nil, errors.New("type assertion failed for open")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Open = floatData
strData, ok = data[x][2].(string)
if !ok {
return resp, errors.New("type assertion failed for high")
return nil, errors.New("type assertion failed for high")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.High = floatData
strData, ok = data[x][3].(string)
if !ok {
return resp, errors.New("type assertion failed for low")
return nil, errors.New("type assertion failed for low")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Low = floatData
strData, ok = data[x][4].(string)
if !ok {
return resp, errors.New("type assertion failed for close")
return nil, errors.New("type assertion failed for close")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Close = floatData
strData, ok = data[x][5].(string)
if !ok {
return resp, errors.New("type assertion failed for volume")
return nil, errors.New("type assertion failed for volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Volume = floatData
floatData, ok = data[x][6].(float64)
if !ok {
return resp, errors.New("type assertion failed for close time")
return nil, errors.New("type assertion failed for close time")
}
tempData.CloseTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][7].(string)
if !ok {
return resp, errors.New("type assertion failed for base asset volume")
return nil, errors.New("type assertion failed for base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.BaseAssetVolume = floatData
floatData, ok = data[x][8].(float64)
if !ok {
return resp, errors.New("type assertion failed for taker buy volume")
return nil, errors.New("type assertion failed for taker buy volume")
}
tempData.TakerBuyVolume = floatData
strData, ok = data[x][9].(string)
if !ok {
return resp, errors.New("type assertion failed for taker buy base asset volume")
return nil, errors.New("type assertion failed for taker buy base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.TakerBuyBaseAssetVolume = floatData
resp = append(resp, tempData)
resp[x] = tempData
}
return resp, nil
}
// GetIndexPriceKlines gets continuous kline data
func (b *Binance) GetIndexPriceKlines(ctx context.Context, pair, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
var data [][10]interface{}
var resp []FuturesCandleStick
params := url.Values{}
params.Set("pair", pair)
if limit > 0 && limit <= 1500 {
params.Set("limit", strconv.FormatInt(limit, 10))
}
if !common.StringDataCompare(validFuturesIntervals, interval) {
return resp, errors.New("invalid interval parsed")
return nil, errors.New("invalid interval parsed")
}
params.Set("interval", interval)
if !startTime.IsZero() && !endTime.IsZero() {
if startTime.After(endTime) {
return resp, errors.New("startTime cannot be after endTime")
return nil, errors.New("startTime cannot be after endTime")
}
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
}
rateBudget := getKlineRateBudget(limit)
var data [][10]interface{}
err := b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesIndexKline+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
resp := make([]FuturesCandleStick, len(data))
for x := range data {
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
floatData, ok = data[x][0].(float64)
if !ok {
return resp, errors.New("type assertion failed for open time")
return nil, errors.New("type assertion failed for open time")
}
tempData.OpenTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][1].(string)
if !ok {
return resp, errors.New("type assertion failed for open")
return nil, errors.New("type assertion failed for open")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Open = floatData
strData, ok = data[x][2].(string)
if !ok {
return resp, errors.New("type assertion failed for high")
return nil, errors.New("type assertion failed for high")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.High = floatData
strData, ok = data[x][3].(string)
if !ok {
return resp, errors.New("type assertion failed for low")
return nil, errors.New("type assertion failed for low")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Low = floatData
strData, ok = data[x][4].(string)
if !ok {
return resp, errors.New("type assertion failed for close")
return nil, errors.New("type assertion failed for close")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Close = floatData
strData, ok = data[x][5].(string)
if !ok {
return resp, errors.New("type assertion failed for volume")
return nil, errors.New("type assertion failed for volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Volume = floatData
floatData, ok = data[x][6].(float64)
if !ok {
return resp, errors.New("type assertion failed for close time")
return nil, errors.New("type assertion failed for close time")
}
tempData.CloseTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][7].(string)
if !ok {
return resp, errors.New("type assertion failed for base asset volume")
return nil, errors.New("type assertion failed for base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.BaseAssetVolume = floatData
floatData, ok = data[x][8].(float64)
if !ok {
return resp, errors.New("type assertion failed for taker buy volume")
return nil, errors.New("type assertion failed for taker buy volume")
}
tempData.TakerBuyVolume = floatData
strData, ok = data[x][9].(string)
if !ok {
return resp, errors.New("type assertion failed for taker buy base asset volume")
return nil, errors.New("type assertion failed for taker buy base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.TakerBuyBaseAssetVolume = floatData
resp = append(resp, tempData)
resp[x] = tempData
}
return resp, nil
}
// GetMarkPriceKline gets mark price kline data
func (b *Binance) GetMarkPriceKline(ctx context.Context, symbol currency.Pair, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
var data [][10]interface{}
var resp []FuturesCandleStick
params := url.Values{}
symbolValue, err := b.FormatSymbol(symbol, asset.CoinMarginedFutures)
if err != nil {
return resp, err
return nil, err
}
params := url.Values{}
params.Set("symbol", symbolValue)
if limit > 0 && limit <= 1500 {
params.Set("limit", strconv.FormatInt(limit, 10))
}
if !common.StringDataCompare(validFuturesIntervals, interval) {
return resp, errors.New("invalid interval parsed")
return nil, errors.New("invalid interval parsed")
}
params.Set("interval", interval)
if !startTime.IsZero() && !endTime.IsZero() {
if startTime.After(endTime) {
return resp, errors.New("startTime cannot be after endTime")
return nil, errors.New("startTime cannot be after endTime")
}
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
}
var data [][10]interface{}
rateBudget := getKlineRateBudget(limit)
err = b.SendHTTPRequest(ctx, exchange.RestCoinMargined, cfuturesMarkPriceKline+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
resp := make([]FuturesCandleStick, len(data))
for x := range data {
var floatData float64
var strData string
var ok bool
var tempData FuturesCandleStick
floatData, ok = data[x][0].(float64)
if !ok {
return resp, errors.New("type assertion failed for open time")
return nil, errors.New("type assertion failed for open time")
}
tempData.OpenTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][1].(string)
if !ok {
return resp, errors.New("type assertion failed for open")
return nil, errors.New("type assertion failed for open")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Open = floatData
strData, ok = data[x][2].(string)
if !ok {
return resp, errors.New("type assertion failed for high")
return nil, errors.New("type assertion failed for high")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.High = floatData
strData, ok = data[x][3].(string)
if !ok {
return resp, errors.New("type assertion failed for low")
return nil, errors.New("type assertion failed for low")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Low = floatData
strData, ok = data[x][4].(string)
if !ok {
return resp, errors.New("type assertion failed for close")
return nil, errors.New("type assertion failed for close")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Close = floatData
strData, ok = data[x][5].(string)
if !ok {
return resp, errors.New("type assertion failed for volume")
return nil, errors.New("type assertion failed for volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Volume = floatData
floatData, ok = data[x][6].(float64)
if !ok {
return resp, errors.New("type assertion failed for close time")
return nil, errors.New("type assertion failed for close time")
}
tempData.CloseTime = time.Unix(int64(floatData), 0)
strData, ok = data[x][7].(string)
if !ok {
return resp, errors.New("type assertion failed for base asset volume")
return nil, errors.New("type assertion failed for base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.BaseAssetVolume = floatData
floatData, ok = data[x][8].(float64)
if !ok {
return resp, errors.New("type assertion failed for taker buy volume")
return nil, errors.New("type assertion failed for taker buy volume")
}
tempData.TakerBuyVolume = floatData
strData, ok = data[x][9].(string)
if !ok {
return resp, errors.New("type assertion failed for taker buy base asset volume")
return nil, errors.New("type assertion failed for taker buy base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.TakerBuyBaseAssetVolume = floatData
resp = append(resp, tempData)
resp[x] = tempData
}
return resp, nil
}
@@ -1466,12 +1480,12 @@ func (b *Binance) FuturesPositionsADLEstimate(ctx context.Context, symbol curren
// FetchCoinMarginExchangeLimits fetches coin margined order execution limits
func (b *Binance) FetchCoinMarginExchangeLimits(ctx context.Context) ([]order.MinMaxLevel, error) {
var limits []order.MinMaxLevel
coinFutures, err := b.FuturesExchangeInfo(ctx)
if err != nil {
return nil, err
}
limits := make([]order.MinMaxLevel, 0, len(coinFutures.Symbols))
for x := range coinFutures.Symbols {
symbol := strings.Split(coinFutures.Symbols[x].Symbol, currency.UnderscoreDelimiter)
var cp currency.Pair

View File

@@ -36,6 +36,7 @@ func TestMain(m *testing.M) {
log.Fatal("Binance setup error", err)
}
b.setupOrderbookManager()
request.MaxRequestJobs = 100
b.Websocket.DataHandler = sharedtestvalues.GetWebsocketInterfaceChannelOverride()
log.Printf(sharedtestvalues.LiveTesting, b.Name)
os.Exit(m.Run())

View File

@@ -12,6 +12,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
)
@@ -57,6 +58,7 @@ func TestMain(m *testing.M) {
log.Fatal(err)
}
}
request.MaxRequestJobs = 100
log.Printf(sharedtestvalues.MockTesting, b.Name)
os.Exit(m.Run())
}

View File

@@ -84,22 +84,22 @@ func (b *Binance) UExchangeInfo(ctx context.Context) (UFuturesExchangeInfo, erro
}
// UFuturesOrderbook gets orderbook data for usdt margined futures
func (b *Binance) UFuturesOrderbook(ctx context.Context, symbol currency.Pair, limit int64) (OrderBook, error) {
var resp OrderBook
var data OrderbookData
params := url.Values{}
func (b *Binance) UFuturesOrderbook(ctx context.Context, symbol currency.Pair, limit int64) (*OrderBook, error) {
symbolValue, err := b.FormatSymbol(symbol, asset.USDTMarginedFutures)
if err != nil {
return resp, err
return nil, err
}
params := url.Values{}
params.Set("symbol", symbolValue)
strLimit := strconv.FormatInt(limit, 10)
if strLimit != "" {
if !common.StringDataCompare(uValidOBLimits, strLimit) {
return resp, fmt.Errorf("invalid limit: %v", limit)
return nil, fmt.Errorf("invalid limit: %v", limit)
}
params.Set("limit", strLimit)
}
rateBudget := uFuturesDefaultRate
switch {
case limit == 5, limit == 10, limit == 20, limit == 50:
@@ -111,42 +111,50 @@ func (b *Binance) UFuturesOrderbook(ctx context.Context, symbol currency.Pair, l
case limit == 1000:
rateBudget = uFuturesOrderbook1000Rate
}
var data OrderbookData
err = b.SendHTTPRequest(ctx, exchange.RestUSDTMargined, ufuturesOrderbook+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
resp.Symbol = symbolValue
resp.LastUpdateID = data.LastUpdateID
resp := OrderBook{
Symbol: symbolValue,
LastUpdateID: data.LastUpdateID,
Bids: make([]OrderbookItem, len(data.Bids)),
Asks: make([]OrderbookItem, len(data.Asks)),
}
var price, quantity float64
for x := range data.Asks {
price, err = strconv.ParseFloat(data.Asks[x][0], 64)
if err != nil {
return resp, err
return nil, err
}
quantity, err = strconv.ParseFloat(data.Asks[x][1], 64)
if err != nil {
return resp, err
return nil, err
}
resp.Asks = append(resp.Asks, OrderbookItem{
resp.Asks[x] = OrderbookItem{
Price: price,
Quantity: quantity,
})
}
}
for y := range data.Bids {
price, err = strconv.ParseFloat(data.Bids[y][0], 64)
if err != nil {
return resp, err
return nil, err
}
quantity, err = strconv.ParseFloat(data.Bids[y][1], 64)
if err != nil {
return resp, err
return nil, err
}
resp.Bids = append(resp.Bids, OrderbookItem{
resp.Bids[y] = OrderbookItem{
Price: price,
Quantity: quantity,
})
}
}
return resp, nil
return &resp, nil
}
// URecentTrades gets recent trades for usdt margined futures
@@ -212,16 +220,14 @@ func (b *Binance) UCompressedTrades(ctx context.Context, symbol currency.Pair, f
// UKlineData gets kline data for usdt margined futures
func (b *Binance) UKlineData(ctx context.Context, symbol currency.Pair, interval string, limit int64, startTime, endTime time.Time) ([]FuturesCandleStick, error) {
var data [][10]interface{}
var resp []FuturesCandleStick
params := url.Values{}
symbolValue, err := b.FormatSymbol(symbol, asset.USDTMarginedFutures)
if err != nil {
return resp, err
return nil, err
}
params.Set("symbol", symbolValue)
if !common.StringDataCompare(validFuturesIntervals, interval) {
return resp, errors.New("invalid interval")
return nil, errors.New("invalid interval")
}
params.Set("interval", interval)
if limit > 0 && limit <= 1500 {
@@ -229,7 +235,7 @@ func (b *Binance) UKlineData(ctx context.Context, symbol currency.Pair, interval
}
if !startTime.IsZero() && !endTime.IsZero() {
if startTime.After(endTime) {
return resp, errors.New("startTime cannot be after endTime")
return nil, errors.New("startTime cannot be after endTime")
}
params.Set("startTime", timeString(startTime))
params.Set("endTime", timeString(endTime))
@@ -245,71 +251,76 @@ func (b *Binance) UKlineData(ctx context.Context, symbol currency.Pair, interval
case limit > 1000:
rateBudget = uFuturesKlineMaxRate
}
var data [][10]interface{}
err = b.SendHTTPRequest(ctx, exchange.RestUSDTMargined, ufuturesKlineData+params.Encode(), rateBudget, &data)
if err != nil {
return resp, err
return nil, err
}
var tempData FuturesCandleStick
var floatData float64
var strData string
var ok bool
resp := make([]FuturesCandleStick, len(data))
for x := range data {
var tempData FuturesCandleStick
var floatData float64
var strData string
var ok bool
floatData, ok = data[x][0].(float64)
if !ok {
return resp, errors.New("type assertion failed for opentime")
return nil, errors.New("type assertion failed for opentime")
}
tempData.OpenTime, err = convert.TimeFromUnixTimestampFloat(floatData)
if err != nil {
return resp, err
return nil, err
}
strData, ok = data[x][1].(string)
if !ok {
return resp, errors.New("type assertion failed for open")
return nil, errors.New("type assertion failed for open")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Open = floatData
strData, ok = data[x][2].(string)
if !ok {
return resp, errors.New("type assertion failed for high")
return nil, errors.New("type assertion failed for high")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.High = floatData
strData, ok = data[x][3].(string)
if !ok {
return resp, errors.New("type assertion failed for low")
return nil, errors.New("type assertion failed for low")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Low = floatData
strData, ok = data[x][4].(string)
if !ok {
return resp, errors.New("type assertion failed for close")
return nil, errors.New("type assertion failed for close")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Close = floatData
strData, ok = data[x][5].(string)
if !ok {
return resp, errors.New("type assertion failed for volume")
return nil, errors.New("type assertion failed for volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.Volume = floatData
floatData, ok = data[x][6].(float64)
if !ok {
return resp, errors.New("type assertion failed for close time")
return nil, errors.New("type assertion failed for close time")
}
tempData.CloseTime, err = convert.TimeFromUnixTimestampFloat(floatData)
if err != nil {
@@ -317,28 +328,28 @@ func (b *Binance) UKlineData(ctx context.Context, symbol currency.Pair, interval
}
strData, ok = data[x][7].(string)
if !ok {
return resp, errors.New("type assertion failed base asset volume")
return nil, errors.New("type assertion failed base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.BaseAssetVolume = floatData
floatData, ok = data[x][8].(float64)
if !ok {
return resp, errors.New("type assertion failed for taker buy volume")
return nil, errors.New("type assertion failed for taker buy volume")
}
tempData.TakerBuyVolume = floatData
strData, ok = data[x][9].(string)
if !ok {
return resp, errors.New("type assertion failed for taker buy base asset volume")
return nil, errors.New("type assertion failed for taker buy base asset volume")
}
floatData, err = strconv.ParseFloat(strData, 64)
if err != nil {
return resp, err
return nil, err
}
tempData.TakerBuyBaseAssetVolume = floatData
resp = append(resp, tempData)
resp[x] = tempData
}
return resp, nil
}
@@ -1139,12 +1150,12 @@ func (b *Binance) GetFundingRates(ctx context.Context, symbol currency.Pair, lim
// FetchUSDTMarginExchangeLimits fetches USDT margined order execution limits
func (b *Binance) FetchUSDTMarginExchangeLimits(ctx context.Context) ([]order.MinMaxLevel, error) {
var limits []order.MinMaxLevel
usdtFutures, err := b.UExchangeInfo(ctx)
if err != nil {
return nil, err
}
limits := make([]order.MinMaxLevel, 0, len(usdtFutures.Symbols))
for x := range usdtFutures.Symbols {
var cp currency.Pair
cp, err = currency.NewPairFromStrings(usdtFutures.Symbols[x].BaseAsset,

View File

@@ -482,31 +482,32 @@ func (b *Binance) SeedLocalCache(ctx context.Context, p currency.Pair) error {
if err != nil {
return err
}
return b.SeedLocalCacheWithBook(p, &ob)
return b.SeedLocalCacheWithBook(p, ob)
}
// SeedLocalCacheWithBook seeds the local orderbook cache
func (b *Binance) SeedLocalCacheWithBook(p currency.Pair, orderbookNew *OrderBook) error {
var newOrderBook orderbook.Base
newOrderBook := orderbook.Base{
Pair: p,
Asset: asset.Spot,
Exchange: b.Name,
LastUpdateID: orderbookNew.LastUpdateID,
VerifyOrderbook: b.CanVerifyOrderbook,
Bids: make(orderbook.Items, len(orderbookNew.Bids)),
Asks: make(orderbook.Items, len(orderbookNew.Asks)),
}
for i := range orderbookNew.Bids {
newOrderBook.Bids = append(newOrderBook.Bids, orderbook.Item{
newOrderBook.Bids[i] = orderbook.Item{
Amount: orderbookNew.Bids[i].Quantity,
Price: orderbookNew.Bids[i].Price,
})
}
}
for i := range orderbookNew.Asks {
newOrderBook.Asks = append(newOrderBook.Asks, orderbook.Item{
newOrderBook.Asks[i] = orderbook.Item{
Amount: orderbookNew.Asks[i].Quantity,
Price: orderbookNew.Asks[i].Price,
})
}
}
newOrderBook.Pair = p
newOrderBook.Asset = asset.Spot
newOrderBook.Exchange = b.Name
newOrderBook.LastUpdateID = orderbookNew.LastUpdateID
newOrderBook.VerifyOrderbook = b.CanVerifyOrderbook
return b.Websocket.Orderbook.LoadSnapshot(&newOrderBook)
}
@@ -626,7 +627,7 @@ func (b *Binance) Unsubscribe(channelsToUnsubscribe []stream.ChannelSubscription
// ProcessUpdate processes the websocket orderbook update
func (b *Binance) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDepthStream) error {
var updateBid []orderbook.Item
updateBid := make([]orderbook.Item, len(ws.UpdateBids))
for i := range ws.UpdateBids {
price, ok := ws.UpdateBids[i][0].(string)
if !ok {
@@ -644,10 +645,10 @@ func (b *Binance) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDep
if err != nil {
return err
}
updateBid = append(updateBid, orderbook.Item{Price: p, Amount: a})
updateBid[i] = orderbook.Item{Price: p, Amount: a}
}
var updateAsk []orderbook.Item
updateAsk := make([]orderbook.Item, len(ws.UpdateAsks))
for i := range ws.UpdateAsks {
price, ok := ws.UpdateAsks[i][0].(string)
if !ok {
@@ -665,7 +666,7 @@ func (b *Binance) ProcessUpdate(cp currency.Pair, a asset.Item, ws *WebsocketDep
if err != nil {
return err
}
updateAsk = append(updateAsk, orderbook.Item{Price: p, Amount: a})
updateAsk[i] = orderbook.Item{Price: p, Amount: a}
}
return b.Websocket.Orderbook.Update(&buffer.Update{

View File

@@ -657,7 +657,7 @@ func (b *Binance) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTyp
Asset: assetType,
VerifyOrderbook: b.CanVerifyOrderbook,
}
var orderbookNew OrderBook
var orderbookNew *OrderBook
var err error
switch assetType {
case asset.Spot, asset.Margin:
@@ -673,17 +673,20 @@ func (b *Binance) UpdateOrderbook(ctx context.Context, p currency.Pair, assetTyp
if err != nil {
return book, err
}
book.Bids = make(orderbook.Items, len(orderbookNew.Bids))
for x := range orderbookNew.Bids {
book.Bids = append(book.Bids, orderbook.Item{
book.Bids[x] = orderbook.Item{
Amount: orderbookNew.Bids[x].Quantity,
Price: orderbookNew.Bids[x].Price,
})
}
}
book.Asks = make(orderbook.Items, len(orderbookNew.Asks))
for x := range orderbookNew.Asks {
book.Asks = append(book.Asks, orderbook.Item{
book.Asks[x] = orderbook.Item{
Amount: orderbookNew.Asks[x].Quantity,
Price: orderbookNew.Asks[x].Price,
})
}
}
err = book.Process()
@@ -834,15 +837,16 @@ func (b *Binance) GetWithdrawalsHistory(ctx context.Context, c currency.Code) (r
// GetRecentTrades returns the most recent trades for a currency and asset
func (b *Binance) GetRecentTrades(ctx context.Context, p currency.Pair, assetType asset.Item) ([]trade.Data, error) {
var resp []trade.Data
limit := 1000
const limit = 1000
tradeData, err := b.GetMostRecentTrades(ctx,
RecentTradeRequestParams{p, limit})
if err != nil {
return nil, err
}
resp := make([]trade.Data, len(tradeData))
for i := range tradeData {
resp = append(resp, trade.Data{
resp[i] = trade.Data{
TID: strconv.FormatInt(tradeData[i].ID, 10),
Exchange: b.Name,
CurrencyPair: p,
@@ -850,7 +854,7 @@ func (b *Binance) GetRecentTrades(ctx context.Context, p currency.Pair, assetTyp
Price: tradeData[i].Price,
Amount: tradeData[i].Quantity,
Timestamp: tradeData[i].Time,
})
}
}
if b.IsSaveTradeDataEnabled() {
err := trade.AddTradesToBuffer(b.Name, resp...)
@@ -874,11 +878,11 @@ func (b *Binance) GetHistoricTrades(ctx context.Context, p currency.Pair, a asse
if err != nil {
return nil, err
}
var result []trade.Data
result := make([]trade.Data, len(trades))
exName := b.GetName()
for i := range trades {
t := trades[i].toTradeData(p, exName, a)
result = append(result, *t)
result[i] = *t
}
return result, nil
}

View File

@@ -148,7 +148,7 @@ func baseMarginInfo(data []interface{}) (MarginInfoV2, error) {
}
func symbolMarginInfo(data []interface{}) ([]MarginInfoV2, error) {
var resp []MarginInfoV2
resp := make([]MarginInfoV2, len(data))
for x := range data {
var tempResp MarginInfoV2
tempData, ok := data[x].([]interface{})
@@ -183,7 +183,7 @@ func symbolMarginInfo(data []interface{}) ([]MarginInfoV2, error) {
if !ok {
return nil, fmt.Errorf("%w for BestBidAmount", errTypeAssert)
}
resp = append(resp, tempResp)
resp[x] = tempResp
}
return resp, nil
}
@@ -381,7 +381,6 @@ func (b *Bitfinex) GetAccountInfoV2(ctx context.Context) (AccountV2Data, error)
// GetV2Balances gets v2 balances
func (b *Bitfinex) GetV2Balances(ctx context.Context) ([]WalletDataV2, error) {
var resp []WalletDataV2
var data [][4]interface{}
err := b.SendAuthenticatedHTTPRequestV2(ctx,
exchange.RestSpot, http.MethodPost,
@@ -390,8 +389,9 @@ func (b *Bitfinex) GetV2Balances(ctx context.Context) ([]WalletDataV2, error) {
&data,
getAccountFees)
if err != nil {
return resp, err
return nil, err
}
resp := make([]WalletDataV2, len(data))
for x := range data {
wType, ok := data[x][0].(string)
if !ok {
@@ -409,12 +409,12 @@ func (b *Bitfinex) GetV2Balances(ctx context.Context) ([]WalletDataV2, error) {
if !ok {
return resp, fmt.Errorf("%v GetV2Balances: %w for unsettledInterest", b.Name, errTypeAssert)
}
resp = append(resp, WalletDataV2{
resp[x] = WalletDataV2{
WalletType: wType,
Currency: curr,
Balance: bal,
UnsettledInterest: unsettledInterest,
})
}
}
return resp, nil
}
@@ -435,9 +435,6 @@ func (b *Bitfinex) GetMarginPairs(ctx context.Context) ([]string, error) {
// GetDerivativeStatusInfo gets status data for the queried derivative
func (b *Bitfinex) GetDerivativeStatusInfo(ctx context.Context, keys, startTime, endTime string, sort, limit int64) ([]DerivativeDataResponse, error) {
var result [][]interface{}
var finalResp []DerivativeDataResponse
params := url.Values{}
params.Set("keys", keys)
if startTime != "" {
@@ -452,12 +449,15 @@ func (b *Bitfinex) GetDerivativeStatusInfo(ctx context.Context, keys, startTime,
if limit != 0 {
params.Set("limit", strconv.FormatInt(limit, 10))
}
var result [][]interface{}
path := bitfinexAPIVersion2 + bitfinexDerivativeData +
params.Encode()
err := b.SendHTTPRequest(ctx, exchange.RestSpot, path, &result, status)
if err != nil {
return finalResp, err
return nil, err
}
finalResp := make([]DerivativeDataResponse, len(result))
for z := range result {
if len(result[z]) < 19 {
return finalResp, fmt.Errorf("%v GetDerivativeStatusInfo: invalid response, array length too small, check api docs for updates", b.Name)
@@ -507,7 +507,7 @@ func (b *Bitfinex) GetDerivativeStatusInfo(ctx context.Context, keys, startTime,
t,
)
}
finalResp = append(finalResp, response)
finalResp[z] = response
}
return finalResp, nil
}
@@ -526,82 +526,198 @@ func (b *Bitfinex) GetTickerBatch(ctx context.Context) (map[string]Ticker, error
var tickers = make(map[string]Ticker)
for x := range response {
symbol, ok := response[x][0].(string)
if !ok {
return nil, errors.New("unable to type assert symbol")
}
var t Ticker
if len(response[x]) > 11 {
tickers[response[x][0].(string)] = Ticker{
FlashReturnRate: response[x][1].(float64),
Bid: response[x][2].(float64),
BidPeriod: int64(response[x][3].(float64)),
BidSize: response[x][4].(float64),
Ask: response[x][5].(float64),
AskPeriod: int64(response[x][6].(float64)),
AskSize: response[x][7].(float64),
DailyChange: response[x][8].(float64),
DailyChangePerc: response[x][9].(float64),
Last: response[x][10].(float64),
Volume: response[x][11].(float64),
High: response[x][12].(float64),
Low: response[x][13].(float64),
FFRAmountAvailable: response[x][16].(float64),
if t.FlashReturnRate, ok = response[x][1].(float64); !ok {
return nil, errors.New("unable to type assert flashReturnRate")
}
if t.Bid, ok = response[x][2].(float64); !ok {
return nil, errors.New("unable to type assert bid")
}
var bidPeriod float64
bidPeriod, ok = response[x][3].(float64)
if !ok {
return nil, errors.New("unable to type assert bidPeriod")
}
t.BidPeriod = int64(bidPeriod)
if t.BidSize, ok = response[x][4].(float64); !ok {
return nil, errors.New("unable to type assert bidSize")
}
if t.Ask, ok = response[x][5].(float64); !ok {
return nil, errors.New("unable to type assert ask")
}
var askPeriod float64
askPeriod, ok = response[x][6].(float64)
if !ok {
return nil, errors.New("unable to type assert askPeriod")
}
t.AskPeriod = int64(askPeriod)
if t.AskSize, ok = response[x][7].(float64); !ok {
return nil, errors.New("unable to type assert askSize")
}
if t.DailyChange, ok = response[x][8].(float64); !ok {
return nil, errors.New("unable to type assert dailyChange")
}
if t.DailyChangePerc, ok = response[x][9].(float64); !ok {
return nil, errors.New("unable to type assert dailyChangePerc")
}
if t.Last, ok = response[x][10].(float64); !ok {
return nil, errors.New("unable to type assert last")
}
if t.Volume, ok = response[x][11].(float64); !ok {
return nil, errors.New("unable to type assert volume")
}
if t.High, ok = response[x][12].(float64); !ok {
return nil, errors.New("unable to type assert high")
}
if t.Low, ok = response[x][13].(float64); !ok {
return nil, errors.New("unable to type assert low")
}
if t.FFRAmountAvailable, ok = response[x][16].(float64); !ok {
return nil, errors.New("unable to type assert FFRAmountAvailable")
}
tickers[symbol] = t
continue
}
tickers[response[x][0].(string)] = Ticker{
Bid: response[x][1].(float64),
BidSize: response[x][2].(float64),
Ask: response[x][3].(float64),
AskSize: response[x][4].(float64),
DailyChange: response[x][5].(float64),
DailyChangePerc: response[x][6].(float64),
Last: response[x][7].(float64),
Volume: response[x][8].(float64),
High: response[x][9].(float64),
Low: response[x][10].(float64),
if t.Bid, ok = response[x][1].(float64); !ok {
return nil, errors.New("unable to type assert bid")
}
if t.BidSize, ok = response[x][2].(float64); !ok {
return nil, errors.New("unable to type assert bid size")
}
if t.Ask, ok = response[x][3].(float64); !ok {
return nil, errors.New("unable to type assert ask")
}
if t.AskSize, ok = response[x][4].(float64); !ok {
return nil, errors.New("unable to type assert ask size")
}
if t.DailyChange, ok = response[x][5].(float64); !ok {
return nil, errors.New("unable to type assert daily change")
}
if t.DailyChangePerc, ok = response[x][6].(float64); !ok {
return nil, errors.New("unable to type assert daily change perc")
}
if t.Last, ok = response[x][7].(float64); !ok {
return nil, errors.New("unable to type assert last")
}
if t.Volume, ok = response[x][8].(float64); !ok {
return nil, errors.New("unable to type assert volume")
}
if t.High, ok = response[x][9].(float64); !ok {
return nil, errors.New("unable to type assert high")
}
if t.Low, ok = response[x][10].(float64); !ok {
return nil, errors.New("unable to type assert low")
}
tickers[symbol] = t
}
return tickers, nil
}
// GetTicker returns ticker information for one symbol
func (b *Bitfinex) GetTicker(ctx context.Context, symbol string) (Ticker, error) {
func (b *Bitfinex) GetTicker(ctx context.Context, symbol string) (*Ticker, error) {
var response []interface{}
path := bitfinexAPIVersion2 + bitfinexTicker + symbol
err := b.SendHTTPRequest(ctx, exchange.RestSpot, path, &response, tickerFunction)
if err != nil {
return Ticker{}, err
return nil, err
}
var t Ticker
if len(response) > 10 {
return Ticker{
FlashReturnRate: response[0].(float64),
Bid: response[1].(float64),
BidPeriod: int64(response[2].(float64)),
BidSize: response[3].(float64),
Ask: response[4].(float64),
AskPeriod: int64(response[5].(float64)),
AskSize: response[6].(float64),
DailyChange: response[7].(float64),
DailyChangePerc: response[8].(float64),
Last: response[9].(float64),
Volume: response[10].(float64),
High: response[11].(float64),
Low: response[12].(float64),
FFRAmountAvailable: response[15].(float64),
}, nil
var ok bool
if t.FlashReturnRate, ok = response[0].(float64); !ok {
return nil, errors.New("unable to type assert flashReturnRate")
}
if t.Bid, ok = response[1].(float64); !ok {
return nil, errors.New("unable to type assert bid")
}
var bidPeriod float64
bidPeriod, ok = response[2].(float64)
if !ok {
return nil, errors.New("unable to type assert bidPeriod")
}
t.BidPeriod = int64(bidPeriod)
if t.BidSize, ok = response[3].(float64); !ok {
return nil, errors.New("unable to type assert bidSize")
}
if t.Ask, ok = response[4].(float64); !ok {
return nil, errors.New("unable to type assert ask")
}
var askPeriod float64
askPeriod, ok = response[5].(float64)
if !ok {
return nil, errors.New("unable to type assert askPeriod")
}
t.AskPeriod = int64(askPeriod)
if t.AskSize, ok = response[6].(float64); !ok {
return nil, errors.New("unable to type assert askSize")
}
if t.DailyChange, ok = response[7].(float64); !ok {
return nil, errors.New("unable to type assert dailyChange")
}
if t.DailyChangePerc, ok = response[8].(float64); !ok {
return nil, errors.New("unable to type assert dailyChangePerc")
}
if t.Last, ok = response[9].(float64); !ok {
return nil, errors.New("unable to type assert last")
}
if t.Volume, ok = response[10].(float64); !ok {
return nil, errors.New("unable to type assert volume")
}
if t.High, ok = response[11].(float64); !ok {
return nil, errors.New("unable to type assert high")
}
if t.Low, ok = response[12].(float64); !ok {
return nil, errors.New("unable to type assert low")
}
if t.FFRAmountAvailable, ok = response[15].(float64); !ok {
return nil, errors.New("unable to type assert FFRAmountAvailable")
}
return &t, nil
}
return Ticker{
Bid: response[0].(float64),
BidSize: response[1].(float64),
Ask: response[2].(float64),
AskSize: response[3].(float64),
DailyChange: response[4].(float64),
DailyChangePerc: response[5].(float64),
Last: response[6].(float64),
Volume: response[7].(float64),
High: response[8].(float64),
Low: response[9].(float64),
}, nil
var ok bool
if t.Bid, ok = response[0].(float64); !ok {
return nil, errors.New("unable to type assert bid")
}
if t.BidSize, ok = response[1].(float64); !ok {
return nil, errors.New("unable to type assert bidSize")
}
if t.Ask, ok = response[2].(float64); !ok {
return nil, errors.New("unable to type assert ask")
}
if t.AskSize, ok = response[3].(float64); !ok {
return nil, errors.New("unable to type assert askSize")
}
if t.DailyChange, ok = response[4].(float64); !ok {
return nil, errors.New("unable to type assert dailyChange")
}
if t.DailyChangePerc, ok = response[5].(float64); !ok {
return nil, errors.New("unable to type assert dailyChangePerc")
}
if t.Last, ok = response[6].(float64); !ok {
return nil, errors.New("unable to type assert last")
}
if t.Volume, ok = response[7].(float64); !ok {
return nil, errors.New("unable to type assert volume")
}
if t.High, ok = response[8].(float64); !ok {
return nil, errors.New("unable to type assert high")
}
if t.Low, ok = response[9].(float64); !ok {
return nil, errors.New("unable to type assert low")
}
return &t, nil
}
// GetTrades gets historic trades that occurred on the exchange
@@ -637,7 +753,7 @@ func (b *Bitfinex) GetTrades(ctx context.Context, currencyPair string, limit, ti
return nil, err
}
var history []Trade
history := make([]Trade, len(resp))
for i := range resp {
amount, ok := resp[i][2].(float64)
if !ok {
@@ -649,25 +765,49 @@ func (b *Bitfinex) GetTrades(ctx context.Context, currencyPair string, limit, ti
amount *= -1
}
if len(resp[i]) > 4 {
history = append(history, Trade{
TID: int64(resp[i][0].(float64)),
Timestamp: int64(resp[i][1].(float64)),
Amount: amount,
Rate: resp[i][3].(float64),
Period: int64(resp[i][4].(float64)),
Type: side,
})
continue
tid, ok := resp[i][0].(float64)
if !ok {
return nil, errors.New("unable to type assert trade ID")
}
timestamp, ok := resp[i][1].(float64)
if !ok {
return nil, errors.New("unable to type assert timestamp")
}
history = append(history, Trade{
TID: int64(resp[i][0].(float64)),
Timestamp: int64(resp[i][1].(float64)),
if len(resp[i]) > 4 {
var rate float64
rate, ok = resp[i][3].(float64)
if !ok {
return nil, errors.New("unable to type assert rate")
}
var period float64
period, ok = resp[i][4].(float64)
if !ok {
return nil, errors.New("unable to type assert period")
}
history[i] = Trade{
TID: int64(tid),
Timestamp: int64(timestamp),
Amount: amount,
Rate: rate,
Period: int64(period),
Type: side,
}
continue
}
price, ok := resp[i][3].(float64)
if !ok {
return nil, errors.New("unable to type assert price")
}
history[i] = Trade{
TID: int64(tid),
Timestamp: int64(timestamp),
Amount: amount,
Price: resp[i][3].(float64),
Price: price,
Type: side,
})
}
}
return history, nil
@@ -873,19 +1013,33 @@ func (b *Bitfinex) GetCandles(ctx context.Context, symbol, timeFrame string, sta
return nil, err
}
var c []Candle
candles := make([]Candle, len(response))
for i := range response {
c = append(c, Candle{
Timestamp: time.Unix(int64(response[i][0].(float64)/1000), 0),
Open: response[i][1].(float64),
Close: response[i][2].(float64),
High: response[i][3].(float64),
Low: response[i][4].(float64),
Volume: response[i][5].(float64),
})
var c Candle
timestamp, ok := response[i][0].(float64)
if !ok {
return nil, errors.New("unable to type assert timestamp")
}
c.Timestamp = time.UnixMilli(int64(timestamp))
if c.Open, ok = response[i][1].(float64); !ok {
return nil, errors.New("unable to type assert open")
}
if c.Close, ok = response[i][2].(float64); !ok {
return nil, errors.New("unable to type assert close")
}
if c.High, ok = response[i][3].(float64); !ok {
return nil, errors.New("unable to type assert high")
}
if c.Low, ok = response[i][4].(float64); !ok {
return nil, errors.New("unable to type assert low")
}
if c.Volume, ok = response[i][5].(float64); !ok {
return nil, errors.New("unable to type assert volume")
}
candles[i] = c
}
return c, nil
return candles, nil
}
path += "/last"
@@ -900,14 +1054,29 @@ func (b *Bitfinex) GetCandles(ctx context.Context, symbol, timeFrame string, sta
return nil, errors.New("no data returned")
}
return []Candle{{
Timestamp: time.Unix(int64(response[0].(float64))/1000, 0),
Open: response[1].(float64),
Close: response[2].(float64),
High: response[3].(float64),
Low: response[4].(float64),
Volume: response[5].(float64),
}}, nil
var c Candle
timestamp, ok := response[0].(float64)
if !ok {
return nil, errors.New("unable to type assert timestamp")
}
c.Timestamp = time.UnixMilli(int64(timestamp))
if c.Open, ok = response[1].(float64); !ok {
return nil, errors.New("unable to type assert open")
}
if c.Close, ok = response[2].(float64); !ok {
return nil, errors.New("unable to type assert close")
}
if c.High, ok = response[3].(float64); !ok {
return nil, errors.New("unable to type assert high")
}
if c.Low, ok = response[4].(float64); !ok {
return nil, errors.New("unable to type assert low")
}
if c.Volume, ok = response[5].(float64); !ok {
return nil, errors.New("unable to type assert volume")
}
return []Candle{c}, nil
}
// GetConfigurations fetchs currency and symbol site configuration data.
@@ -983,7 +1152,7 @@ func (b *Bitfinex) GetLeaderboard(ctx context.Context, key, timeframe, symbol st
return r
}
var result []LeaderboardEntry
result := make([]LeaderboardEntry, len(resp))
for x := range resp {
r, ok := resp[x].([]interface{})
if !ok {
@@ -1008,13 +1177,13 @@ func (b *Bitfinex) GetLeaderboard(ctx context.Context, key, timeframe, symbol st
if !ok {
return nil, errors.New("unable to type assert value")
}
result = append(result, LeaderboardEntry{
result[x] = LeaderboardEntry{
Timestamp: time.UnixMilli(int64(tm)),
Username: username,
Ranking: int(ranking),
Value: value,
TwitterHandle: parseTwitterHandle(r[9]),
})
}
}
return result, nil
}

View File

@@ -1311,6 +1311,7 @@ func TestWsOrderSnapshot(t *testing.T) {
}
func TestWsNotifications(t *testing.T) {
b.WsAddSubscriptionChannel(0, "account", "N/A")
pressXToJSON := `[0,"n",[1575282446099,"fon-req",null,null,[41238905,null,null,null,-1000,null,null,null,null,null,null,null,null,null,0.002,2,null,null,null,null,null],null,"SUCCESS","Submitting funding bid of 1000.0 USD at 0.2000 for 2 days."]]`
err := b.wsHandleData([]byte(pressXToJSON))
if err != nil {
@@ -1324,6 +1325,90 @@ func TestWsNotifications(t *testing.T) {
}
}
func TestWSFundingOfferSnapshotAndUpdate(t *testing.T) {
b.WsAddSubscriptionChannel(0, "account", "N/A")
pressXToJSON := `[0,"fos",[[41237920,"fETH",1573912039000,1573912039000,0.5,0.5,"LIMIT",null,null,0,"ACTIVE",null,null,null,0.0024,2,0,0,null,0,null]]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
pressXToJSON = `[0,"fon",[41238747,"fUST",1575026670000,1575026670000,5000,5000,"LIMIT",null,null,0,"ACTIVE",null,null,null,0.006000000000000001,30,0,0,null,0,null]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
}
func TestWSFundingCreditSnapshotAndUpdate(t *testing.T) {
b.WsAddSubscriptionChannel(0, "account", "N/A")
pressXToJSON := `[0,"fcs",[[26223578,"fUST",1,1575052261000,1575296187000,350,0,"ACTIVE",null,null,null,0,30,1575052261000,1575293487000,0,0,null,0,null,0,"tBTCUST"],[26223711,"fUSD",-1,1575291961000,1575296187000,180,0,"ACTIVE",null,null,null,0.002,7,1575282446000,1575295587000,0,0,null,0,null,0,"tETHUSD"]]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
pressXToJSON = `[0,"fcu",[26223578,"fUST",1,1575052261000,1575296787000,350,0,"ACTIVE",null,null,null,0,30,1575052261000,1575293487000,0,0,null,0,null,0,"tBTCUST"]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
}
func TestWSFundingLoanSnapshotAndUpdate(t *testing.T) {
b.WsAddSubscriptionChannel(0, "account", "N/A")
pressXToJSON := `[0,"fls",[[2995442,"fUSD",-1,1575291961000,1575295850000,820,0,"ACTIVE",null,null,null,0.002,7,1575282446000,1575295850000,0,0,null,0,null,0]]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
pressXToJSON = `[0,"fln",[2995444,"fUSD",-1,1575298742000,1575298742000,1000,0,"ACTIVE",null,null,null,0.002,7,1575298742000,1575298742000,0,0,null,0,null,0]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
}
func TestWSWalletSnapshot(t *testing.T) {
b.WsAddSubscriptionChannel(0, "account", "N/A")
pressXToJSON := `[0,"ws",[["exchange","SAN",19.76,0,null,null,null]]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
}
func TestWSBalanceUpdate(t *testing.T) {
b.WsAddSubscriptionChannel(0, "account", "N/A")
const pressXToJSON = `[0,"bu",[4131.85,4131.85]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
}
func TestWSMarginInfoUpdate(t *testing.T) {
b.WsAddSubscriptionChannel(0, "account", "N/A")
const pressXToJSON = `[0,"miu",["base",[-13.014640000000007,0,49331.70267297,49318.68803297,27]]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
}
func TestWSFundingInfoUpdate(t *testing.T) {
b.WsAddSubscriptionChannel(0, "account", "N/A")
const pressXToJSON = `[0,"fiu",["sym","tETHUSD",[149361.09689202666,149639.26293509,830.0182168075556,895.0658432466332]]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
}
func TestWSFundingTrade(t *testing.T) {
b.WsAddSubscriptionChannel(0, "account", "N/A")
pressXToJSON := `[0,"fte",[636854,"fUSD",1575282446000,41238905,-1000,0.002,7,null]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
pressXToJSON = `[0,"ftu",[636854,"fUSD",1575282446000,41238905,-1000,0.002,7,null]]`
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
t.Error(err)
}
}
func TestGetHistoricCandles(t *testing.T) {
currencyPair, err := currency.NewPairFromString("BTCUSD")
if err != nil {

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