Merge pull request #734 from zenixls2/feature/lint_fmt_check

fix: apply gofmt on all files, add revive action
This commit is contained in:
Yo-An Lin 2022-06-17 18:51:34 +08:00 committed by GitHub
commit f25f2f076f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 2810 additions and 2720 deletions

View File

@ -17,7 +17,7 @@ jobs:
env: env:
MYSQL_DATABASE: bbgo MYSQL_DATABASE: bbgo
MYSQL_USER: "root" MYSQL_USER: "root"
MYSQL_PASSWORD: "root" MYSQL_PASSWORD: "root" # pragma: allowlist secret
steps: steps:
@ -44,10 +44,17 @@ jobs:
# auto-start: "false" # auto-start: "false"
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: 1.18 go-version: 1.18
- name: Run pre-commit
run: |
pip install pre-commit
pre-commit install-hooks
pre-commit run markdownlint --files=README.md --verbose
pre-commit run detect-secrets --all-files --verbose
- name: Install Migration Tool - name: Install Migration Tool
run: go install github.com/c9s/rockhopper/cmd/rockhopper@v1.2.1 run: go install github.com/c9s/rockhopper/cmd/rockhopper@v1.2.1
@ -72,6 +79,12 @@ jobs:
go test -race -coverprofile coverage_dnum.txt -covermode atomic -tags dnum ./pkg/... go test -race -coverprofile coverage_dnum.txt -covermode atomic -tags dnum ./pkg/...
sed -i -e '/_requestgen.go/d' coverage_dnum.txt sed -i -e '/_requestgen.go/d' coverage_dnum.txt
- name: Revive Check
uses: morphy2k/revive-action@v2
with:
reporter: github-pr-review
fail_on_error: true
- name: Upload Coverage Report - name: Upload Coverage Report
uses: codecov/codecov-action@v3 uses: codecov/codecov-action@v3
with: with:

22
.github/workflows/golang-lint.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: golang-lint
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.18
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.46.2

7
.golangci.yml Normal file
View File

@ -0,0 +1,7 @@
run:
issues-exit-code: 0
tests: false
linters:
disable-all: true
enable:
- gofmt

5
.markdownlint.yaml Normal file
View File

@ -0,0 +1,5 @@
default: true
extends: null
MD033: false
MD010: false
MD013: false

14
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,14 @@
---
repos:
# Secret Detection
- repo: https://github.com/Yelp/detect-secrets
rev: v1.2.0
hooks:
- id: detect-secrets
args: ['--exclude-secrets', '3899a918953e01bfe218116cdfeccbed579e26275c4a89abcbc70d2cb9e9bbb8']
exclude: pacakge.lock.json
# Markdown
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.31.1
hooks:
- id: markdownlint

View File

@ -5,6 +5,8 @@ A trading bot framework written in Go. The name bbgo comes from the BB8 bot in t
## Current Status ## Current Status
[![Go](https://github.com/c9s/bbgo/actions/workflows/go.yml/badge.svg?branch=main)](https://github.com/c9s/bbgo/actions/workflows/go.yml) [![Go](https://github.com/c9s/bbgo/actions/workflows/go.yml/badge.svg?branch=main)](https://github.com/c9s/bbgo/actions/workflows/go.yml)
[![GoDoc](https://godoc.org/github.com/c9s/bbgo?status.svg)](https://pkg.go.dev/github.com/c9s/bbgo)
[![Go Report Card](https://goreportcard.com/badge/github.com/c9s/bbgo)](https://goreportcard.com/report/github.com/c9s/bbgo)
[![DockerHub](https://img.shields.io/docker/pulls/yoanlin/bbgo.svg)](https://hub.docker.com/r/yoanlin/bbgo) [![DockerHub](https://img.shields.io/docker/pulls/yoanlin/bbgo.svg)](https://hub.docker.com/r/yoanlin/bbgo)
[![Coverage Status](http://codecov.io/github/c9s/bbgo/coverage.svg?branch=main)](http://codecov.io/github/c9s/bbgo?branch=main) [![Coverage Status](http://codecov.io/github/c9s/bbgo/coverage.svg?branch=main)](http://codecov.io/github/c9s/bbgo?branch=main)
<img alt="open collective badge" src="https://opencollective.com/bbgo/tiers/badge.svg"> <img alt="open collective badge" src="https://opencollective.com/bbgo/tiers/badge.svg">
@ -42,7 +44,38 @@ You can use BBGO's underlying common exchange API, currently it supports 4+ majo
- Built-in parameter optimization tool. - Built-in parameter optimization tool.
- Built-in Grid strategy and many other built-in strategies. - Built-in Grid strategy and many other built-in strategies.
- Multi-exchange session support: you can connect to more than 2 exchanges with different accounts or subaccounts. - Multi-exchange session support: you can connect to more than 2 exchanges with different accounts or subaccounts.
- Standard indicators, e.g., SMA, EMA, BOLL, VMA, MACD... - Indicators with interface similar to `pandas.Series`([series](https://github.com/c9s/bbgo/blob/main/doc/development/series.md))([usage](https://github.com/c9s/bbgo/blob/main/doc/development/indicator.md)):
- [Accumulation/Distribution Indicator](./pkg/indicator/ad.go)
- [Arnaud Legoux Moving Average](./pkg/indicator/alma.go)
- [Average True Range](./pkg/indicator/atr.go)
- [Bollinger Bands](./pkg/indicator/boll.go)
- [Commodity Channel Index](./pkg/indicator/cci.go)
- [Cumulative Moving Average](./pkg/indicator/cma.go)
- [Double Exponential Moving Average](./pkg/indicator/dema.go)
- [Directional Movement Index](./pkg/indicator/dmi.go)
- [Brownian Motion's Drift Factor](./pkg/indicator/drift.go)
- [Ease of Movement](./pkg/indicator/emv.go)
- [Exponentially Weighted Moving Average](./pkg/indicator/ewma.go)
- [Hull Moving Average](./pkg/indicator/hull.go)
- [Trend Line (Tool)](./pkg/indicator/line.go)
- [Moving Average Convergence Divergence Indicator](./pkg/indicator/macd.go)
- [On-Balance Volume](./pkg/indicator/obv.go)
- [Pivot](./pkg/indicator/pivot.go)
- [Running Moving Average](./pkg/indicator/rma.go)
- [Relative Strength Index](./pkg/indicator/rsi.go)
- [Simple Moving Average](./pkg/indicator/sma.go)
- [Ehler's Super Smoother Filter](./pkg/indicator/ssf.go)
- [Stochastic Oscillator](./pkg/indicator/stoch.go)
- [SuperTrend](./pkg/indicator/supertrend.go)
- [Triple Exponential Moving Average](./pkg/indicator/tema.go)
- [Tillson T3 Moving Average](./pkg/indicator/till.go)
- [Triangular Moving Average](./pkg/indicator/tma.go)
- [Variable Index Dynamic Average](./pkg/indicator/vidya.go)
- [Volatility Indicator](./pkg/indicator/volatility.go)
- [Volume Weighted Average Price](./pkg/indicator/vwap.go)
- [Zero Lag Exponential Moving Average](./pkg/indicator/zlema.go)
- And more...
- HeikinAshi OHLC / Normal OHLC (check [this config](https://github.com/c9s/bbgo/blob/main/config/skeleton.yaml#L5))
- React-powered Web Dashboard. - React-powered Web Dashboard.
- Docker image ready. - Docker image ready.
- Kubernetes support. - Kubernetes support.
@ -51,7 +84,7 @@ You can use BBGO's underlying common exchange API, currently it supports 4+ majo
## Screenshots ## Screenshots
![bbgo dashboard](assets/screenshots/dashboard.jpeg) ![bbgo dashboard](assets/screenshots/dashboard.jpeg)
![bbgo backtest report](assets/screenshots/backtest-report.jpg) ![bbgo backtest report](assets/screenshots/backtest-report.jpg)
@ -63,8 +96,8 @@ You can use BBGO's underlying common exchange API, currently it supports 4+ majo
- Kucoin Spot Exchange - Kucoin Spot Exchange
- MAX Spot Exchange (located in Taiwan) - MAX Spot Exchange (located in Taiwan)
## Documentation and General Topics ## Documentation and General Topics
- Check the [documentation index](doc/README.md) - Check the [documentation index](doc/README.md)
## BBGO Tokenomics ## BBGO Tokenomics
@ -105,6 +138,7 @@ bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/setup-bol
``` ```
If you already have configuration somewhere, a download-only script might be suitable for you: If you already have configuration somewhere, a download-only script might be suitable for you:
```sh ```sh
bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/download.sh) bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/download.sh)
``` ```
@ -114,7 +148,7 @@ Or refer to the [Release Page](https://github.com/c9s/bbgo/releases) and downloa
Since v2, we've added new float point implementation from dnum to support decimals with higher precision. Since v2, we've added new float point implementation from dnum to support decimals with higher precision.
To download & setup, please refer to [Dnum Installation](doc/topics/dnum-binary.md) To download & setup, please refer to [Dnum Installation](doc/topics/dnum-binary.md)
### One-click Linode StackScript: ### One-click Linode StackScript
- BBGO Grid Trading on Binance <https://cloud.linode.com/stackscripts/950715> - BBGO Grid Trading on Binance <https://cloud.linode.com/stackscripts/950715>
- BBGO USDT/TWD Grid Trading on MAX <https://cloud.linode.com/stackscripts/793380> - BBGO USDT/TWD Grid Trading on MAX <https://cloud.linode.com/stackscripts/793380>
@ -165,14 +199,12 @@ Prepare your dotenv file `.env.local` and BBGO yaml config file `bbgo.yaml`.
To check the available environment variables, please see [Environment Variables](./doc/configuration/envvars.md) To check the available environment variables, please see [Environment Variables](./doc/configuration/envvars.md)
The minimal bbgo.yaml could be generated by: The minimal bbgo.yaml could be generated by:
```sh ```sh
curl -o bbgo.yaml https://raw.githubusercontent.com/c9s/bbgo/main/config/minimal.yaml curl -o bbgo.yaml https://raw.githubusercontent.com/c9s/bbgo/main/config/minimal.yaml
``` ```
To run strategy: To run strategy:
```sh ```sh
@ -185,14 +217,12 @@ To start bbgo with the frontend dashboard:
bbgo run --enable-webserver bbgo run --enable-webserver
``` ```
If you want to switch to other dotenv file, you can add an `--dotenv` option or `--config`: If you want to switch to other dotenv file, you can add an `--dotenv` option or `--config`:
```sh ```sh
bbgo sync --dotenv .env.dev --config config/grid.yaml --session binance bbgo sync --dotenv .env.dev --config config/grid.yaml --session binance
``` ```
To query transfer history: To query transfer history:
```sh ```sh
@ -207,13 +237,13 @@ bbgo pnl --exchange binance --asset BTC --since "2019-01-01"
``` ```
---> --->
## Advanced Configuration ## Advanced Configuration
### Testnet (Paper Trading) ### Testnet (Paper Trading)
Currently only supports binance testnet. Currently only supports binance testnet.
To run bbgo in testnet, apply new API keys from [Binance Test Network](https://testnet.binance.vision), and set the following env before you start bbgo: To run bbgo in testnet, apply new API keys from [Binance Test Network](https://testnet.binance.vision), and set the following env before you start bbgo:
```bash ```bash
export PAPER_TRADE=1 export PAPER_TRADE=1
export DISABLE_MARKET_CACHE=1 # the symbols supported in testnet is far less than the mainnet export DISABLE_MARKET_CACHE=1 # the symbols supported in testnet is far less than the mainnet

View File

@ -102,7 +102,7 @@ func main() {
return return
} }
if err := trader.LoadState() ; err != nil { if err := trader.LoadState(); err != nil {
log.WithError(err).Error("failed to load strategy states") log.WithError(err).Error("failed to load strategy states")
return return
} }

View File

@ -110,7 +110,7 @@ func main() {
return return
} }
if err := trader.LoadState() ; err != nil { if err := trader.LoadState(); err != nil {
log.WithError(err).Error("failed to load strategy states") log.WithError(err).Error("failed to load strategy states")
return return
} }
@ -123,7 +123,7 @@ func main() {
} }
// find a free port for binding the server // find a free port for binding the server
ln, err := net.Listen("tcp", "127.0.0.1:" + strconv.Itoa(portNum)) ln, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(portNum))
if err != nil { if err != nil {
log.WithError(err).Error("can not bind listener") log.WithError(err).Error("can not bind listener")
return return

View File

@ -1,12 +1,12 @@
package main package main
import ( import (
"fmt"
"github.com/c9s/bbgo/pkg/cmd" "github.com/c9s/bbgo/pkg/cmd"
"github.com/spf13/cobra/doc" "github.com/spf13/cobra/doc"
"log"
"path" "path"
"runtime" "runtime"
"fmt"
"log"
) )
func main() { func main() {

View File

@ -39,4 +39,3 @@ var accountsCmd = &cobra.Command{
return nil return nil
}, },
} }

View File

@ -32,7 +32,6 @@ func init() {
ordersCmd.AddCommand(historyOrdersCmd) ordersCmd.AddCommand(historyOrdersCmd)
} }
// go run ./examples/kucoin orders // go run ./examples/kucoin orders
var ordersCmd = &cobra.Command{ var ordersCmd = &cobra.Command{
Use: "orders", Use: "orders",
@ -73,7 +72,6 @@ var ordersCmd = &cobra.Command{
}, },
} }
// go run ./examples/kucoin orders history // go run ./examples/kucoin orders history
var historyOrdersCmd = &cobra.Command{ var historyOrdersCmd = &cobra.Command{
Use: "history [--symbol SYMBOL]", Use: "history [--symbol SYMBOL]",
@ -105,7 +103,6 @@ var historyOrdersCmd = &cobra.Command{
}, },
} }
// usage: // usage:
// go run ./examples/kucoin orders place --symbol LTC-USDT --price 50 --size 1 --order-type limit --side buy // go run ./examples/kucoin orders place --symbol LTC-USDT --price 50 --size 1 --order-type limit --side buy
var placeOrderCmd = &cobra.Command{ var placeOrderCmd = &cobra.Command{
@ -124,14 +121,12 @@ var placeOrderCmd = &cobra.Command{
req.OrderType(kucoinapi.OrderType(orderType)) req.OrderType(kucoinapi.OrderType(orderType))
side, err := cmd.Flags().GetString("side") side, err := cmd.Flags().GetString("side")
if err != nil { if err != nil {
return err return err
} }
req.Side(kucoinapi.SideType(side)) req.Side(kucoinapi.SideType(side))
symbol, err := cmd.Flags().GetString("symbol") symbol, err := cmd.Flags().GetString("symbol")
if err != nil { if err != nil {
return err return err
@ -155,7 +150,6 @@ var placeOrderCmd = &cobra.Command{
} }
size, err := cmd.Flags().GetString("size") size, err := cmd.Flags().GetString("size")
if err != nil { if err != nil {
return err return err
@ -172,8 +166,6 @@ var placeOrderCmd = &cobra.Command{
}, },
} }
// usage: // usage:
var cancelOrderCmd = &cobra.Command{ var cancelOrderCmd = &cobra.Command{
Use: "cancel", Use: "cancel",

View File

@ -25,4 +25,3 @@ var symbolsCmd = &cobra.Command{
return nil return nil
}, },
} }

View File

@ -36,7 +36,6 @@ var tickersCmd = &cobra.Command{
logrus.Infof("ticker: %+v", ticker) logrus.Infof("ticker: %+v", ticker)
tickerStats, err := client.MarketDataService.GetTicker24HStat(args[0]) tickerStats, err := client.MarketDataService.GetTicker24HStat(args[0])
if err != nil { if err != nil {
return err return err
@ -46,4 +45,3 @@ var tickersCmd = &cobra.Command{
return nil return nil
}, },
} }

View File

@ -77,16 +77,16 @@ var websocketCmd = &cobra.Command{
id := time.Now().UnixNano() / int64(time.Millisecond) id := time.Now().UnixNano() / int64(time.Millisecond)
wsCmds := []kucoin.WebSocketCommand{ wsCmds := []kucoin.WebSocketCommand{
/* /*
{ {
Id: id+1, Id: id+1,
Type: "subscribe", Type: "subscribe",
Topic: "/market/ticker:ETH-USDT", Topic: "/market/ticker:ETH-USDT",
PrivateChannel: false, PrivateChannel: false,
Response: true, Response: true,
}, },
*/ */
{ {
Id: id+2, Id: id + 2,
Type: "subscribe", Type: "subscribe",
Topic: "/market/candles:ETH-USDT_1min", Topic: "/market/candles:ETH-USDT_1min",
PrivateChannel: false, PrivateChannel: false,
@ -131,7 +131,6 @@ var websocketCmd = &cobra.Command{
logrus.WithError(err).Error("websocket ping error", err) logrus.WithError(err).Error("websocket ping error", err)
} }
case <-interrupt: case <-interrupt:
logrus.Infof("interrupt") logrus.Infof("interrupt")
@ -144,8 +143,8 @@ var websocketCmd = &cobra.Command{
} }
select { select {
case <-done: case <-done:
case <-time.After(time.Second): case <-time.After(time.Second):
} }
return nil return nil
} }

View File

@ -69,7 +69,6 @@ var rootCmd = &cobra.Command{
log.Infof("%+v", account) log.Infof("%+v", account)
log.Infof("ASSET BALANCES:") log.Infof("ASSET BALANCES:")
assetBalances, err := client.AssetBalances() assetBalances, err := client.AssetBalances()
if err != nil { if err != nil {

View File

@ -19,19 +19,19 @@ func TestKLineDumper(t *testing.T) {
t1 := time.Now() t1 := time.Now()
err := dumper.Record(types.KLine{ err := dumper.Record(types.KLine{
Exchange: types.ExchangeBinance, Exchange: types.ExchangeBinance,
Symbol: "BTCUSDT", Symbol: "BTCUSDT",
StartTime: types.Time(t1), StartTime: types.Time(t1),
EndTime: types.Time(t1.Add(time.Minute)), EndTime: types.Time(t1.Add(time.Minute)),
Interval: types.Interval1m, Interval: types.Interval1m,
Open: fixedpoint.NewFromFloat(1000.0), Open: fixedpoint.NewFromFloat(1000.0),
High: fixedpoint.NewFromFloat(2000.0), High: fixedpoint.NewFromFloat(2000.0),
Low: fixedpoint.NewFromFloat(3000.0), Low: fixedpoint.NewFromFloat(3000.0),
Close: fixedpoint.NewFromFloat(4000.0), Close: fixedpoint.NewFromFloat(4000.0),
Volume: fixedpoint.NewFromFloat(5000.0), Volume: fixedpoint.NewFromFloat(5000.0),
QuoteVolume: fixedpoint.NewFromFloat(6000.0), QuoteVolume: fixedpoint.NewFromFloat(6000.0),
NumberOfTrades: 10, NumberOfTrades: 10,
Closed: true, Closed: true,
}) })
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -30,6 +30,7 @@ var klineMatchingLogger *logrus.Entry = nil
// FeeToken is used to simulate the exchange platform fee token // FeeToken is used to simulate the exchange platform fee token
// This is to ease the back-testing environment for closing positions. // This is to ease the back-testing environment for closing positions.
const FeeToken = "FEE" const FeeToken = "FEE"
var useFeeToken = true var useFeeToken = true
func init() { func init() {

View File

@ -34,7 +34,6 @@ func TestStateRecorder(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, recorder.writers, 1) assert.Len(t, recorder.writers, 1)
st.Position.AddTrade(types.Trade{ st.Position.AddTrade(types.Trade{
OrderID: 1, OrderID: 1,
Exchange: types.ExchangeBinance, Exchange: types.ExchangeBinance,

View File

@ -596,7 +596,7 @@ func (environ *Environment) syncWithUserConfig(ctx context.Context, userConfig *
syncSymbolMap, restSymbols := categorizeSyncSymbol(userConfig.Sync.Symbols) syncSymbolMap, restSymbols := categorizeSyncSymbol(userConfig.Sync.Symbols)
for _, session := range sessions { for _, session := range sessions {
syncSymbols := restSymbols syncSymbols := restSymbols
if ss, ok := syncSymbolMap[session.Name] ; ok { if ss, ok := syncSymbolMap[session.Name]; ok {
syncSymbols = append(syncSymbols, ss...) syncSymbols = append(syncSymbols, ss...)
} }
@ -928,10 +928,11 @@ func (environ *Environment) setupInteraction(persistence service.PersistenceServ
} }
interact.AddCustomInteraction(&interact.AuthInteract{ interact.AddCustomInteraction(&interact.AuthInteract{
Strict: authStrict, Strict: authStrict,
Mode: authMode, Mode: authMode,
Token: authToken, // can be empty string here Token: authToken, // can be empty string here
OneTimePasswordKey: key, // can be nil here // pragma: allowlist nextline secret
OneTimePasswordKey: key, // can be nil here
}) })
return nil return nil
} }

View File

@ -69,4 +69,3 @@ func (m *Notifiability) NotifyTo(channel string, obj interface{}, args ...interf
n.NotifyTo(channel, obj, args...) n.NotifyTo(channel, obj, args...)
} }
} }

View File

@ -1,2 +1 @@
package bbgo package bbgo

View File

@ -100,4 +100,3 @@ func newTypeValueInterface(typ reflect.Type) interface{} {
dst := reflect.New(typ) dst := reflect.New(typ)
return dst.Interface() return dst.Interface()
} }

View File

@ -1,4 +1,4 @@
// Code generated by "callbackgen -type StrategyController strategy_controller.go"; DO NOT EDIT. // Code generated by "callbackgen -type StrategyController -interface"; DO NOT EDIT.
package bbgo package bbgo
@ -33,3 +33,11 @@ func (s *StrategyController) EmitEmergencyStop() {
cb() cb()
} }
} }
type StrategyControllerEventHub interface {
OnSuspend(cb func())
OnResume(cb func())
OnEmergencyStop(cb func())
}

View File

@ -1,2 +1 @@
package bbgo package bbgo

View File

@ -1,2 +1 @@
package cmdutil package cmdutil

View File

@ -35,6 +35,7 @@ func New() *RestClient {
} }
func (c *RestClient) Auth(apiKey string) { func (c *RestClient) Auth(apiKey string) {
// pragma: allowlist nextline secret
c.apiKey = apiKey c.apiKey = apiKey
} }

View File

@ -35,6 +35,7 @@ func NewRestClient() *RestClient {
} }
func (c *RestClient) Auth(apiKey string) { func (c *RestClient) Auth(apiKey string) {
// pragma: allowlist nextline secret
c.apiKey = apiKey c.apiKey = apiKey
} }

View File

@ -3,6 +3,7 @@ package depth
import ( import (
"fmt" "fmt"
"sync" "sync"
"sync/atomic"
"time" "time"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -40,7 +41,7 @@ type Buffer struct {
updateTimeout time.Duration updateTimeout time.Duration
// bufferingPeriod is used to buffer the update message before we get the full depth // bufferingPeriod is used to buffer the update message before we get the full depth
bufferingPeriod time.Duration bufferingPeriod atomic.Value
} }
func NewBuffer(fetcher SnapshotFetcher) *Buffer { func NewBuffer(fetcher SnapshotFetcher) *Buffer {
@ -55,7 +56,7 @@ func (b *Buffer) SetUpdateTimeout(d time.Duration) {
} }
func (b *Buffer) SetBufferingPeriod(d time.Duration) { func (b *Buffer) SetBufferingPeriod(d time.Duration) {
b.bufferingPeriod = d b.bufferingPeriod.Store(d)
} }
func (b *Buffer) resetSnapshot() { func (b *Buffer) resetSnapshot() {
@ -185,8 +186,8 @@ func (b *Buffer) fetchAndPush() error {
func (b *Buffer) tryFetch() { func (b *Buffer) tryFetch() {
for { for {
if b.bufferingPeriod > 0 { if period := b.bufferingPeriod.Load(); period != nil {
<-time.After(b.bufferingPeriod) <-time.After(period.(time.Duration))
} }
err := b.fetchAndPush() err := b.fetchAndPush()

View File

@ -1,2 +1 @@
package batch package batch

View File

@ -15,8 +15,8 @@ type MarginInterestBatchQuery struct {
func (e *MarginInterestBatchQuery) Query(ctx context.Context, asset string, startTime, endTime time.Time) (c chan types.MarginInterest, errC chan error) { func (e *MarginInterestBatchQuery) Query(ctx context.Context, asset string, startTime, endTime time.Time) (c chan types.MarginInterest, errC chan error) {
query := &AsyncTimeRangedBatchQuery{ query := &AsyncTimeRangedBatchQuery{
Type: types.MarginInterest{}, Type: types.MarginInterest{},
Limiter: rate.NewLimiter(rate.Every(5*time.Second), 2), Limiter: rate.NewLimiter(rate.Every(5*time.Second), 2),
JumpIfEmpty: time.Hour * 24 * 30, JumpIfEmpty: time.Hour * 24 * 30,
Q: func(startTime, endTime time.Time) (interface{}, error) { Q: func(startTime, endTime time.Time) (interface{}, error) {
return e.QueryInterestHistory(ctx, asset, &startTime, &endTime) return e.QueryInterestHistory(ctx, asset, &startTime, &endTime)

View File

@ -16,8 +16,8 @@ type MarginLiquidationBatchQuery struct {
func (e *MarginLiquidationBatchQuery) Query(ctx context.Context, startTime, endTime time.Time) (c chan types.MarginLiquidation, errC chan error) { func (e *MarginLiquidationBatchQuery) Query(ctx context.Context, startTime, endTime time.Time) (c chan types.MarginLiquidation, errC chan error) {
query := &AsyncTimeRangedBatchQuery{ query := &AsyncTimeRangedBatchQuery{
Type: types.MarginLiquidation{}, Type: types.MarginLiquidation{},
Limiter: rate.NewLimiter(rate.Every(5*time.Second), 2), Limiter: rate.NewLimiter(rate.Every(5*time.Second), 2),
JumpIfEmpty: time.Hour * 24 * 30, JumpIfEmpty: time.Hour * 24 * 30,
Q: func(startTime, endTime time.Time) (interface{}, error) { Q: func(startTime, endTime time.Time) (interface{}, error) {
return e.QueryLiquidationHistory(ctx, &startTime, &endTime) return e.QueryLiquidationHistory(ctx, &startTime, &endTime)

View File

@ -16,8 +16,8 @@ type MarginRepayBatchQuery struct {
func (e *MarginRepayBatchQuery) Query(ctx context.Context, asset string, startTime, endTime time.Time) (c chan types.MarginRepay, errC chan error) { func (e *MarginRepayBatchQuery) Query(ctx context.Context, asset string, startTime, endTime time.Time) (c chan types.MarginRepay, errC chan error) {
query := &AsyncTimeRangedBatchQuery{ query := &AsyncTimeRangedBatchQuery{
Type: types.MarginRepay{}, Type: types.MarginRepay{},
Limiter: rate.NewLimiter(rate.Every(5*time.Second), 2), Limiter: rate.NewLimiter(rate.Every(5*time.Second), 2),
JumpIfEmpty: time.Hour * 24 * 30, JumpIfEmpty: time.Hour * 24 * 30,
Q: func(startTime, endTime time.Time) (interface{}, error) { Q: func(startTime, endTime time.Time) (interface{}, error) {
return e.QueryRepayHistory(ctx, asset, &startTime, &endTime) return e.QueryRepayHistory(ctx, asset, &startTime, &endTime)

View File

@ -21,7 +21,7 @@ func (e TradeBatchQuery) Query(ctx context.Context, symbol string, options *type
startTime := *options.StartTime startTime := *options.StartTime
endTime := *options.EndTime endTime := *options.EndTime
query := &AsyncTimeRangedBatchQuery{ query := &AsyncTimeRangedBatchQuery{
Type: types.Trade{}, Type: types.Trade{},
Q: func(startTime, endTime time.Time) (interface{}, error) { Q: func(startTime, endTime time.Time) (interface{}, error) {
return e.ExchangeTradeHistoryService.QueryTrades(ctx, symbol, options) return e.ExchangeTradeHistoryService.QueryTrades(ctx, symbol, options)
}, },

View File

@ -60,6 +60,7 @@ func NewClient(baseURL string) *RestClient {
func (c *RestClient) Auth(key, secret string) { func (c *RestClient) Auth(key, secret string) {
c.Key = key c.Key = key
// pragma: allowlist nextline secret
c.Secret = secret c.Secret = secret
} }

View File

@ -84,7 +84,6 @@ func TestClient_NewSpotRebateHistoryRequest(t *testing.T) {
t.Logf("spot rebate history: %+v", history) t.Logf("spot rebate history: %+v", history)
} }
func TestClient_NewGetMarginInterestRateHistoryRequest(t *testing.T) { func TestClient_NewGetMarginInterestRateHistoryRequest(t *testing.T) {
client := getTestClientOrSkip(t) client := getTestClientOrSkip(t)
ctx := context.Background() ctx := context.Background()
@ -121,8 +120,8 @@ func TestClient_privateCall(t *testing.T) {
resp, err := client.SendRequest(req) resp, err := client.SendRequest(req)
if assert.NoError(t, err) { if assert.NoError(t, err) {
var feeStructs []struct{ var feeStructs []struct {
Symbol string `json:"symbol"` Symbol string `json:"symbol"`
MakerCommission string `json:"makerCommission"` MakerCommission string `json:"makerCommission"`
TakerCommission string `json:"takerCommission"` TakerCommission string `json:"takerCommission"`
} }
@ -131,7 +130,7 @@ func TestClient_privateCall(t *testing.T) {
assert.NotEmpty(t, feeStructs) assert.NotEmpty(t, feeStructs)
} }
} else { } else {
dump, _ := httputil.DumpRequest(req, true); dump, _ := httputil.DumpRequest(req, true)
log.Printf("request: %s", dump) log.Printf("request: %s", dump)
} }
} }

View File

@ -7,9 +7,9 @@ import (
) )
type TradeFee struct { type TradeFee struct {
Symbol string `json:"symbol"` Symbol string `json:"symbol"`
MakerCommission fixedpoint.Value `json:"makerCommission"` MakerCommission fixedpoint.Value `json:"makerCommission"`
TakerCommission fixedpoint.Value `json:"takerCommission"` TakerCommission fixedpoint.Value `json:"takerCommission"`
} }
//go:generate requestgen -method GET -url "/sapi/v1/asset/tradeFee" -type GetTradeFeeRequest -responseType []TradeFee //go:generate requestgen -method GET -url "/sapi/v1/asset/tradeFee" -type GetTradeFeeRequest -responseType []TradeFee

View File

@ -122,7 +122,8 @@ func New(key, secret string) *Exchange {
} }
return &Exchange{ return &Exchange{
key: key, key: key,
// pragma: allowlist nextline secret
secret: secret, secret: secret,
client: client, client: client,
futuresClient: futuresClient, futuresClient: futuresClient,

View File

@ -119,4 +119,3 @@ func Test_toLocalOrderTypeWithMarket(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, ftxapi.OrderTypeMarket, orderType) assert.Equal(t, ftxapi.OrderTypeMarket, orderType)
} }

View File

@ -90,8 +90,9 @@ func NewExchange(key, secret string, subAccount string) *Exchange {
client: client, client: client,
restEndpoint: u, restEndpoint: u,
key: key, key: key,
secret: secret, // pragma: allowlist nextline secret
subAccount: subAccount, secret: secret,
subAccount: subAccount,
} }
} }

View File

@ -66,7 +66,6 @@ func (c *RestClient) NewGetPositionsRequest() *GetPositionsRequest {
} }
} }
type Balance struct { type Balance struct {
Coin string `json:"coin"` Coin string `json:"coin"`
Free fixedpoint.Value `json:"free"` Free fixedpoint.Value `json:"free"`

View File

@ -68,6 +68,7 @@ func NewClient() *RestClient {
func (c *RestClient) Auth(key, secret, subAccount string) { func (c *RestClient) Auth(key, secret, subAccount string) {
c.Key = key c.Key = key
// pragma: allowlist nextline secret
c.Secret = secret c.Secret = secret
c.subAccount = subAccount c.subAccount = subAccount
} }
@ -200,5 +201,3 @@ func castPayload(payload interface{}) ([]byte, error) {
return nil, nil return nil, nil
} }

View File

@ -37,7 +37,7 @@ func TestClient_Requests(t *testing.T) {
return return
} }
ctx, cancel := context.WithTimeout(context.TODO(), 15 * time.Second) ctx, cancel := context.WithTimeout(context.TODO(), 15*time.Second)
defer cancel() defer cancel()
client := NewClient() client := NewClient()
@ -45,13 +45,13 @@ func TestClient_Requests(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string
tt func(t *testing.T) tt func(t *testing.T)
} { }{
{ {
name: "GetMarketsRequest", name: "GetMarketsRequest",
tt: func(t *testing.T) { tt: func(t *testing.T) {
req := client.NewGetMarketsRequest() req := client.NewGetMarketsRequest()
markets ,err := req.Do(ctx) markets, err := req.Do(ctx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, markets) assert.NotNil(t, markets)
t.Logf("markets: %+v", markets) t.Logf("markets: %+v", markets)
@ -61,7 +61,7 @@ func TestClient_Requests(t *testing.T) {
name: "GetAccountRequest", name: "GetAccountRequest",
tt: func(t *testing.T) { tt: func(t *testing.T) {
req := client.NewGetAccountRequest() req := client.NewGetAccountRequest()
account ,err := req.Do(ctx) account, err := req.Do(ctx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, account) assert.NotNil(t, account)
t.Logf("account: %+v", account) t.Logf("account: %+v", account)
@ -78,7 +78,7 @@ func TestClient_Requests(t *testing.T) {
Side(SideBuy). Side(SideBuy).
Market("LTC/USDT") Market("LTC/USDT")
createdOrder,err := req.Do(ctx) createdOrder, err := req.Do(ctx)
if assert.NoError(t, err) { if assert.NoError(t, err) {
assert.NotNil(t, createdOrder) assert.NotNil(t, createdOrder)
t.Logf("createdOrder: %+v", createdOrder) t.Logf("createdOrder: %+v", createdOrder)

View File

@ -25,7 +25,7 @@ type Market struct {
Underlying string `json:"underlying"` Underlying string `json:"underlying"`
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
Ask fixedpoint.Value `json:"ask"` Ask fixedpoint.Value `json:"ask"`
Bid fixedpoint.Value `json:"bid"` Bid fixedpoint.Value `json:"bid"`
Last fixedpoint.Value `json:"last"` Last fixedpoint.Value `json:"last"`
PostOnly bool `json:"postOnly"` PostOnly bool `json:"postOnly"`
Price fixedpoint.Value `json:"price"` Price fixedpoint.Value `json:"price"`
@ -33,6 +33,7 @@ type Market struct {
SizeIncrement fixedpoint.Value `json:"sizeIncrement"` SizeIncrement fixedpoint.Value `json:"sizeIncrement"`
Restricted bool `json:"restricted"` Restricted bool `json:"restricted"`
} }
//go:generate GetRequest -url "api/markets" -type GetMarketsRequest -responseDataType []Market //go:generate GetRequest -url "api/markets" -type GetMarketsRequest -responseDataType []Market
type GetMarketsRequest struct { type GetMarketsRequest struct {
client requestgen.APIClient client requestgen.APIClient

View File

@ -128,7 +128,7 @@ type Fill struct {
BaseCurrency string `json:"baseCurrency"` BaseCurrency string `json:"baseCurrency"`
QuoteCurrency string `json:"quoteCurrency"` QuoteCurrency string `json:"quoteCurrency"`
OrderId uint64 `json:"orderId"` OrderId uint64 `json:"orderId"`
TradeId uint64 `json:"tradeId"` TradeId uint64 `json:"tradeId"`
Price fixedpoint.Value `json:"price"` Price fixedpoint.Value `json:"price"`
Side Side `json:"side"` Side Side `json:"side"`
Size fixedpoint.Value `json:"size"` Size fixedpoint.Value `json:"size"`

View File

@ -1,3 +1,4 @@
//go:build ignore
// +build ignore // +build ignore
package main package main

View File

@ -92,6 +92,7 @@ func newRestRequest(c *http.Client, baseURL *url.URL) *restRequest {
func (r *restRequest) Auth(key, secret string) *restRequest { func (r *restRequest) Auth(key, secret string) *restRequest {
r.key = key r.key = key
// pragma: allowlist nextline secret
r.secret = secret r.secret = secret
return r return r
} }

View File

@ -5,8 +5,8 @@ import (
"strings" "strings"
"time" "time"
"github.com/c9s/bbgo/pkg/types"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
) )
// ex: 2019-03-05T09:56:55.728933+00:00 // ex: 2019-03-05T09:56:55.728933+00:00
@ -121,7 +121,7 @@ type position struct {
Cost fixedpoint.Value `json:"cost"` Cost fixedpoint.Value `json:"cost"`
EntryPrice fixedpoint.Value `json:"entryPrice"` EntryPrice fixedpoint.Value `json:"entryPrice"`
EstimatedLiquidationPrice fixedpoint.Value `json:"estimatedLiquidationPrice"` EstimatedLiquidationPrice fixedpoint.Value `json:"estimatedLiquidationPrice"`
Future string `json:"future"` Future string `json:"future"`
InitialMarginRequirement fixedpoint.Value `json:"initialMarginRequirement"` InitialMarginRequirement fixedpoint.Value `json:"initialMarginRequirement"`
LongOrderSize fixedpoint.Value `json:"longOrderSize"` LongOrderSize fixedpoint.Value `json:"longOrderSize"`
MaintenanceMarginRequirement fixedpoint.Value `json:"maintenanceMarginRequirement"` MaintenanceMarginRequirement fixedpoint.Value `json:"maintenanceMarginRequirement"`
@ -129,7 +129,7 @@ type position struct {
OpenSize fixedpoint.Value `json:"openSize"` OpenSize fixedpoint.Value `json:"openSize"`
RealizedPnl fixedpoint.Value `json:"realizedPnl"` RealizedPnl fixedpoint.Value `json:"realizedPnl"`
ShortOrderSize fixedpoint.Value `json:"shortOrderSize"` ShortOrderSize fixedpoint.Value `json:"shortOrderSize"`
Side string `json:"Side"` Side string `json:"Side"`
Size fixedpoint.Value `json:"size"` Size fixedpoint.Value `json:"size"`
UnrealizedPnl fixedpoint.Value `json:"unrealizedPnl"` UnrealizedPnl fixedpoint.Value `json:"unrealizedPnl"`
CollateralUsed fixedpoint.Value `json:"collateralUsed"` CollateralUsed fixedpoint.Value `json:"collateralUsed"`
@ -139,7 +139,7 @@ type balances struct {
Success bool `json:"success"` Success bool `json:"success"`
Result []struct { Result []struct {
Coin string `json:"coin"` Coin string `json:"coin"`
Free fixedpoint.Value `json:"free"` Free fixedpoint.Value `json:"free"`
Total fixedpoint.Value `json:"total"` Total fixedpoint.Value `json:"total"`
} `json:"result"` } `json:"result"`
@ -178,9 +178,9 @@ type marketsResponse struct {
} }
type market struct { type market struct {
Name string `json:"name"` Name string `json:"name"`
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
PostOnly bool `json:"postOnly"` PostOnly bool `json:"postOnly"`
PriceIncrement fixedpoint.Value `json:"priceIncrement"` PriceIncrement fixedpoint.Value `json:"priceIncrement"`
SizeIncrement fixedpoint.Value `json:"sizeIncrement"` SizeIncrement fixedpoint.Value `json:"sizeIncrement"`
MinProvideSize fixedpoint.Value `json:"minProvideSize"` MinProvideSize fixedpoint.Value `json:"minProvideSize"`
@ -188,12 +188,12 @@ type market struct {
Bid fixedpoint.Value `json:"bid"` Bid fixedpoint.Value `json:"bid"`
Ask fixedpoint.Value `json:"ask"` Ask fixedpoint.Value `json:"ask"`
Price fixedpoint.Value `json:"price"` Price fixedpoint.Value `json:"price"`
Type string `json:"type"` Type string `json:"type"`
BaseCurrency string `json:"baseCurrency"` BaseCurrency string `json:"baseCurrency"`
QuoteCurrency string `json:"quoteCurrency"` QuoteCurrency string `json:"quoteCurrency"`
Underlying string `json:"underlying"` Underlying string `json:"underlying"`
Restricted bool `json:"restricted"` Restricted bool `json:"restricted"`
HighLeverageFeeExempt bool `json:"highLeverageFeeExempt"` HighLeverageFeeExempt bool `json:"highLeverageFeeExempt"`
Change1h fixedpoint.Value `json:"change1h"` Change1h fixedpoint.Value `json:"change1h"`
Change24h fixedpoint.Value `json:"change24h"` Change24h fixedpoint.Value `json:"change24h"`
ChangeBod fixedpoint.Value `json:"changeBod"` ChangeBod fixedpoint.Value `json:"changeBod"`
@ -222,12 +222,12 @@ type HistoricalPricesResponse struct {
} }
type Candle struct { type Candle struct {
Close fixedpoint.Value `json:"close"` Close fixedpoint.Value `json:"close"`
High fixedpoint.Value `json:"high"` High fixedpoint.Value `json:"high"`
Low fixedpoint.Value `json:"low"` Low fixedpoint.Value `json:"low"`
Open fixedpoint.Value `json:"open"` Open fixedpoint.Value `json:"open"`
StartTime datetime `json:"startTime"` StartTime datetime `json:"startTime"`
Volume fixedpoint.Value `json:"volume"` Volume fixedpoint.Value `json:"volume"`
} }
type ordersHistoryResponse struct { type ordersHistoryResponse struct {
@ -248,24 +248,24 @@ type cancelOrderResponse struct {
} }
type order struct { type order struct {
CreatedAt datetime `json:"createdAt"` CreatedAt datetime `json:"createdAt"`
FilledSize fixedpoint.Value `json:"filledSize"` FilledSize fixedpoint.Value `json:"filledSize"`
// Future field is not defined in the response format table but in the response example. // Future field is not defined in the response format table but in the response example.
Future string `json:"future"` Future string `json:"future"`
ID int64 `json:"id"` ID int64 `json:"id"`
Market string `json:"market"` Market string `json:"market"`
Price fixedpoint.Value `json:"price"` Price fixedpoint.Value `json:"price"`
AvgFillPrice fixedpoint.Value `json:"avgFillPrice"` AvgFillPrice fixedpoint.Value `json:"avgFillPrice"`
RemainingSize fixedpoint.Value `json:"remainingSize"` RemainingSize fixedpoint.Value `json:"remainingSize"`
Side string `json:"side"` Side string `json:"side"`
Size fixedpoint.Value `json:"size"` Size fixedpoint.Value `json:"size"`
Status string `json:"status"` Status string `json:"status"`
Type string `json:"type"` Type string `json:"type"`
ReduceOnly bool `json:"reduceOnly"` ReduceOnly bool `json:"reduceOnly"`
Ioc bool `json:"ioc"` Ioc bool `json:"ioc"`
PostOnly bool `json:"postOnly"` PostOnly bool `json:"postOnly"`
ClientId string `json:"clientId"` ClientId string `json:"clientId"`
Liquidation bool `json:"liquidation"` Liquidation bool `json:"liquidation"`
} }
type orderResponse struct { type orderResponse struct {
@ -299,18 +299,18 @@ type depositHistoryResponse struct {
} }
type depositHistory struct { type depositHistory struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Coin string `json:"coin"` Coin string `json:"coin"`
TxID string `json:"txid"` TxID string `json:"txid"`
Address address `json:"address"` Address address `json:"address"`
Confirmations int64 `json:"confirmations"` Confirmations int64 `json:"confirmations"`
ConfirmedTime datetime `json:"confirmedTime"` ConfirmedTime datetime `json:"confirmedTime"`
Fee fixedpoint.Value `json:"fee"` Fee fixedpoint.Value `json:"fee"`
SentTime datetime `json:"sentTime"` SentTime datetime `json:"sentTime"`
Size fixedpoint.Value `json:"size"` Size fixedpoint.Value `json:"size"`
Status string `json:"status"` Status string `json:"status"`
Time datetime `json:"time"` Time datetime `json:"time"`
Notes string `json:"notes"` Notes string `json:"notes"`
} }
/** /**
@ -354,22 +354,22 @@ type fillsResponse struct {
} }
*/ */
type fill struct { type fill struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Market string `json:"market"` Market string `json:"market"`
Future string `json:"future"` Future string `json:"future"`
BaseCurrency string `json:"baseCurrency"` BaseCurrency string `json:"baseCurrency"`
QuoteCurrency string `json:"quoteCurrency"` QuoteCurrency string `json:"quoteCurrency"`
Type string `json:"type"` Type string `json:"type"`
Side types.SideType `json:"side"` Side types.SideType `json:"side"`
Price fixedpoint.Value `json:"price"` Price fixedpoint.Value `json:"price"`
Size fixedpoint.Value `json:"size"` Size fixedpoint.Value `json:"size"`
OrderId uint64 `json:"orderId"` OrderId uint64 `json:"orderId"`
Time datetime `json:"time"` Time datetime `json:"time"`
TradeId uint64 `json:"tradeId"` TradeId uint64 `json:"tradeId"`
FeeRate fixedpoint.Value `json:"feeRate"` FeeRate fixedpoint.Value `json:"feeRate"`
Fee fixedpoint.Value `json:"fee"` Fee fixedpoint.Value `json:"fee"`
FeeCurrency string `json:"feeCurrency"` FeeCurrency string `json:"feeCurrency"`
Liquidity string `json:"liquidity"` Liquidity string `json:"liquidity"`
} }
type transferResponse struct { type transferResponse struct {
@ -378,12 +378,12 @@ type transferResponse struct {
} }
type transfer struct { type transfer struct {
Id uint `json:"id"` Id uint `json:"id"`
Coin string `json:"coin"` Coin string `json:"coin"`
Size fixedpoint.Value `json:"size"` Size fixedpoint.Value `json:"size"`
Time string `json:"time"` Time string `json:"time"`
Notes string `json:"notes"` Notes string `json:"notes"`
Status string `json:"status"` Status string `json:"status"`
} }
func (t *transfer) String() string { func (t *transfer) String() string {

View File

@ -42,4 +42,3 @@ func (r *walletRequest) DepositHistory(ctx context.Context, since time.Time, unt
return d, nil return d, nil
} }

View File

@ -37,8 +37,9 @@ type klineSubscription struct {
func NewStream(key, secret string, subAccount string, e *Exchange) *Stream { func NewStream(key, secret string, subAccount string, e *Exchange) *Stream {
s := &Stream{ s := &Stream{
exchange: e, exchange: e,
key: key, key: key,
// pragma: allowlist nextline secret
secret: secret, secret: secret,
subAccount: subAccount, subAccount: subAccount,
StandardStream: &types.StandardStream{}, StandardStream: &types.StandardStream{},

File diff suppressed because it is too large Load Diff

View File

@ -182,6 +182,7 @@ func Test_insertAt(t *testing.T) {
func Test_newLoginRequest(t *testing.T) { func Test_newLoginRequest(t *testing.T) {
// From API doc: https://docs.ftx.com/?javascript#authentication-2 // From API doc: https://docs.ftx.com/?javascript#authentication-2
r := newLoginRequest("", "Y2QTHI23f23f23jfjas23f23To0RfUwX3H42fvN-", time.Unix(0, 1557246346499*int64(time.Millisecond)), "") r := newLoginRequest("", "Y2QTHI23f23f23jfjas23f23To0RfUwX3H42fvN-", time.Unix(0, 1557246346499*int64(time.Millisecond)), "")
// pragma: allowlist nextline secret
expectedSignature := "d10b5a67a1a941ae9463a60b285ae845cdeac1b11edc7da9977bef0228b96de9" expectedSignature := "d10b5a67a1a941ae9463a60b285ae845cdeac1b11edc7da9977bef0228b96de9"
assert.Equal(t, expectedSignature, r.Login.Signature) assert.Equal(t, expectedSignature, r.Login.Signature)
jsonStr, err := json.Marshal(r) jsonStr, err := json.Marshal(r)

View File

@ -245,4 +245,3 @@ func toGlobalTrade(fill kucoinapi.Fill) types.Trade {
} }
return trade return trade
} }

View File

@ -44,7 +44,8 @@ func New(key, secret, passphrase string) *Exchange {
} }
return &Exchange{ return &Exchange{
key: key, key: key,
// pragma: allowlist nextline secret
secret: secret, secret: secret,
passphrase: passphrase, passphrase: passphrase,
client: client, client: client,

View File

@ -53,7 +53,7 @@ func main() {
defer resp.Body.Close() defer resp.Body.Close()
r := &ApiResponse{} r := &ApiResponse{}
if err := json.NewDecoder(resp.Body).Decode(r) ; err != nil { if err := json.NewDecoder(resp.Body).Decode(r); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -61,7 +61,6 @@ type GetPublicBulletRequest struct {
client requestgen.APIClient client requestgen.APIClient
} }
//go:generate requestgen -type GetPrivateBulletRequest -method "POST" -url "/api/v1/bullet-private" -responseType .APIResponse -responseDataField Data -responseDataType .Bullet //go:generate requestgen -type GetPrivateBulletRequest -method "POST" -url "/api/v1/bullet-private" -responseType .APIResponse -responseDataField Data -responseDataType .Bullet
type GetPrivateBulletRequest struct { type GetPrivateBulletRequest struct {
client requestgen.AuthenticatedAPIClient client requestgen.AuthenticatedAPIClient

View File

@ -58,6 +58,7 @@ func NewClient() *RestClient {
func (c *RestClient) Auth(key, secret, passphrase string) { func (c *RestClient) Auth(key, secret, passphrase string) {
c.Key = key c.Key = key
// pragma: allowlist nextline secret
c.Secret = secret c.Secret = secret
c.Passphrase = passphrase c.Passphrase = passphrase
} }

View File

@ -9,9 +9,9 @@ import (
"github.com/c9s/bbgo/pkg/depth" "github.com/c9s/bbgo/pkg/depth"
"github.com/c9s/bbgo/pkg/exchange/kucoin/kucoinapi" "github.com/c9s/bbgo/pkg/exchange/kucoin/kucoinapi"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
"github.com/c9s/bbgo/pkg/util" "github.com/c9s/bbgo/pkg/util"
"github.com/c9s/bbgo/pkg/fixedpoint"
) )
const readTimeout = 30 * time.Second const readTimeout = 30 * time.Second
@ -20,8 +20,8 @@ const readTimeout = 30 * time.Second
type Stream struct { type Stream struct {
types.StandardStream types.StandardStream
client *kucoinapi.RestClient client *kucoinapi.RestClient
exchange *Exchange exchange *Exchange
bullet *kucoinapi.Bullet bullet *kucoinapi.Bullet
candleEventCallbacks []func(candle *WebSocketCandleEvent, e *WebSocketEvent) candleEventCallbacks []func(candle *WebSocketCandleEvent, e *WebSocketEvent)
@ -125,8 +125,8 @@ func (s *Stream) handlePrivateOrderEvent(e *WebSocketPrivateOrderEvent) {
IsBuyer: e.Side == "buy", IsBuyer: e.Side == "buy",
IsMaker: e.Liquidity == "maker", IsMaker: e.Liquidity == "maker",
Time: types.Time(e.Ts.Time()), Time: types.Time(e.Ts.Time()),
Fee: fixedpoint.Zero, // not supported Fee: fixedpoint.Zero, // not supported
FeeCurrency: "", // not supported FeeCurrency: "", // not supported
}) })
} }

File diff suppressed because it is too large Load Diff

View File

@ -47,8 +47,9 @@ func New(key, secret string) *Exchange {
client := maxapi.NewRestClient(baseURL) client := maxapi.NewRestClient(baseURL)
client.Auth(key, secret) client.Auth(key, secret)
return &Exchange{ return &Exchange{
client: client, client: client,
key: key, key: key,
// pragma: allowlist nextline secret
secret: secret, secret: secret,
v3order: &v3.OrderService{Client: client}, v3order: &v3.OrderService{Client: client},
v3margin: &v3.MarginService{Client: client}, v3margin: &v3.MarginService{Client: client},

View File

@ -110,4 +110,3 @@ func TestAccountService_NewGetDepositHistoryRequest(t *testing.T) {
assert.NotEmpty(t, deposits) assert.NotEmpty(t, deposits)
t.Logf("deposits: %+v", deposits) t.Logf("deposits: %+v", deposits)
} }

View File

@ -22,5 +22,3 @@ func integrationTestConfigured(t *testing.T, prefix string) (key, secret string,
} }
return key, secret, ok return key, secret, ok
} }

View File

@ -130,7 +130,9 @@ func NewRestClient(baseURL string) *RestClient {
// Auth sets api key and secret for usage is requests that requires authentication. // Auth sets api key and secret for usage is requests that requires authentication.
func (c *RestClient) Auth(key string, secret string) *RestClient { func (c *RestClient) Auth(key string, secret string) *RestClient {
// pragma: allowlist nextline secret
c.APIKey = key c.APIKey = key
// pragma: allowlist nextline secret
c.APISecret = secret c.APISecret = secret
return c return c
} }

View File

@ -158,4 +158,3 @@ type MarginRepayRequest struct {
currency string `param:"currency,slug,required"` currency string `param:"currency,slug,required"`
amount string `param:"amount"` amount string `param:"amount"`
} }

View File

@ -28,4 +28,3 @@ type WebsocketCommand struct {
Action string `json:"action"` Action string `json:"action"`
Subscriptions []Subscription `json:"subscriptions,omitempty"` Subscriptions []Subscription `json:"subscriptions,omitempty"`
} }

View File

@ -56,8 +56,8 @@ type WithdrawalAddress struct {
//go:generate GetRequest -url "v2/withdraw_addresses" -type GetWithdrawalAddressesRequest -responseType []WithdrawalAddress //go:generate GetRequest -url "v2/withdraw_addresses" -type GetWithdrawalAddressesRequest -responseType []WithdrawalAddress
type GetWithdrawalAddressesRequest struct { type GetWithdrawalAddressesRequest struct {
client requestgen.AuthenticatedAPIClient client requestgen.AuthenticatedAPIClient
currency string `param:"currency,required"` currency string `param:"currency,required"`
} }
type WithdrawalService struct { type WithdrawalService struct {

View File

@ -44,7 +44,8 @@ func NewStream(key, secret string) *Stream {
stream := &Stream{ stream := &Stream{
StandardStream: types.NewStandardStream(), StandardStream: types.NewStandardStream(),
key: key, key: key,
secret: secret, // pragma: allowlist nextline secret
secret: secret,
} }
stream.SetEndpointCreator(stream.getEndpoint) stream.SetEndpointCreator(stream.getEndpoint)
stream.SetParser(max.ParseMessage) stream.SetParser(max.ParseMessage)
@ -116,7 +117,9 @@ func (s *Stream) handleConnect() {
nonce := time.Now().UnixNano() / int64(time.Millisecond) nonce := time.Now().UnixNano() / int64(time.Millisecond)
auth := &max.AuthMessage{ auth := &max.AuthMessage{
Action: "auth", // pragma: allowlist nextline secret
Action: "auth",
// pragma: allowlist nextline secret
APIKey: s.key, APIKey: s.key,
Nonce: nonce, Nonce: nonce,
Signature: signPayload(fmt.Sprintf("%d", nonce), s.secret), Signature: signPayload(fmt.Sprintf("%d", nonce), s.secret),

View File

@ -31,7 +31,6 @@ func TestExchange_QueryTickers_SomeSymbols(t *testing.T) {
return return
} }
e := New(key, secret) e := New(key, secret)
got, err := e.QueryTickers(context.Background(), "BTCUSDT", "ETHUSDT") got, err := e.QueryTickers(context.Background(), "BTCUSDT", "ETHUSDT")
if assert.NoError(t, err) { if assert.NoError(t, err) {

View File

@ -38,7 +38,8 @@ func New(key, secret, passphrase string) *Exchange {
} }
return &Exchange{ return &Exchange{
key: key, key: key,
// pragma: allowlist nextline secret
secret: secret, secret: secret,
passphrase: passphrase, passphrase: passphrase,
client: client, client: client,
@ -275,7 +276,7 @@ func (e *Exchange) NewStream() types.Stream {
} }
func (e *Exchange) QueryKLines(ctx context.Context, symbol string, interval types.Interval, options types.KLineQueryOptions) ([]types.KLine, error) { func (e *Exchange) QueryKLines(ctx context.Context, symbol string, interval types.Interval, options types.KLineQueryOptions) ([]types.KLine, error) {
if err := marketDataLimiter.Wait(ctx) ; err != nil { if err := marketDataLimiter.Wait(ctx); err != nil {
return nil, err return nil, err
} }

View File

@ -1,3 +1,4 @@
//go:build ignore
// +build ignore // +build ignore
package main package main

View File

@ -91,6 +91,7 @@ func NewClient() *RestClient {
func (c *RestClient) Auth(key, secret, passphrase string) { func (c *RestClient) Auth(key, secret, passphrase string) {
c.Key = key c.Key = key
// pragma: allowlist nextline secret
c.Secret = secret c.Secret = secret
c.Passphrase = passphrase c.Passphrase = passphrase
} }

View File

@ -28,9 +28,9 @@ type Stream struct {
client *okexapi.RestClient client *okexapi.RestClient
// public callbacks // public callbacks
candleEventCallbacks []func(candle Candle) candleEventCallbacks []func(candle Candle)
bookEventCallbacks []func(book BookEvent) bookEventCallbacks []func(book BookEvent)
eventCallbacks []func(event WebSocketEvent) eventCallbacks []func(event WebSocketEvent)
accountEventCallbacks []func(account okexapi.Account) accountEventCallbacks []func(account okexapi.Account)
orderDetailsEventCallbacks []func(orderDetails []okexapi.OrderDetails) orderDetailsEventCallbacks []func(orderDetails []okexapi.OrderDetails)

File diff suppressed because it is too large Load Diff

View File

@ -349,11 +349,11 @@ func NewFromString(input string) (Value, error) {
} }
} }
if hasDecimal { if hasDecimal {
after := input[dotIndex+1 : len(input)] after := input[dotIndex+1:]
if decimalCount >= 8 { if decimalCount >= 8 {
after = after[0:8] + "." + after[8:len(after)] after = after[0:8] + "." + after[8:]
} else { } else {
after = after[0:decimalCount] + strings.Repeat("0", 8-decimalCount) + after[decimalCount:len(after)] after = after[0:decimalCount] + strings.Repeat("0", 8-decimalCount) + after[decimalCount:]
} }
input = input[0:dotIndex] + after input = input[0:dotIndex] + after
v, err := strconv.ParseFloat(input, 64) v, err := strconv.ParseFloat(input, 64)
@ -368,7 +368,7 @@ func NewFromString(input string) (Value, error) {
return Value(int64(math.Trunc(v))), nil return Value(int64(math.Trunc(v))), nil
} else if hasScientificNotion { } else if hasScientificNotion {
exp, err := strconv.ParseInt(input[scIndex+1:len(input)], 10, 32) exp, err := strconv.ParseInt(input[scIndex+1:], 10, 32)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@ -282,7 +282,7 @@ func (dn Value) FormatString(prec int) string {
// decimal within // decimal within
dec := nd + e dec := nd + e
decimals := digits[dec:min(dec+prec, nd)] decimals := digits[dec:min(dec+prec, nd)]
return sign + digits[:dec] + "." + decimals + strings.Repeat("0", max(0, prec - len(decimals))) return sign + digits[:dec] + "." + decimals + strings.Repeat("0", max(0, prec-len(decimals)))
} else if 0 < dn.exp && dn.exp <= digitsMax { } else if 0 < dn.exp && dn.exp <= digitsMax {
// decimal to the right // decimal to the right
if prec > 0 { if prec > 0 {
@ -403,7 +403,7 @@ func (dn Value) FormatPercentage(prec int) string {
// decimal within // decimal within
dec := nd + e dec := nd + e
decimals := digits[dec:min(dec+prec, nd)] decimals := digits[dec:min(dec+prec, nd)]
return sign + digits[:dec] + "." + decimals + strings.Repeat("0", max(0, prec - len(decimals))) + "%" return sign + digits[:dec] + "." + decimals + strings.Repeat("0", max(0, prec-len(decimals))) + "%"
} else if 0 < exp && exp <= digitsMax { } else if 0 < exp && exp <= digitsMax {
// decimal to the right // decimal to the right
if prec > 0 { if prec > 0 {

View File

@ -19,7 +19,7 @@ func TestNumFractionalDigitsLegacy(t *testing.T) {
}, },
{ {
name: "zero underflow", name: "zero underflow",
v: MustNewFromString("1e-100"), v: MustNewFromString("1e-100"),
want: 0, want: 0,
}, },
} }

View File

@ -1,10 +1,10 @@
package fixedpoint package fixedpoint
import ( import (
"encoding/json"
"github.com/stretchr/testify/assert"
"math/big" "math/big"
"testing" "testing"
"github.com/stretchr/testify/assert"
"encoding/json"
) )
const Delta = 1e-9 const Delta = 1e-9
@ -167,7 +167,6 @@ func TestJson(t *testing.T) {
assert.Equal(t, "0.00000000", p.FormatString(8)) assert.Equal(t, "0.00000000", p.FormatString(8))
assert.Equal(t, "0.00000000", string(e)) assert.Equal(t, "0.00000000", string(e))
_ = json.Unmarshal([]byte("0.00153917575"), &p) _ = json.Unmarshal([]byte("0.00153917575"), &p)
assert.Equal(t, "0.00153917", p.FormatString(8)) assert.Equal(t, "0.00153917", p.FormatString(8))

View File

@ -97,14 +97,14 @@ func toSide(side pb.Side) types.SideType {
func toSubmitOrders(pbOrders []*pb.SubmitOrder) (submitOrders []types.SubmitOrder) { func toSubmitOrders(pbOrders []*pb.SubmitOrder) (submitOrders []types.SubmitOrder) {
for _, pbOrder := range pbOrders { for _, pbOrder := range pbOrders {
submitOrders = append(submitOrders, types.SubmitOrder{ submitOrders = append(submitOrders, types.SubmitOrder{
ClientOrderID: pbOrder.ClientOrderId, ClientOrderID: pbOrder.ClientOrderId,
Symbol: pbOrder.Symbol, Symbol: pbOrder.Symbol,
Side: toSide(pbOrder.Side), Side: toSide(pbOrder.Side),
Type: toOrderType(pbOrder.OrderType), Type: toOrderType(pbOrder.OrderType),
Price: fixedpoint.MustNewFromString(pbOrder.Price), Price: fixedpoint.MustNewFromString(pbOrder.Price),
Quantity: fixedpoint.MustNewFromString(pbOrder.Quantity), Quantity: fixedpoint.MustNewFromString(pbOrder.Quantity),
StopPrice: fixedpoint.MustNewFromString(pbOrder.StopPrice), StopPrice: fixedpoint.MustNewFromString(pbOrder.StopPrice),
TimeInForce: "", TimeInForce: "",
}) })
} }

View File

@ -2,8 +2,8 @@ package indicator
import ( import (
"encoding/json" "encoding/json"
"testing"
"fmt" "fmt"
"testing"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
@ -51,27 +51,31 @@ func Test_DMI(t *testing.T) {
return klines return klines
} }
type output struct{dip float64; dim float64; adx float64} type output struct {
dip float64
dim float64
adx float64
}
tests := []struct { tests := []struct {
name string name string
klines []types.KLine klines []types.KLine
want output want output
next output next output
total int total int
}{ }{
{ {
name: "test_dmi", name: "test_dmi",
klines: buildKLines(highb, lowb, clozeb), klines: buildKLines(highb, lowb, clozeb),
want: output{dip: 4.85114, dim: 1.339736, adx: 37.857156}, want: output{dip: 4.85114, dim: 1.339736, adx: 37.857156},
next: output{dip: 4.813853, dim: 1.67532, adx: 36.111434}, next: output{dip: 4.813853, dim: 1.67532, adx: 36.111434},
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
dmi := &DMI{ dmi := &DMI{
IntervalWindow: types.IntervalWindow{Window: 5}, IntervalWindow: types.IntervalWindow{Window: 5},
ADXSmoothing: 14, ADXSmoothing: 14,
} }
dmi.calculateAndUpdate(tt.klines) dmi.calculateAndUpdate(tt.klines)
assert.InDelta(t, dmi.GetDIPlus().Last(), tt.want.dip, Delta) assert.InDelta(t, dmi.GetDIPlus().Last(), tt.want.dip, Delta)

View File

@ -37,6 +37,7 @@ type AuthInteract struct {
func (it *AuthInteract) Commands(interact *Interact) { func (it *AuthInteract) Commands(interact *Interact) {
if it.Strict { if it.Strict {
// generate a one-time-use otp // generate a one-time-use otp
// pragma: allowlist nextline secret
if it.OneTimePasswordKey == nil { if it.OneTimePasswordKey == nil {
opts := totp.GenerateOpts{ opts := totp.GenerateOpts{
Issuer: "interact", Issuer: "interact",
@ -48,7 +49,7 @@ func (it *AuthInteract) Commands(interact *Interact) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
// pragma: allowlist nextline secret
it.OneTimePasswordKey = key it.OneTimePasswordKey = key
} }
interact.Command("/auth", "authorize", func(reply Reply, session Session) error { interact.Command("/auth", "authorize", func(reply Reply, session Session) error {

View File

@ -14,7 +14,7 @@ func TestGetMigrationsMap(t *testing.T) {
func TestMergeMigrationsMap(t *testing.T) { func TestMergeMigrationsMap(t *testing.T) {
MergeMigrationsMap(map[int64]*rockhopper.Migration{ MergeMigrationsMap(map[int64]*rockhopper.Migration{
2: &rockhopper.Migration{}, 2: {},
3: &rockhopper.Migration{}, 3: {},
}) })
} }

View File

@ -14,7 +14,7 @@ func TestGetMigrationsMap(t *testing.T) {
func TestMergeMigrationsMap(t *testing.T) { func TestMergeMigrationsMap(t *testing.T) {
MergeMigrationsMap(map[int64]*rockhopper.Migration{ MergeMigrationsMap(map[int64]*rockhopper.Migration{
2: &rockhopper.Migration{}, 2: {},
3: &rockhopper.Migration{}, 3: {},
}) })
} }

View File

@ -17,11 +17,15 @@ func collectSessionEnvVars(sessions map[string]*bbgo.ExchangeSession) (envVars m
} }
if len(session.EnvVarPrefix) > 0 { if len(session.EnvVarPrefix) > 0 {
// pragma: allowlist nextline secret
envVars[session.EnvVarPrefix+"_API_KEY"] = session.Key envVars[session.EnvVarPrefix+"_API_KEY"] = session.Key
// pragma: allowlist nextline secret
envVars[session.EnvVarPrefix+"_API_SECRET"] = session.Secret envVars[session.EnvVarPrefix+"_API_SECRET"] = session.Secret
} else if len(session.Name) > 0 { } else if len(session.Name) > 0 {
sn := strings.ToUpper(session.Name) sn := strings.ToUpper(session.Name)
// pragma: allowlist nextline secret
envVars[sn+"_API_KEY"] = session.Key envVars[sn+"_API_KEY"] = session.Key
// pragma: allowlist nextline secret
envVars[sn+"_API_SECRET"] = session.Secret envVars[sn+"_API_SECRET"] = session.Secret
} else { } else {
err = fmt.Errorf("session %s name or env var prefix is not defined", session.Name) err = fmt.Errorf("session %s name or env var prefix is not defined", session.Name)

View File

@ -41,22 +41,22 @@ func (s *AccountService) InsertAsset(time time.Time, session string, name types.
price_in_usd, price_in_usd,
is_margin, is_isolated, isolated_symbol) is_margin, is_isolated, isolated_symbol)
values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);`, values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);`,
session, session,
name, name,
account, account,
time, time,
v.Currency, v.Currency,
v.InUSD, v.InUSD,
v.InBTC, v.InBTC,
v.Total, v.Total,
v.Available, v.Available,
v.Locked, v.Locked,
v.Borrowed, v.Borrowed,
v.NetAsset, v.NetAsset,
v.PriceInUSD, v.PriceInUSD,
isMargin, isMargin,
isIsolatedMargin, isIsolatedMargin,
isolatedMarginSymbol) isolatedMarginSymbol)
err = multierr.Append(err, _err) // successful request err = multierr.Append(err, _err) // successful request

View File

@ -76,4 +76,3 @@ func (store JsonStore) Save(val interface{}) error {
p := filepath.Join(store.Directory, store.ID) + ".json" p := filepath.Join(store.Directory, store.ID) + ".json"
return ioutil.WriteFile(p, data, 0666) return ioutil.WriteFile(p, data, 0666)
} }

View File

@ -19,6 +19,7 @@ func NewRedisPersistenceService(config *RedisPersistenceConfig) *RedisPersistenc
client := redis.NewClient(&redis.Options{ client := redis.NewClient(&redis.Options{
Addr: net.JoinHostPort(config.Host, config.Port), Addr: net.JoinHostPort(config.Host, config.Port),
// Username: "", // username is only for redis 6.0 // Username: "", // username is only for redis 6.0
// pragma: allowlist nextline secret
Password: config.Password, // no password set Password: config.Password, // no password set
DB: config.DB, // use default DB DB: config.DB, // use default DB
}) })

View File

@ -93,8 +93,6 @@ func (s *RewardService) Sync(ctx context.Context, exchange types.Exchange) error
return <-errC return <-errC
} }
type CurrencyPositionMap map[string]fixedpoint.Value type CurrencyPositionMap map[string]fixedpoint.Value
func (s *RewardService) AggregateUnspentCurrencyPosition(ctx context.Context, ex types.ExchangeName, since time.Time) (CurrencyPositionMap, error) { func (s *RewardService) AggregateUnspentCurrencyPosition(ctx context.Context, ex types.ExchangeName, since time.Time) (CurrencyPositionMap, error) {
@ -128,8 +126,8 @@ func (s *RewardService) QueryUnspentSince(ctx context.Context, ex types.Exchange
sql += " ORDER BY created_at ASC" sql += " ORDER BY created_at ASC"
rows, err := s.DB.NamedQueryContext(ctx, sql, map[string]interface{}{ rows, err := s.DB.NamedQueryContext(ctx, sql, map[string]interface{}{
"exchange": ex, "exchange": ex,
"since": since, "since": since,
}) })
if err != nil { if err != nil {

View File

@ -74,7 +74,6 @@ func TestRewardService_InsertAndQueryUnspent(t *testing.T) {
assert.Equal(t, types.RewardCommission, rewards[0].Type) assert.Equal(t, types.RewardCommission, rewards[0].Type)
} }
func TestRewardService_AggregateUnspentCurrencyPosition(t *testing.T) { func TestRewardService_AggregateUnspentCurrencyPosition(t *testing.T) {
db, err := prepareDB(t) db, err := prepareDB(t)
if err != nil { if err != nil {
@ -126,7 +125,7 @@ func TestRewardService_AggregateUnspentCurrencyPosition(t *testing.T) {
}) })
assert.NoError(t, err) assert.NoError(t, err)
currencyPositions, err := service.AggregateUnspentCurrencyPosition(ctx, types.ExchangeMax, now.Add(-10 * time.Second)) currencyPositions, err := service.AggregateUnspentCurrencyPosition(ctx, types.ExchangeMax, now.Add(-10*time.Second))
assert.NoError(t, err) assert.NoError(t, err)
assert.NotEmpty(t, currencyPositions) assert.NotEmpty(t, currencyPositions)
assert.Len(t, currencyPositions, 2) assert.Len(t, currencyPositions, 2)

View File

@ -7,8 +7,8 @@ import (
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/c9s/bbgo/pkg/types"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
) )
func TestWithdrawService(t *testing.T) { func TestWithdrawService(t *testing.T) {

View File

@ -154,7 +154,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
// s.pvDivergence.OnUpdate(func(corr float64) { // s.pvDivergence.OnUpdate(func(corr float64) {
// //fmt.Printf("now we've got corr: %f\n", corr) // //fmt.Printf("now we've got corr: %f\n", corr)
// }) // })
windowSize := 360/s.Interval.Minutes() windowSize := 360 / s.Interval.Minutes()
if windowSize == 0 { if windowSize == 0 {
windowSize = 3 windowSize = 3
} }

View File

@ -340,7 +340,6 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
log.WithError(err).Errorf("can not place order") log.WithError(err).Errorf("can not place order")
} }
if err := s.activeAdjustmentOrders.GracefulCancel(ctx, s.session.Exchange); err != nil { if err := s.activeAdjustmentOrders.GracefulCancel(ctx, s.session.Exchange); err != nil {
log.WithError(err).Errorf("graceful cancel order error") log.WithError(err).Errorf("graceful cancel order error")
} }

View File

@ -11,10 +11,10 @@ type State struct {
CoveredPosition fixedpoint.Value `json:"coveredPosition,omitempty"` CoveredPosition fixedpoint.Value `json:"coveredPosition,omitempty"`
// Deprecated: // Deprecated:
Position *types.Position `json:"position,omitempty"` Position *types.Position `json:"position,omitempty"`
// Deprecated: // Deprecated:
ProfitStats ProfitStats `json:"profitStats,omitempty"` ProfitStats ProfitStats `json:"profitStats,omitempty"`
} }
type ProfitStats struct { type ProfitStats struct {

View File

@ -11,40 +11,40 @@ import (
// Super basic Series type that simply holds the float64 data // Super basic Series type that simply holds the float64 data
// with size limit (the only difference compare to float64slice) // with size limit (the only difference compare to float64slice)
type Queue struct { type Queue struct {
arr []float64 arr []float64
size int size int
} }
func NewQueue(size int) *Queue { func NewQueue(size int) *Queue {
return &Queue{ return &Queue{
arr: make([]float64, 0, size), arr: make([]float64, 0, size),
size: size, size: size,
} }
} }
func (inc *Queue) Last() float64 { func (inc *Queue) Last() float64 {
if len(inc.arr) == 0 { if len(inc.arr) == 0 {
return 0 return 0
} }
return inc.arr[len(inc.arr)-1] return inc.arr[len(inc.arr)-1]
} }
func (inc *Queue) Index(i int) float64 { func (inc *Queue) Index(i int) float64 {
if len(inc.arr)-i-1 < 0 { if len(inc.arr)-i-1 < 0 {
return 0 return 0
} }
return inc.arr[len(inc.arr)-i-1] return inc.arr[len(inc.arr)-i-1]
} }
func (inc *Queue) Length() int { func (inc *Queue) Length() int {
return len(inc.arr) return len(inc.arr)
} }
func (inc *Queue) Update(v float64) { func (inc *Queue) Update(v float64) {
inc.arr = append(inc.arr, v) inc.arr = append(inc.arr, v)
if len(inc.arr) > inc.size { if len(inc.arr) > inc.size {
inc.arr = inc.arr[len(inc.arr)-inc.size:] inc.arr = inc.arr[len(inc.arr)-inc.size:]
} }
} }
var _ Series = &Queue{} var _ Series = &Queue{}

View File

@ -91,7 +91,7 @@ func Test_formatPrice(t *testing.T) {
{ {
name: "no fraction", name: "no fraction",
args: args{ args: args{
price: fixedpoint.NewFromFloat(10.0), price: fixedpoint.NewFromFloat(10.0),
tickSize: fixedpoint.NewFromFloat(0.001), tickSize: fixedpoint.NewFromFloat(0.001),
}, },
want: "10.000", want: "10.000",
@ -99,7 +99,7 @@ func Test_formatPrice(t *testing.T) {
{ {
name: "fraction truncate", name: "fraction truncate",
args: args{ args: args{
price: fixedpoint.NewFromFloat(2.334), price: fixedpoint.NewFromFloat(2.334),
tickSize: fixedpoint.NewFromFloat(0.01), tickSize: fixedpoint.NewFromFloat(0.01),
}, },
want: "2.33", want: "2.33",
@ -107,7 +107,7 @@ func Test_formatPrice(t *testing.T) {
{ {
name: "fraction", name: "fraction",
args: args{ args: args{
price: fixedpoint.NewFromFloat(2.334), price: fixedpoint.NewFromFloat(2.334),
tickSize: fixedpoint.NewFromFloat(0.0001), tickSize: fixedpoint.NewFromFloat(0.0001),
}, },
want: "2.3340", want: "2.3340",
@ -115,7 +115,7 @@ func Test_formatPrice(t *testing.T) {
{ {
name: "more fraction", name: "more fraction",
args: args{ args: args{
price: fixedpoint.MustNewFromString("2.1234567898888"), price: fixedpoint.MustNewFromString("2.1234567898888"),
tickSize: fixedpoint.NewFromFloat(0.0001), tickSize: fixedpoint.NewFromFloat(0.0001),
}, },
want: "2.1234", want: "2.1234",
@ -125,7 +125,7 @@ func Test_formatPrice(t *testing.T) {
binanceFormatRE := regexp.MustCompile("^([0-9]{1,20})(.[0-9]{1,20})?$") binanceFormatRE := regexp.MustCompile("^([0-9]{1,20})(.[0-9]{1,20})?$")
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got := formatPrice(tt.args.price, tt.args.tickSize); got := formatPrice(tt.args.price, tt.args.tickSize)
if got != tt.want { if got != tt.want {
t.Errorf("formatPrice() = %v, want %v", got, tt.want) t.Errorf("formatPrice() = %v, want %v", got, tt.want)
} }
@ -135,10 +135,9 @@ func Test_formatPrice(t *testing.T) {
} }
} }
func Test_formatQuantity(t *testing.T) { func Test_formatQuantity(t *testing.T) {
type args struct { type args struct {
quantity fixedpoint.Value quantity fixedpoint.Value
tickSize fixedpoint.Value tickSize fixedpoint.Value
} }
tests := []struct { tests := []struct {
@ -183,7 +182,7 @@ func Test_formatQuantity(t *testing.T) {
binanceFormatRE := regexp.MustCompile("^([0-9]{1,20})(.[0-9]{1,20})?$") binanceFormatRE := regexp.MustCompile("^([0-9]{1,20})(.[0-9]{1,20})?$")
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got := formatQuantity(tt.args.quantity, tt.args.tickSize); got := formatQuantity(tt.args.quantity, tt.args.tickSize)
if got != tt.want { if got != tt.want {
t.Errorf("formatQuantity() = %v, want %v", got, tt.want) t.Errorf("formatQuantity() = %v, want %v", got, tt.want)
} }

View File

@ -227,7 +227,6 @@ func NewProfitStats(market Market) *ProfitStats {
} }
} }
func (s *ProfitStats) Init(market Market) { func (s *ProfitStats) Init(market Market) {
s.Symbol = market.Symbol s.Symbol = market.Symbol
s.BaseCurrency = market.BaseCurrency s.BaseCurrency = market.BaseCurrency

View File

@ -8,24 +8,24 @@ import (
) )
func TestSortTradesAscending(t *testing.T) { func TestSortTradesAscending(t *testing.T) {
var trades = []Trade { var trades = []Trade{
{ {
ID: 1, ID: 1,
Symbol: "BTCUSDT", Symbol: "BTCUSDT",
Side: SideTypeBuy, Side: SideTypeBuy,
IsBuyer: false, IsBuyer: false,
IsMaker: false, IsMaker: false,
Time: Time(time.Unix(2000, 0 )), Time: Time(time.Unix(2000, 0)),
}, },
{ {
ID: 2, ID: 2,
Symbol: "BTCUSDT", Symbol: "BTCUSDT",
Side: SideTypeBuy, Side: SideTypeBuy,
IsBuyer: false, IsBuyer: false,
IsMaker: false, IsMaker: false,
Time: Time(time.Unix(1000, 0 )), Time: Time(time.Unix(1000, 0)),
}, },
} }
trades = SortTradesAscending(trades) trades = SortTradesAscending(trades)
assert.True(t ,trades[0].Time.Before(trades[1].Time.Time())) assert.True(t, trades[0].Time.Before(trades[1].Time.Time()))
} }

View File

@ -1,2 +1 @@
package util package util

View File

@ -1,3 +1,4 @@
//go:build !release
// +build !release // +build !release
package version package version
@ -5,4 +6,3 @@ package version
const Version = "v1.35.0-daaa3352-dev" const Version = "v1.35.0-daaa3352-dev"
const VersionGitRef = "daaa3352" const VersionGitRef = "daaa3352"

View File

@ -1,3 +1,4 @@
//go:build release
// +build release // +build release
package version package version
@ -5,4 +6,3 @@ package version
const Version = "v1.35.0-daaa3352" const Version = "v1.35.0-daaa3352"
const VersionGitRef = "daaa3352" const VersionGitRef = "daaa3352"