mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-27 01:05:15 +00:00
Merge pull request #1034 from c9s/feature/grid2
strategy: grid2: use initial order ID to query closed order history to recover grid
This commit is contained in:
commit
5bb590faec
|
@ -24,6 +24,7 @@ type GridProfitStats struct {
|
|||
Market types.Market `json:"market,omitempty"`
|
||||
ProfitEntries []*GridProfit `json:"profitEntries,omitempty"`
|
||||
Since *time.Time `json:"since,omitempty"`
|
||||
InitialOrderID uint64 `json:"initialOrderID"`
|
||||
}
|
||||
|
||||
func newGridProfitStats(market types.Market) *GridProfitStats {
|
||||
|
|
|
@ -3,6 +3,7 @@ package grid2
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -116,7 +117,6 @@ type Strategy struct {
|
|||
SkipSpreadCheck bool `json:"skipSpreadCheck"`
|
||||
|
||||
GridProfitStats *GridProfitStats `persistence:"grid_profit_stats"`
|
||||
ProfitStats *types.ProfitStats `persistence:"profit_stats"`
|
||||
Position *types.Position `persistence:"position"`
|
||||
|
||||
grid *Grid
|
||||
|
@ -179,7 +179,15 @@ func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
|
|||
|
||||
// InstanceID returns the instance identifier from the current grid configuration parameters
|
||||
func (s *Strategy) InstanceID() string {
|
||||
return fmt.Sprintf("%s-%s-%d-%d-%d", ID, s.Symbol, s.GridNum, s.UpperPrice.Int(), s.LowerPrice.Int())
|
||||
id := fmt.Sprintf("%s-%s-size-%d", ID, s.Symbol, s.GridNum)
|
||||
|
||||
if s.AutoRange != nil {
|
||||
id += "-autoRange-" + s.AutoRange.String()
|
||||
} else {
|
||||
id += "-" + s.UpperPrice.String() + "-" + s.LowerPrice.String()
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
func (s *Strategy) checkSpread() error {
|
||||
|
@ -820,10 +828,23 @@ func (s *Strategy) openGrid(ctx context.Context, session *bbgo.ExchangeSession)
|
|||
return err
|
||||
}
|
||||
|
||||
var orderIds []uint64
|
||||
|
||||
for _, order := range createdOrders {
|
||||
orderIds = append(orderIds, order.OrderID)
|
||||
|
||||
s.logger.Info(order.String())
|
||||
}
|
||||
|
||||
sort.Slice(orderIds, func(i, j int) bool {
|
||||
return orderIds[i] < orderIds[j]
|
||||
})
|
||||
|
||||
if len(orderIds) > 0 {
|
||||
s.GridProfitStats.InitialOrderID = orderIds[0]
|
||||
bbgo.Sync(ctx, s)
|
||||
}
|
||||
|
||||
s.logger.Infof("ALL GRID ORDERS SUBMITTED")
|
||||
return nil
|
||||
}
|
||||
|
@ -998,9 +1019,13 @@ func (s *Strategy) recoverGrid(ctx context.Context, historyService types.Exchang
|
|||
_ = lastOrderTime
|
||||
|
||||
// for MAX exchange we need the order ID to query the closed order history
|
||||
if s.GridProfitStats != nil && s.GridProfitStats.InitialOrderID > 0 {
|
||||
lastOrderID = s.GridProfitStats.InitialOrderID
|
||||
} else {
|
||||
if oid, ok := findEarliestOrderID(openOrders); ok {
|
||||
lastOrderID = oid
|
||||
}
|
||||
}
|
||||
|
||||
activeOrderBook := s.orderExecutor.ActiveMakerOrders()
|
||||
|
||||
|
@ -1251,10 +1276,6 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
|
|||
s.GridProfitStats = newGridProfitStats(s.Market)
|
||||
}
|
||||
|
||||
if s.ProfitStats == nil {
|
||||
s.ProfitStats = types.NewProfitStats(s.Market)
|
||||
}
|
||||
|
||||
if s.Position == nil {
|
||||
s.Position = types.NewPositionFromMarket(s.Market)
|
||||
}
|
||||
|
@ -1276,7 +1297,6 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
|
|||
|
||||
orderExecutor := bbgo.NewGeneralOrderExecutor(session, s.Symbol, ID, instanceID, s.Position)
|
||||
orderExecutor.BindEnvironment(s.Environment)
|
||||
orderExecutor.BindProfitStats(s.ProfitStats)
|
||||
orderExecutor.Bind()
|
||||
orderExecutor.TradeCollector().OnTrade(func(trade types.Trade, _, _ fixedpoint.Value) {
|
||||
s.GridProfitStats.AddTrade(trade)
|
||||
|
@ -1338,14 +1358,14 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
|
|||
session.MarketDataStream.OnKLineClosed(s.newTakeProfitHandler(ctx, session))
|
||||
}
|
||||
|
||||
session.UserDataStream.OnStart(func() {
|
||||
// if TriggerPrice is zero, that means we need to open the grid when start up
|
||||
if s.TriggerPrice.IsZero() {
|
||||
session.UserDataStream.OnStart(func() {
|
||||
if err := s.openGrid(ctx, session); err != nil {
|
||||
s.logger.WithError(err).Errorf("failed to setup grid orders")
|
||||
}
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ func (s *State) SlackAttachment() slack.Attachment {
|
|||
Title: s.Asset + " Transfer States",
|
||||
Fields: []slack.AttachmentField{
|
||||
{Title: "Total Number of Transfers", Value: fmt.Sprintf("%d", s.DailyNumberOfTransfers), Short: true},
|
||||
{Title: "Total Amount of Transfers", Value: util.FormatFloat(s.DailyAmountOfTransfers.Float64(), 4), Short: true},
|
||||
{Title: "Total Amount of Transfers", Value: s.DailyAmountOfTransfers.String(), Short: true},
|
||||
},
|
||||
Footer: templateutil.Render("Since {{ . }}", time.Unix(s.Since, 0).Format(time.RFC822)),
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var simpleDurationRegExp = regexp.MustCompile("^(\\d+)([hdw])$")
|
||||
var simpleDurationRegExp = regexp.MustCompile(`^(\d+)([hdw])$`)
|
||||
|
||||
var ErrNotSimpleDuration = errors.New("the given input is not simple duration format, valid format: [1-9][0-9]*[hdw]")
|
||||
|
||||
|
@ -20,6 +20,10 @@ type SimpleDuration struct {
|
|||
Duration Duration
|
||||
}
|
||||
|
||||
func (d *SimpleDuration) String() string {
|
||||
return fmt.Sprintf("%d%s", d.Num, d.Unit)
|
||||
}
|
||||
|
||||
func (d *SimpleDuration) Interval() Interval {
|
||||
switch d.Unit {
|
||||
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
)
|
||||
|
||||
const MaxDigits = 18 // MAX_INT64 ~ 9 * 10^18
|
||||
|
||||
var Pow10Table = [MaxDigits + 1]int64{
|
||||
1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18,
|
||||
}
|
||||
|
||||
func Pow10(n int64) int64 {
|
||||
if n < 0 || n > MaxDigits {
|
||||
return 0
|
||||
}
|
||||
return Pow10Table[n]
|
||||
}
|
||||
|
||||
func FormatValue(val fixedpoint.Value, prec int) string {
|
||||
return val.FormatString(prec)
|
||||
}
|
||||
|
||||
func FormatFloat(val float64, prec int) string {
|
||||
return strconv.FormatFloat(val, 'f', prec, 64)
|
||||
}
|
||||
|
||||
func ParseFloat(s string) (float64, error) {
|
||||
if len(s) == 0 {
|
||||
return 0.0, nil
|
||||
}
|
||||
|
||||
return strconv.ParseFloat(s, 64)
|
||||
}
|
||||
|
||||
func MustParseFloat(s string) float64 {
|
||||
if len(s) == 0 {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
v, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
const epsilon = 0.0000001
|
||||
|
||||
func Zero(v float64) bool {
|
||||
return math.Abs(v) < epsilon
|
||||
}
|
||||
|
||||
func NotZero(v float64) bool {
|
||||
return math.Abs(v) > epsilon
|
||||
}
|
||||
|
|
@ -1,36 +1 @@
|
|||
package util
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNotZero(t *testing.T) {
|
||||
type args struct {
|
||||
v float64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "0",
|
||||
args: args{
|
||||
v: 0,
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "0.00001",
|
||||
args: args{
|
||||
v: 0.00001,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := NotZero(tt.args.v); got != tt.want {
|
||||
t.Errorf("NotZero() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
package util
|
||||
|
Loading…
Reference in New Issue
Block a user