Merge pull request #958 from c9s/strategy/pivotshort

WIP: strategy/pivotshort: more improvements
This commit is contained in:
Yo-An Lin 2022-09-19 17:27:31 +08:00 committed by GitHub
commit 29376defa3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 263 additions and 29 deletions

6
go.mod
View File

@ -7,7 +7,7 @@ go 1.17
require (
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/Masterminds/squirrel v1.5.3
github.com/adshao/go-binance/v2 v2.3.5
github.com/adshao/go-binance/v2 v2.3.8
github.com/c-bata/goptuna v0.8.1
github.com/c9s/requestgen v1.3.0
github.com/c9s/rockhopper v1.2.2-0.20220617053729-ffdc87df194b
@ -92,7 +92,7 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
github.com/json-iterator/go v1.1.11 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
@ -107,7 +107,7 @@ require (
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml v1.8.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect

6
go.sum
View File

@ -51,6 +51,8 @@ github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdc
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/adshao/go-binance/v2 v2.3.5 h1:WVYZecm0w8l14YoWlnKZj6xxZT2AKMTHpMQSqIX1xxA=
github.com/adshao/go-binance/v2 v2.3.5/go.mod h1:8Pg/FGTLyAhq8QXA0IkoReKyRpoxJcK3LVujKDAZV/c=
github.com/adshao/go-binance/v2 v2.3.8 h1:9VsAX4jUopnIOlzrvnKUFUf9SWB/nwPgJtUsM2dkj6A=
github.com/adshao/go-binance/v2 v2.3.8/go.mod h1:Z3MCnWI0gHC4Rea8TWiF3aN1t4nV9z3CaU/TeHcKsLM=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -401,6 +403,8 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
@ -501,6 +505,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/muesli/clusters v0.0.0-20180605185049-a07a36e67d36 h1:KMCH+/bbZsAbFgzCXD3aB0DRZXnwAO8NYDmfIfslo+M=
github.com/muesli/clusters v0.0.0-20180605185049-a07a36e67d36/go.mod h1:mw5KDqUj0eLj/6DUNINLVJNoPTFkEuGMHtJsXLviLkY=

View File

@ -98,8 +98,6 @@ func (e *ExchangeOrderExecutionRouter) CancelOrdersTo(ctx context.Context, sessi
type ExchangeOrderExecutor struct {
// MinQuoteBalance fixedpoint.Value `json:"minQuoteBalance,omitempty" yaml:"minQuoteBalance,omitempty"`
Notifiability `json:"-" yaml:"-"`
Session *ExchangeSession `json:"-" yaml:"-"`
// private trade update callbacks

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"strings"
"sync/atomic"
"time"
log "github.com/sirupsen/logrus"
@ -29,6 +30,8 @@ type GeneralOrderExecutor struct {
tradeCollector *TradeCollector
marginBaseMaxBorrowable, marginQuoteMaxBorrowable fixedpoint.Value
closing int64
}
func NewGeneralOrderExecutor(session *ExchangeSession, symbol, strategy, strategyInstanceID string, position *types.Position) *GeneralOrderExecutor {
@ -69,7 +72,7 @@ func (e *GeneralOrderExecutor) startMarginAssetUpdater(ctx context.Context) {
func (e *GeneralOrderExecutor) updateMarginAssetMaxBorrowable(ctx context.Context, marginService types.MarginBorrowRepayService, market types.Market) {
maxBorrowable, err := marginService.QueryMarginAssetMaxBorrowable(ctx, market.BaseCurrency)
if err != nil {
log.WithError(err).Errorf("can not query margin base asset max borrowable")
log.WithError(err).Errorf("can not query margin base asset %s max borrowable", market.BaseCurrency)
} else {
log.Infof("updating margin base asset %s max borrowable amount: %f", market.BaseCurrency, maxBorrowable.Float64())
e.marginBaseMaxBorrowable = maxBorrowable
@ -77,7 +80,7 @@ func (e *GeneralOrderExecutor) updateMarginAssetMaxBorrowable(ctx context.Contex
maxBorrowable, err = marginService.QueryMarginAssetMaxBorrowable(ctx, market.QuoteCurrency)
if err != nil {
log.WithError(err).Errorf("can not query margin base asset max borrowable")
log.WithError(err).Errorf("can not query margin quote asset %s max borrowable", market.QuoteCurrency)
} else {
log.Infof("updating margin quote asset %s max borrowable amount: %f", market.QuoteCurrency, maxBorrowable.Float64())
e.marginQuoteMaxBorrowable = maxBorrowable
@ -88,6 +91,7 @@ func (e *GeneralOrderExecutor) marginAssetMaxBorrowableUpdater(ctx context.Conte
t := time.NewTicker(util.MillisecondsJitter(interval, 500))
defer t.Stop()
e.updateMarginAssetMaxBorrowable(ctx, marginService, market)
for {
select {
case <-ctx.Done():
@ -227,6 +231,11 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
Tag: strings.Join(options.Tags, ","),
}
baseBalance, _ := e.session.Account.Balance(e.position.Market.BaseCurrency)
// FIXME: fix the max quote borrowing checking
// quoteBalance, _ := e.session.Account.Balance(e.position.Market.QuoteCurrency)
if !options.LimitOrderTakerRatio.IsZero() {
if options.Long {
// use higher price to buy (this ensures that our order will be filled)
@ -257,7 +266,7 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
}
quoteQuantity := quantity.Mul(price)
if quoteQuantity.Compare(e.marginQuoteMaxBorrowable) > 0 {
if e.session.Margin && !e.marginQuoteMaxBorrowable.IsZero() && quoteQuantity.Compare(e.marginQuoteMaxBorrowable) > 0 {
log.Warnf("adjusting quantity %f according to the max margin quote borrowable amount: %f", quantity.Float64(), e.marginQuoteMaxBorrowable.Float64())
quantity = AdjustQuantityByMaxAmount(quantity, price, e.marginQuoteMaxBorrowable)
}
@ -282,9 +291,10 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
}
}
if quantity.Compare(e.marginBaseMaxBorrowable) > 0 {
if e.session.Margin && !e.marginBaseMaxBorrowable.IsZero() && quantity.Sub(baseBalance.Available).Compare(e.marginBaseMaxBorrowable) > 0 {
log.Warnf("adjusting %f quantity according to the max margin base borrowable amount: %f", quantity.Float64(), e.marginBaseMaxBorrowable.Float64())
quantity = fixedpoint.Min(quantity, e.marginBaseMaxBorrowable)
// quantity = fixedpoint.Min(quantity, e.marginBaseMaxBorrowable)
quantity = baseBalance.Available.Add(e.marginBaseMaxBorrowable)
}
submitOrder.Side = types.SideTypeSell
@ -347,6 +357,14 @@ func (e *GeneralOrderExecutor) ClosePosition(ctx context.Context, percentage fix
return nil
}
if e.closing > 0 {
log.Errorf("position is already closing")
return nil
}
atomic.AddInt64(&e.closing, 1)
defer atomic.StoreInt64(&e.closing, 0)
// check base balance and adjust the close position order
if e.position.IsLong() {
if baseBalance, ok := e.session.Account.Balance(e.position.Market.BaseCurrency); ok {
@ -355,12 +373,20 @@ func (e *GeneralOrderExecutor) ClosePosition(ctx context.Context, percentage fix
if submitOrder.Quantity.IsZero() {
return fmt.Errorf("insufficient base balance, can not sell: %+v", submitOrder)
}
} else if e.position.IsShort() {
// TODO: check quote balance here, we also need the current price to validate, need to design.
/*
if quoteBalance, ok := e.session.Account.Balance(e.position.Market.QuoteCurrency); ok {
// AdjustQuantityByMaxAmount(submitOrder.Quantity, quoteBalance.Available)
// submitOrder.Quantity = fixedpoint.Min(submitOrder.Quantity,)
}
*/
}
tagStr := strings.Join(tags, ",")
submitOrder.Tag = tagStr
Notify("closing %s position %s with tags: %v", e.symbol, percentage.Percentage(), tagStr)
Notify("Closing %s position %s with tags: %v", e.symbol, percentage.Percentage(), tagStr)
_, err := e.SubmitOrders(ctx, *submitOrder)
return err

View File

@ -0,0 +1,25 @@
package binanceapi
import (
"github.com/c9s/requestgen"
"github.com/c9s/bbgo/pkg/fixedpoint"
)
// MarginMaxBorrowable is the user margin interest record
type MarginMaxBorrowable struct {
Amount fixedpoint.Value `json:"amount"`
BorrowLimit fixedpoint.Value `json:"borrowLimit"`
}
//go:generate requestgen -method GET -url "/sapi/v1/margin/maxBorrowable" -type GetMarginMaxBorrowableRequest -responseType .MarginMaxBorrowable
type GetMarginMaxBorrowableRequest struct {
client requestgen.AuthenticatedAPIClient
asset string `param:"asset"`
isolatedSymbol *string `param:"isolatedSymbol"`
}
func (c *RestClient) NewGetMarginMaxBorrowableRequest() *GetMarginMaxBorrowableRequest {
return &GetMarginMaxBorrowableRequest{client: c}
}

View File

@ -0,0 +1,161 @@
// Code generated by "requestgen -method GET -url /sapi/v1/margin/maxBorrowable -type GetMarginMaxBorrowableRequest -responseType .MarginMaxBorrowable"; DO NOT EDIT.
package binanceapi
import (
"context"
"encoding/json"
"fmt"
"net/url"
"reflect"
"regexp"
)
func (g *GetMarginMaxBorrowableRequest) Asset(asset string) *GetMarginMaxBorrowableRequest {
g.asset = asset
return g
}
func (g *GetMarginMaxBorrowableRequest) IsolatedSymbol(isolatedSymbol string) *GetMarginMaxBorrowableRequest {
g.isolatedSymbol = &isolatedSymbol
return g
}
// GetQueryParameters builds and checks the query parameters and returns url.Values
func (g *GetMarginMaxBorrowableRequest) GetQueryParameters() (url.Values, error) {
var params = map[string]interface{}{}
query := url.Values{}
for _k, _v := range params {
query.Add(_k, fmt.Sprintf("%v", _v))
}
return query, nil
}
// GetParameters builds and checks the parameters and return the result in a map object
func (g *GetMarginMaxBorrowableRequest) GetParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
// check asset field -> json key asset
asset := g.asset
// assign parameter of asset
params["asset"] = asset
// check isolatedSymbol field -> json key isolatedSymbol
if g.isolatedSymbol != nil {
isolatedSymbol := *g.isolatedSymbol
// assign parameter of isolatedSymbol
params["isolatedSymbol"] = isolatedSymbol
} else {
}
return params, nil
}
// GetParametersQuery converts the parameters from GetParameters into the url.Values format
func (g *GetMarginMaxBorrowableRequest) GetParametersQuery() (url.Values, error) {
query := url.Values{}
params, err := g.GetParameters()
if err != nil {
return query, err
}
for _k, _v := range params {
if g.isVarSlice(_v) {
g.iterateSlice(_v, func(it interface{}) {
query.Add(_k+"[]", fmt.Sprintf("%v", it))
})
} else {
query.Add(_k, fmt.Sprintf("%v", _v))
}
}
return query, nil
}
// GetParametersJSON converts the parameters from GetParameters into the JSON format
func (g *GetMarginMaxBorrowableRequest) GetParametersJSON() ([]byte, error) {
params, err := g.GetParameters()
if err != nil {
return nil, err
}
return json.Marshal(params)
}
// GetSlugParameters builds and checks the slug parameters and return the result in a map object
func (g *GetMarginMaxBorrowableRequest) GetSlugParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
return params, nil
}
func (g *GetMarginMaxBorrowableRequest) applySlugsToUrl(url string, slugs map[string]string) string {
for _k, _v := range slugs {
needleRE := regexp.MustCompile(":" + _k + "\\b")
url = needleRE.ReplaceAllString(url, _v)
}
return url
}
func (g *GetMarginMaxBorrowableRequest) iterateSlice(slice interface{}, _f func(it interface{})) {
sliceValue := reflect.ValueOf(slice)
for _i := 0; _i < sliceValue.Len(); _i++ {
it := sliceValue.Index(_i).Interface()
_f(it)
}
}
func (g *GetMarginMaxBorrowableRequest) isVarSlice(_v interface{}) bool {
rt := reflect.TypeOf(_v)
switch rt.Kind() {
case reflect.Slice:
return true
}
return false
}
func (g *GetMarginMaxBorrowableRequest) GetSlugsMap() (map[string]string, error) {
slugs := map[string]string{}
params, err := g.GetSlugParameters()
if err != nil {
return slugs, nil
}
for _k, _v := range params {
slugs[_k] = fmt.Sprintf("%v", _v)
}
return slugs, nil
}
func (g *GetMarginMaxBorrowableRequest) Do(ctx context.Context) (*MarginMaxBorrowable, error) {
// empty params for GET operation
var params interface{}
query, err := g.GetParametersQuery()
if err != nil {
return nil, err
}
apiURL := "/sapi/v1/margin/maxBorrowable"
req, err := g.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params)
if err != nil {
return nil, err
}
response, err := g.client.SendRequest(req)
if err != nil {
return nil, err
}
var apiResponse MarginMaxBorrowable
if err := response.DecodeJSON(&apiResponse); err != nil {
return nil, err
}
return &apiResponse, nil
}

View File

@ -307,17 +307,18 @@ func (e *Exchange) NewStream() types.Stream {
}
func (e *Exchange) QueryMarginAssetMaxBorrowable(ctx context.Context, asset string) (amount fixedpoint.Value, err error) {
req := e.client.NewGetMaxBorrowableService()
req := e.client2.NewGetMarginMaxBorrowableRequest()
req.Asset(asset)
if e.IsIsolatedMargin {
req.IsolatedSymbol(e.IsolatedMarginSymbol)
}
resp, err := req.Do(ctx)
if err != nil {
return fixedpoint.Zero, err
}
return fixedpoint.NewFromString(resp.Amount)
return resp.Amount, nil
}
func (e *Exchange) RepayMarginAsset(ctx context.Context, asset string, amount fixedpoint.Value) error {
@ -325,7 +326,7 @@ func (e *Exchange) RepayMarginAsset(ctx context.Context, asset string, amount fi
req.Asset(asset)
req.Amount(amount.String())
if e.IsIsolatedMargin {
req.IsolatedSymbol(e.IsolatedMarginSymbol)
req.Symbol(e.IsolatedMarginSymbol)
}
log.Infof("repaying margin asset %s amount %f", asset, amount.Float64())
@ -343,7 +344,7 @@ func (e *Exchange) BorrowMarginAsset(ctx context.Context, asset string, amount f
req.Asset(asset)
req.Amount(amount.String())
if e.IsIsolatedMargin {
req.IsolatedSymbol(e.IsolatedMarginSymbol)
req.Symbol(e.IsolatedMarginSymbol)
}
log.Infof("borrowing margin asset %s amount %f", asset, amount.Float64())

View File

@ -34,6 +34,12 @@ func (t *LogHook) Fire(e *logrus.Entry) error {
}
var message = fmt.Sprintf("[%s] %s", e.Level.String(), e.Message)
if errData, ok := e.Data[logrus.ErrorKey]; ok {
if err, isErr := errData.(error); isErr {
message += " Error: " + err.Error()
}
}
t.notifier.Notify(message)
return nil
}

View File

@ -2,6 +2,7 @@ package xmaker
import (
"sync"
"time"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
@ -57,7 +58,7 @@ func (s *ProfitStats) AddTrade(trade types.Trade) {
}
func (s *ProfitStats) ResetToday() {
s.ProfitStats.ResetToday()
s.ProfitStats.ResetToday(time.Now())
s.lock.Lock()
s.TodayMakerVolume = fixedpoint.Zero

View File

@ -154,24 +154,34 @@ type ProfitStats struct {
AccumulatedPnL fixedpoint.Value `json:"accumulatedPnL,omitempty"`
AccumulatedNetProfit fixedpoint.Value `json:"accumulatedNetProfit,omitempty"`
AccumulatedGrossProfit fixedpoint.Value `json:"accumulatedProfit,omitempty"`
AccumulatedGrossLoss fixedpoint.Value `json:"accumulatedLoss,omitempty"`
AccumulatedGrossProfit fixedpoint.Value `json:"accumulatedGrossProfit,omitempty"`
AccumulatedGrossLoss fixedpoint.Value `json:"accumulatedGrossLoss,omitempty"`
AccumulatedVolume fixedpoint.Value `json:"accumulatedVolume,omitempty"`
AccumulatedSince int64 `json:"accumulatedSince,omitempty"`
TodayPnL fixedpoint.Value `json:"todayPnL,omitempty"`
TodayNetProfit fixedpoint.Value `json:"todayNetProfit,omitempty"`
TodayGrossProfit fixedpoint.Value `json:"todayProfit,omitempty"`
TodayGrossLoss fixedpoint.Value `json:"todayLoss,omitempty"`
TodayGrossProfit fixedpoint.Value `json:"todayGrossProfit,omitempty"`
TodayGrossLoss fixedpoint.Value `json:"todayGrossLoss,omitempty"`
TodaySince int64 `json:"todaySince,omitempty"`
}
func NewProfitStats(market Market) *ProfitStats {
return &ProfitStats{
Symbol: market.Symbol,
BaseCurrency: market.BaseCurrency,
QuoteCurrency: market.QuoteCurrency,
AccumulatedSince: time.Now().Unix(),
Symbol: market.Symbol,
QuoteCurrency: market.QuoteCurrency,
BaseCurrency: market.BaseCurrency,
AccumulatedPnL: fixedpoint.Zero,
AccumulatedNetProfit: fixedpoint.Zero,
AccumulatedGrossProfit: fixedpoint.Zero,
AccumulatedGrossLoss: fixedpoint.Zero,
AccumulatedVolume: fixedpoint.Zero,
AccumulatedSince: 0,
TodayPnL: fixedpoint.Zero,
TodayNetProfit: fixedpoint.Zero,
TodayGrossProfit: fixedpoint.Zero,
TodayGrossLoss: fixedpoint.Zero,
TodaySince: 0,
}
}
@ -188,7 +198,7 @@ func (s *ProfitStats) Init(market Market) {
func (s *ProfitStats) AddProfit(profit Profit) {
if s.IsOver24Hours() {
s.ResetToday()
s.ResetToday(profit.TradedAt)
}
// since field guard
@ -217,7 +227,7 @@ func (s *ProfitStats) AddProfit(profit Profit) {
func (s *ProfitStats) AddTrade(trade Trade) {
if s.IsOver24Hours() {
s.ResetToday()
s.ResetToday(trade.Time.Time())
}
s.AccumulatedVolume = s.AccumulatedVolume.Add(trade.Quantity)
@ -228,13 +238,13 @@ func (s *ProfitStats) IsOver24Hours() bool {
return time.Since(time.Unix(s.TodaySince, 0)) >= 24*time.Hour
}
func (s *ProfitStats) ResetToday() {
func (s *ProfitStats) ResetToday(t time.Time) {
s.TodayPnL = fixedpoint.Zero
s.TodayNetProfit = fixedpoint.Zero
s.TodayGrossProfit = fixedpoint.Zero
s.TodayGrossLoss = fixedpoint.Zero
var beginningOfTheDay = BeginningOfTheDay(time.Now().Local())
var beginningOfTheDay = BeginningOfTheDay(t.Local())
s.TodaySince = beginningOfTheDay.Unix()
}

View File

@ -12,7 +12,7 @@ import (
func FilterSimpleArgs(args []interface{}) (simpleArgs []interface{}) {
for _, arg := range args {
switch arg.(type) {
case int, int64, int32, uint64, uint32, string, []byte, float64, float32, fixedpoint.Value, time.Time:
case int, int64, int32, uint64, uint32, string, []string, []byte, float64, []float64, float32, fixedpoint.Value, time.Time:
simpleArgs = append(simpleArgs, arg)
default:
rt := reflect.TypeOf(arg)