mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 06:53:52 +00:00
Merge pull request #734 from zenixls2/feature/lint_fmt_check
fix: apply gofmt on all files, add revive action
This commit is contained in:
commit
f25f2f076f
17
.github/workflows/go.yml
vendored
17
.github/workflows/go.yml
vendored
|
@ -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
22
.github/workflows/golang-lint.yml
vendored
Normal 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
7
.golangci.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
run:
|
||||||
|
issues-exit-code: 0
|
||||||
|
tests: false
|
||||||
|
linters:
|
||||||
|
disable-all: true
|
||||||
|
enable:
|
||||||
|
- gofmt
|
5
.markdownlint.yaml
Normal file
5
.markdownlint.yaml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
default: true
|
||||||
|
extends: null
|
||||||
|
MD033: false
|
||||||
|
MD010: false
|
||||||
|
MD013: false
|
14
.pre-commit-config.yaml
Normal file
14
.pre-commit-config.yaml
Normal 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
|
48
README.md
48
README.md
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -39,4 +39,3 @@ var accountsCmd = &cobra.Command{
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -25,4 +25,3 @@ var symbolsCmd = &cobra.Command{
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,4 +69,3 @@ func (m *Notifiability) NotifyTo(channel string, obj interface{}, args ...interf
|
||||||
n.NotifyTo(channel, obj, args...)
|
n.NotifyTo(channel, obj, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
package bbgo
|
package bbgo
|
||||||
|
|
||||||
|
|
|
@ -100,4 +100,3 @@ func newTypeValueInterface(typ reflect.Type) interface{} {
|
||||||
dst := reflect.New(typ)
|
dst := reflect.New(typ)
|
||||||
return dst.Interface()
|
return dst.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
|
}
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
package bbgo
|
package bbgo
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
package cmdutil
|
package cmdutil
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
package batch
|
package batch
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
},
|
},
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"`
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"`
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build ignore
|
||||||
// +build ignore
|
// +build ignore
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -42,4 +42,3 @@ func (r *walletRequest) DepositHistory(ctx context.Context, since time.Time, unt
|
||||||
|
|
||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
@ -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)
|
||||||
|
|
|
@ -245,4 +245,3 @@ func toGlobalTrade(fill kucoinapi.Fill) types.Trade {
|
||||||
}
|
}
|
||||||
return trade
|
return trade
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@ -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},
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,5 +22,3 @@ func integrationTestConfigured(t *testing.T, prefix string) (key, secret string,
|
||||||
}
|
}
|
||||||
return key, secret, ok
|
return key, secret, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build ignore
|
||||||
// +build ignore
|
// +build ignore
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
@ -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: "",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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: {},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: {},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
})
|
})
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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{}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
package util
|
package util
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user