mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
fix: use ZeroAssetError, refactor
This commit is contained in:
parent
ac2f7decdf
commit
fdbcaef2ca
|
@ -219,7 +219,23 @@ type OpenPositionOptions struct {
|
|||
Tags []string `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
var Delta fixedpoint.Value = fixedpoint.NewFromFloat(0.005)
|
||||
// Delta used to modify the order to submit, especially for the market order
|
||||
var QuantityReduceDelta fixedpoint.Value = fixedpoint.NewFromFloat(0.005)
|
||||
|
||||
func (e *GeneralOrderExecutor) reduceQuantityAndSubmitOrder(ctx context.Context, price fixedpoint.Value, submitOrder types.SubmitOrder) (types.OrderSlice, error) {
|
||||
for {
|
||||
createdOrder, err2 := e.SubmitOrders(ctx, submitOrder)
|
||||
if err2 != nil {
|
||||
submitOrder.Quantity = submitOrder.Quantity.Mul(fixedpoint.One.Sub(QuantityReduceDelta))
|
||||
if e.position.Market.IsDustQuantity(submitOrder.Quantity, price) {
|
||||
return nil, err2
|
||||
}
|
||||
continue
|
||||
}
|
||||
log.Infof("created order: %+v", createdOrder)
|
||||
return createdOrder, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPositionOptions) (types.OrderSlice, error) {
|
||||
price := options.Price
|
||||
|
@ -252,24 +268,16 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
|
|||
|
||||
quantity := options.Quantity
|
||||
|
||||
market, ok := e.session.Market(e.symbol)
|
||||
if !ok {
|
||||
return nil, errors.New("cannot find market with symbol " + e.symbol)
|
||||
}
|
||||
|
||||
if options.Long {
|
||||
if quantity.IsZero() {
|
||||
quoteQuantity, err := CalculateQuoteQuantity(ctx, e.session, e.position.QuoteCurrency, options.Leverage)
|
||||
if quoteQuantity.IsZero() {
|
||||
log.Warnf("dust quantity: %v", quantity)
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
quantity = quoteQuantity.Div(price)
|
||||
}
|
||||
if market.IsDustQuantity(quantity, price) {
|
||||
if e.position.Market.IsDustQuantity(quantity, price) {
|
||||
log.Warnf("dust quantity: %v", quantity)
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -284,31 +292,16 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
|
|||
submitOrder.Quantity = quantity
|
||||
|
||||
Notify("Opening %s long position with quantity %v at price %v", e.position.Symbol, quantity, price)
|
||||
for {
|
||||
createdOrder, err2 := e.SubmitOrders(ctx, submitOrder)
|
||||
if err2 != nil {
|
||||
submitOrder.Quantity = submitOrder.Quantity.Mul(fixedpoint.One.Sub(Delta))
|
||||
if market.IsDustQuantity(submitOrder.Quantity, price) {
|
||||
return nil, err2
|
||||
}
|
||||
continue
|
||||
}
|
||||
log.Infof("created order: %+v", createdOrder)
|
||||
return createdOrder, nil
|
||||
}
|
||||
return e.reduceQuantityAndSubmitOrder(ctx, price, submitOrder)
|
||||
} else if options.Short {
|
||||
if quantity.IsZero() {
|
||||
var err error
|
||||
quantity, err = CalculateBaseQuantity(e.session, e.position.Market, price, quantity, options.Leverage)
|
||||
if quantity.IsZero() {
|
||||
log.Warnf("dust quantity: %v", quantity)
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if market.IsDustQuantity(quantity, price) {
|
||||
if e.position.Market.IsDustQuantity(quantity, price) {
|
||||
log.Warnf("dust quantity: %v", quantity)
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -323,18 +316,7 @@ func (e *GeneralOrderExecutor) OpenPosition(ctx context.Context, options OpenPos
|
|||
submitOrder.Quantity = quantity
|
||||
|
||||
Notify("Opening %s short position with quantity %v at price %v", e.position.Symbol, quantity, price)
|
||||
for {
|
||||
createdOrder, err2 := e.SubmitOrders(ctx, submitOrder)
|
||||
if err2 != nil {
|
||||
submitOrder.Quantity = submitOrder.Quantity.Mul(fixedpoint.One.Sub(Delta))
|
||||
if market.IsDustQuantity(submitOrder.Quantity, price) {
|
||||
return nil, err2
|
||||
}
|
||||
continue
|
||||
}
|
||||
log.Infof("created order: %+v", createdOrder)
|
||||
return createdOrder, nil
|
||||
}
|
||||
return e.reduceQuantityAndSubmitOrder(ctx, price, submitOrder)
|
||||
}
|
||||
|
||||
return nil, errors.New("options Long or Short must be set")
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
|
@ -243,7 +244,8 @@ func CalculateBaseQuantity(session *ExchangeSession, market types.Market, price,
|
|||
}
|
||||
}
|
||||
|
||||
return quantity, fmt.Errorf("quantity is zero, can not submit sell order, please check your quantity settings, your account balances: %+v", balances)
|
||||
return quantity, types.NewZeroAssetError(
|
||||
fmt.Errorf("quantity is zero, can not submit sell order, please check your quantity settings, your account balances: %+v", balances))
|
||||
}
|
||||
|
||||
usdBalances, restBalances := usdFiatBalances(balances)
|
||||
|
@ -329,7 +331,8 @@ func CalculateBaseQuantity(session *ExchangeSession, market types.Market, price,
|
|||
return maxPositionQuantity, nil
|
||||
}
|
||||
|
||||
return quantity, fmt.Errorf("quantity is zero, can not submit sell order, please check your settings")
|
||||
return quantity, types.NewZeroAssetError(
|
||||
errors.New("quantity is zero, can not submit sell order, please check your settings"))
|
||||
}
|
||||
|
||||
func CalculateQuoteQuantity(ctx context.Context, session *ExchangeSession, quoteCurrency string, leverage fixedpoint.Value) (fixedpoint.Value, error) {
|
||||
|
|
|
@ -36,7 +36,8 @@ func GetModifiableFields(val reflect.Value, callback func(tagName, name string))
|
|||
if !val.IsValid() {
|
||||
return
|
||||
}
|
||||
for i := 0; i < val.Type().NumField(); i++ {
|
||||
num := val.Type().NumField()
|
||||
for i := 0; i < num; i++ {
|
||||
t := val.Type().Field(i)
|
||||
if !t.IsExported() {
|
||||
continue
|
||||
|
|
|
@ -2,7 +2,6 @@ package dynamic
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
|
@ -35,7 +34,6 @@ func TestGetModifiableFields(t *testing.T) {
|
|||
assert.NotEqual(t, name, "Field2")
|
||||
assert.NotEqual(t, tagName, "field3")
|
||||
assert.NotEqual(t, name, "Field3")
|
||||
fmt.Println(tagName, name)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -384,7 +384,7 @@ func (s *Strategy) initTickerFunctions(ctx context.Context) {
|
|||
s.trailingCheck(pricef, "long"))
|
||||
if exitShortCondition || exitLongCondition {
|
||||
if s.ClosePosition(ctx, fixedpoint.One) {
|
||||
log.Infof("Close position by orderbook changes")
|
||||
log.Infof("close position by orderbook changes")
|
||||
}
|
||||
} else {
|
||||
s.positionLock.Unlock()
|
||||
|
@ -752,11 +752,14 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
|||
opt.Price = source
|
||||
opt.Tags = []string{"long"}
|
||||
createdOrders, err := s.GeneralOrderExecutor.OpenPosition(ctx, opt)
|
||||
log.Infof("orders %v", createdOrders)
|
||||
if err != nil {
|
||||
if _, ok := err.(types.ZeroAssetError); ok {
|
||||
return
|
||||
}
|
||||
log.WithError(err).Errorf("cannot place buy order")
|
||||
return
|
||||
}
|
||||
log.Infof("orders %v", createdOrders)
|
||||
if createdOrders != nil {
|
||||
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
|
||||
}
|
||||
|
@ -786,11 +789,14 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
|||
opt.Price = source
|
||||
opt.Tags = []string{"long"}
|
||||
createdOrders, err := s.GeneralOrderExecutor.OpenPosition(ctx, opt)
|
||||
log.Infof("orders %v", createdOrders)
|
||||
if err != nil {
|
||||
if _, ok := err.(types.ZeroAssetError); ok {
|
||||
return
|
||||
}
|
||||
log.WithError(err).Errorf("cannot place buy order")
|
||||
return
|
||||
}
|
||||
log.Infof("orders %v", createdOrders)
|
||||
if createdOrders != nil {
|
||||
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
|
||||
}
|
||||
|
|
|
@ -21,3 +21,13 @@ func NewOrderError(e error, o Order) error {
|
|||
order: o,
|
||||
}
|
||||
}
|
||||
|
||||
type ZeroAssetError struct {
|
||||
error
|
||||
}
|
||||
|
||||
func NewZeroAssetError(e error) ZeroAssetError {
|
||||
return ZeroAssetError{
|
||||
error: e,
|
||||
}
|
||||
}
|
||||
|
|
51
pkg/types/filter.go
Normal file
51
pkg/types/filter.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package types
|
||||
|
||||
type FilterResult struct {
|
||||
a Series
|
||||
b func(int, float64) bool
|
||||
length int
|
||||
c []int
|
||||
}
|
||||
|
||||
func (f *FilterResult) Last() float64 {
|
||||
return f.Index(0)
|
||||
}
|
||||
|
||||
func (f *FilterResult) Index(j int) float64 {
|
||||
if j >= f.length {
|
||||
return 0
|
||||
}
|
||||
if len(f.c) > j {
|
||||
return f.a.Index(f.c[j])
|
||||
}
|
||||
l := f.a.Length()
|
||||
k := len(f.c)
|
||||
i := 0
|
||||
if k > 0 {
|
||||
i = f.c[k-1] + 1
|
||||
}
|
||||
for ; i < l; i++ {
|
||||
tmp := f.a.Index(i)
|
||||
if f.b(i, tmp) {
|
||||
f.c = append(f.c, i)
|
||||
if j == k {
|
||||
return tmp
|
||||
}
|
||||
k++
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (f *FilterResult) Length() int {
|
||||
return f.length
|
||||
}
|
||||
|
||||
// Filter function filters Series by using a boolean function.
|
||||
// When the boolean function returns true, the Series value at index i will be included in the returned Series.
|
||||
// The returned Series will find at most `length` latest matching elements from the input Series.
|
||||
// Query index larger or equal than length from the returned Series will return 0 instead.
|
||||
// Notice that any Update on the input Series will make the previously returned Series outdated.
|
||||
func Filter(a Series, b func(i int, value float64) bool, length int) SeriesExtend {
|
||||
return NewSeries(&FilterResult{a, b, length, nil})
|
||||
}
|
|
@ -998,51 +998,6 @@ func Rolling(a Series, window int) *RollingResult {
|
|||
return &RollingResult{a, window}
|
||||
}
|
||||
|
||||
type FilterResult struct {
|
||||
a Series
|
||||
b func(int, float64) bool
|
||||
length int
|
||||
c []int
|
||||
}
|
||||
|
||||
func (f *FilterResult) Last() float64 {
|
||||
return f.Index(0)
|
||||
}
|
||||
|
||||
func (f *FilterResult) Index(j int) float64 {
|
||||
if j >= f.length {
|
||||
return 0
|
||||
}
|
||||
if len(f.c) > j {
|
||||
return f.a.Index(f.c[j])
|
||||
}
|
||||
l := f.a.Length()
|
||||
k := len(f.c)
|
||||
i := 0
|
||||
if k > 0 {
|
||||
i = f.c[k-1] + 1
|
||||
}
|
||||
for ; i < l; i++ {
|
||||
tmp := f.a.Index(i)
|
||||
if f.b(i, tmp) {
|
||||
f.c = append(f.c, i)
|
||||
if j == k {
|
||||
return tmp
|
||||
}
|
||||
k++
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (f *FilterResult) Length() int {
|
||||
return f.length
|
||||
}
|
||||
|
||||
func Filter(a Series, b func(i int, value float64) bool, length int) SeriesExtend {
|
||||
return NewSeries(&FilterResult{a, b, length, nil})
|
||||
}
|
||||
|
||||
type SigmoidResult struct {
|
||||
a Series
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user