mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 00:05:15 +00:00
fix quantity format
This commit is contained in:
parent
88411a134b
commit
ffa001fc29
|
@ -114,7 +114,6 @@ func main() {
|
|||
}
|
||||
|
||||
// for setup mode, we don't start the trader
|
||||
trader.Subscribe()
|
||||
if err := trader.Run(ctx); err != nil {
|
||||
log.WithError(err).Error("failed to start trader")
|
||||
return
|
||||
|
|
1
go.sum
1
go.sum
|
@ -140,7 +140,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
|
|
|
@ -40,7 +40,6 @@ func TestSimplePriceMatching_LimitOrder(t *testing.T) {
|
|||
BaseCurrency: "BTC",
|
||||
MinNotional: 0.001,
|
||||
MinAmount: 10.0,
|
||||
MinLot: 0.001,
|
||||
MinQuantity: 0.001,
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"math"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
|
@ -33,7 +33,7 @@ type ExchangeOrderExecutionRouter struct {
|
|||
func (e *ExchangeOrderExecutionRouter) SubmitOrdersTo(ctx context.Context, session string, orders ...types.SubmitOrder) (types.OrderSlice, error) {
|
||||
es, ok := e.sessions[session]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("exchange Session %s not found", session)
|
||||
return nil, fmt.Errorf("exchange session %s not found", session)
|
||||
}
|
||||
|
||||
formattedOrders, err := formatOrders(es, orders)
|
||||
|
@ -85,7 +85,7 @@ func (e *ExchangeOrderExecutor) SubmitOrders(ctx context.Context, orders ...type
|
|||
e.Notify(":memo: Submitting %s %s %s order with quantity: %s", order.Symbol, order.Type, order.Side, order.QuantityString, order)
|
||||
}
|
||||
|
||||
logrus.Infof("submitting order: %s", order.String())
|
||||
log.Infof("submitting order: %s", order.String())
|
||||
}
|
||||
|
||||
e.notifySubmitOrders(formattedOrders...)
|
||||
|
@ -94,7 +94,7 @@ func (e *ExchangeOrderExecutor) SubmitOrders(ctx context.Context, orders ...type
|
|||
}
|
||||
|
||||
type BasicRiskController struct {
|
||||
Logger *logrus.Logger
|
||||
Logger *log.Logger
|
||||
|
||||
MaxOrderAmount fixedpoint.Value `json:"maxOrderAmount,omitempty"`
|
||||
MinQuoteBalance fixedpoint.Value `json:"minQuoteBalance,omitempty"`
|
||||
|
@ -258,12 +258,12 @@ func (c *BasicRiskController) ProcessOrders(session *ExchangeSession, orders ...
|
|||
continue
|
||||
}
|
||||
|
||||
if quantity < market.MinLot {
|
||||
if quantity < market.MinQuantity {
|
||||
addError(
|
||||
fmt.Errorf(
|
||||
"can not place sell order, quantity %f is less than the minimal lot %f, order: %s",
|
||||
quantity,
|
||||
market.MinLot,
|
||||
market.MinQuantity,
|
||||
order.String()))
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -148,6 +148,8 @@ func (trader *Trader) Subscribe() {
|
|||
}
|
||||
|
||||
func (trader *Trader) Run(ctx context.Context) error {
|
||||
trader.Subscribe()
|
||||
|
||||
if err := trader.environment.Init(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -214,8 +214,6 @@ var BacktestCmd = &cobra.Command{
|
|||
log.Warnf("backtest does not support CrossExchangeStrategy, strategies won't be added.")
|
||||
}
|
||||
|
||||
trader.Subscribe()
|
||||
|
||||
if err := trader.Run(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
_ "github.com/c9s/bbgo/pkg/strategy/grid"
|
||||
_ "github.com/c9s/bbgo/pkg/strategy/mirrormaker"
|
||||
_ "github.com/c9s/bbgo/pkg/strategy/pricealert"
|
||||
_ "github.com/c9s/bbgo/pkg/strategy/sat"
|
||||
_ "github.com/c9s/bbgo/pkg/strategy/swing"
|
||||
_ "github.com/c9s/bbgo/pkg/strategy/trailingstop"
|
||||
_ "github.com/c9s/bbgo/pkg/strategy/xpuremaker"
|
||||
|
|
|
@ -267,8 +267,6 @@ func runConfig(basectx context.Context, userConfig *bbgo.Config, enableApiServer
|
|||
return err
|
||||
}
|
||||
|
||||
trader.Subscribe()
|
||||
|
||||
if err := trader.Run(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -119,10 +119,9 @@ func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) {
|
|||
// maxQty defines the maximum quantity/icebergQty allowed.
|
||||
// stepSize defines the intervals that a quantity/icebergQty can be increased/decreased by.
|
||||
if f := symbol.LotSizeFilter(); f != nil {
|
||||
market.MinLot = util.MustParseFloat(f.MinQuantity)
|
||||
market.MinQuantity = util.MustParseFloat(f.MinQuantity)
|
||||
market.MaxQuantity = util.MustParseFloat(f.MaxQuantity)
|
||||
// market.StepSize = util.MustParseFloat(f.StepSize)
|
||||
market.StepSize = util.MustParseFloat(f.StepSize)
|
||||
}
|
||||
|
||||
if f := symbol.PriceFilter(); f != nil {
|
||||
|
@ -438,8 +437,11 @@ func (e *Exchange) submitMarginOrder(ctx context.Context, order types.SubmitOrde
|
|||
req := e.Client.NewCreateMarginOrderService().
|
||||
Symbol(order.Symbol).
|
||||
Type(orderType).
|
||||
Side(binance.SideType(order.Side)).
|
||||
NewClientOrderID(clientOrderID)
|
||||
Side(binance.SideType(order.Side))
|
||||
|
||||
if len(clientOrderID) > 0 {
|
||||
req.NewClientOrderID(clientOrderID)
|
||||
}
|
||||
|
||||
// use response result format
|
||||
req.NewOrderRespType(binance.NewOrderRespTypeRESULT)
|
||||
|
@ -460,15 +462,19 @@ func (e *Exchange) submitMarginOrder(ctx context.Context, order types.SubmitOrde
|
|||
req.Quantity(strconv.FormatFloat(order.Quantity, 'f', 8, 64))
|
||||
}
|
||||
|
||||
// set price field for limit orders
|
||||
switch order.Type {
|
||||
case types.OrderTypeStopLimit, types.OrderTypeLimit:
|
||||
if len(order.PriceString) > 0 {
|
||||
req.Price(order.PriceString)
|
||||
} else if order.Market.Symbol != "" {
|
||||
req.Price(order.Market.FormatPrice(order.Price))
|
||||
} else {
|
||||
req.Price(strconv.FormatFloat(order.Price, 'f', 8, 64))
|
||||
}
|
||||
}
|
||||
|
||||
// set stop price
|
||||
switch order.Type {
|
||||
|
||||
case types.OrderTypeStopLimit, types.OrderTypeStopMarket:
|
||||
if len(order.StopPriceString) == 0 {
|
||||
return nil, fmt.Errorf("stop price string can not be empty")
|
||||
|
|
|
@ -351,7 +351,7 @@ func (s *Stream) read(ctx context.Context) {
|
|||
return
|
||||
|
||||
default:
|
||||
if err := s.Conn.SetReadDeadline(time.Now().Add(1 * time.Minute)); err != nil {
|
||||
if err := s.Conn.SetReadDeadline(time.Now().Add(3 * time.Minute)); err != nil {
|
||||
log.WithError(err).Errorf("set read deadline error: %s", err.Error())
|
||||
}
|
||||
|
||||
|
|
|
@ -113,9 +113,11 @@ func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) {
|
|||
BaseCurrency: toGlobalCurrency(m.BaseUnit),
|
||||
MinNotional: m.MinQuoteAmount,
|
||||
MinAmount: m.MinQuoteAmount,
|
||||
MinLot: 1.0 / math.Pow10(m.BaseUnitPrecision), // make it like 0.0001
|
||||
|
||||
MinQuantity: m.MinBaseAmount,
|
||||
MaxQuantity: 10000.0,
|
||||
StepSize: 1.0 / math.Pow10(m.BaseUnitPrecision), // make it like 0.0001
|
||||
|
||||
MinPrice: 1.0 / math.Pow10(m.QuoteUnitPrecision), // used in the price formatter
|
||||
MaxPrice: 10000.0,
|
||||
TickSize: 1.0 / math.Pow10(m.QuoteUnitPrecision),
|
||||
|
|
|
@ -53,14 +53,15 @@ type Market struct {
|
|||
QuoteCurrency string
|
||||
BaseCurrency string
|
||||
|
||||
// The MIN_NOTIONAL filter defines the minimum notional value allowed for an order on a symbol. An order's notional value is the price * quantity
|
||||
// The MIN_NOTIONAL filter defines the minimum notional value allowed for an order on a symbol.
|
||||
// An order's notional value is the price * quantity
|
||||
MinNotional float64
|
||||
MinAmount float64
|
||||
|
||||
// The LOT_SIZE filter defines the quantity
|
||||
MinLot float64
|
||||
MinQuantity float64
|
||||
MaxQuantity float64
|
||||
StepSize float64
|
||||
|
||||
MinPrice float64
|
||||
MaxPrice float64
|
||||
|
@ -86,17 +87,25 @@ func (m Market) FormatPriceCurrency(val float64) string {
|
|||
|
||||
func (m Market) FormatPrice(val float64) string {
|
||||
// p := math.Pow10(m.PricePrecision)
|
||||
prec := int(math.Abs(math.Log10(m.MinPrice)))
|
||||
return formatPrice(val, m.TickSize)
|
||||
}
|
||||
|
||||
func formatPrice(price float64, tickSize float64) string {
|
||||
prec := int(math.Round(math.Abs(math.Log10(tickSize))))
|
||||
p := math.Pow10(prec)
|
||||
val = math.Trunc(val*p) / p
|
||||
return strconv.FormatFloat(val, 'f', prec, 64)
|
||||
price = math.Trunc(price*p) / p
|
||||
return strconv.FormatFloat(price, 'f', prec, 64)
|
||||
}
|
||||
|
||||
func (m Market) FormatQuantity(val float64) string {
|
||||
prec := int(math.Abs(math.Log10(m.MinLot)))
|
||||
return formatQuantity(val, m.StepSize)
|
||||
}
|
||||
|
||||
func formatQuantity(quantity float64, lot float64) string {
|
||||
prec := int(math.Round(math.Abs(math.Log10(lot))))
|
||||
p := math.Pow10(prec)
|
||||
val = math.Trunc(val*p) / p
|
||||
return strconv.FormatFloat(val, 'f', prec, 64)
|
||||
quantity = math.Trunc(quantity*p) / p
|
||||
return strconv.FormatFloat(quantity, 'f', prec, 64)
|
||||
}
|
||||
|
||||
func (m Market) FormatVolume(val float64) string {
|
||||
|
|
|
@ -8,6 +8,22 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFormatQuantity(t *testing.T) {
|
||||
quantity := formatQuantity(0.12511, 0.01)
|
||||
assert.Equal(t, "0.12", quantity)
|
||||
|
||||
quantity = formatQuantity(0.12511, 0.001)
|
||||
assert.Equal(t, "0.125", quantity)
|
||||
}
|
||||
|
||||
func TestFormatPrice(t *testing.T) {
|
||||
price := formatPrice(26.288256, 0.0001)
|
||||
assert.Equal(t, "26.2882", price)
|
||||
|
||||
price = formatPrice(26.288656, 0.001)
|
||||
assert.Equal(t, "26.288", price)
|
||||
}
|
||||
|
||||
func TestDurationParse(t *testing.T) {
|
||||
type A struct {
|
||||
Duration Duration `json:"duration"`
|
||||
|
|
Loading…
Reference in New Issue
Block a user