implement tree copy method

This commit is contained in:
c9s 2021-05-22 12:18:08 +08:00
parent 56b2c8845b
commit fd710d533f
8 changed files with 86 additions and 29 deletions

View File

@ -67,7 +67,7 @@ var rootCmd = &cobra.Command{
return return
case <-streambook.C: case <-streambook.C:
book := streambook.Get() book := streambook.Copy()
if valid, err := book.IsValid(); !valid { if valid, err := book.IsValid(); !valid {
log.Errorf("order book is invalid, error: %v", err) log.Errorf("order book is invalid, error: %v", err)

View File

@ -64,7 +64,7 @@ func (e *TwapExecution) connectUserData(ctx context.Context) {
} }
func (e *TwapExecution) getSideBook() (pvs types.PriceVolumeSlice, err error) { func (e *TwapExecution) getSideBook() (pvs types.PriceVolumeSlice, err error) {
book := e.orderBook.Get() book := e.orderBook.Copy()
switch e.Side { switch e.Side {
case types.SideTypeSell: case types.SideTypeSell:
@ -81,7 +81,7 @@ func (e *TwapExecution) getSideBook() (pvs types.PriceVolumeSlice, err error) {
} }
func (e *TwapExecution) newBestPriceOrder() (orderForm types.SubmitOrder, err error) { func (e *TwapExecution) newBestPriceOrder() (orderForm types.SubmitOrder, err error) {
book := e.orderBook.Get() book := e.orderBook.Copy()
sideBook, err := e.getSideBook() sideBook, err := e.getSideBook()
if err != nil { if err != nil {

View File

@ -234,8 +234,8 @@ func (s *Strategy) CrossRun(ctx context.Context, _ bbgo.OrderExecutionRouter, se
continue continue
} }
sourceBook := s.sourceBook.Get() sourceBook := s.sourceBook.Copy()
book := s.tradingBook.Get() book := s.tradingBook.Copy()
bestBid, hasBid := book.BestBid() bestBid, hasBid := book.BestBid()
bestAsk, hasAsk := book.BestAsk() bestAsk, hasAsk := book.BestAsk()

View File

@ -83,7 +83,7 @@ func (s *Strategy) updateQuote(ctx context.Context) {
// avoid unlock issue // avoid unlock issue
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
sourceBook := s.book.Get() sourceBook := s.book.Copy()
if len(sourceBook.Bids) == 0 || len(sourceBook.Asks) == 0 { if len(sourceBook.Bids) == 0 || len(sourceBook.Asks) == 0 {
return return
} }

View File

@ -184,7 +184,7 @@ func (s *Strategy) updateQuote(ctx context.Context, orderExecutionRouter bbgo.Or
return return
} }
sourceBook := s.book.Get() sourceBook := s.book.Copy()
if len(sourceBook.Bids) == 0 || len(sourceBook.Asks) == 0 { if len(sourceBook.Bids) == 0 || len(sourceBook.Asks) == 0 {
return return
} }
@ -443,7 +443,7 @@ func (s *Strategy) Hedge(ctx context.Context, pos fixedpoint.Value) {
} }
lastPrice := s.lastPrice lastPrice := s.lastPrice
sourceBook := s.book.Get() sourceBook := s.book.Copy()
switch side { switch side {
case types.SideTypeBuy: case types.SideTypeBuy:

View File

@ -56,7 +56,7 @@ func (b *MutexOrderBook) CopyDepth(depth int) SliceOrderBook {
return b.SliceOrderBook.CopyDepth(depth) return b.SliceOrderBook.CopyDepth(depth)
} }
func (b *MutexOrderBook) Get() SliceOrderBook { func (b *MutexOrderBook) Copy() SliceOrderBook {
b.Lock() b.Lock()
defer b.Unlock() defer b.Unlock()
return b.SliceOrderBook.Copy() return b.SliceOrderBook.Copy()

View File

@ -4,20 +4,20 @@ import (
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
) )
var Neel = &RBNode{
Color: Black,
}
type RBTree struct { type RBTree struct {
Root, Neel *RBNode Root *RBNode
} }
func NewRBTree() *RBTree { func NewRBTree() *RBTree {
var neel = &RBNode{ var root = Neel
Color: Black, root.Parent = Neel
}
var root = neel
root.Parent = neel
return &RBTree{ return &RBTree{
Root: root, Root: root,
Neel: neel,
} }
} }
@ -31,13 +31,13 @@ func (tree *RBTree) Delete(key fixedpoint.Value) bool {
// x (the child of the deleted node) // x (the child of the deleted node)
var x, y *RBNode var x, y *RBNode
if del.Left == tree.Neel || del.Right == tree.Neel { if del.Left == Neel || del.Right == Neel {
y = del y = del
} else { } else {
y = tree.Successor(del) y = tree.Successor(del)
} }
if y.Left != tree.Neel { if y.Left != Neel {
x = y.Left x = y.Left
} else { } else {
x = y.Right x = y.Right
@ -45,7 +45,7 @@ func (tree *RBTree) Delete(key fixedpoint.Value) bool {
x.Parent = y.Parent x.Parent = y.Parent
if y.Parent == tree.Neel { if y.Parent == Neel {
tree.Root = x tree.Root = x
} else if y == y.Parent.Left { } else if y == y.Parent.Left {
y.Parent.Left = x y.Parent.Left = x
@ -129,7 +129,7 @@ func (tree *RBTree) DeleteFixup(current *RBNode) {
} }
func (tree *RBTree) Upsert(key, val fixedpoint.Value) { func (tree *RBTree) Upsert(key, val fixedpoint.Value) {
var y = tree.Neel var y = Neel
var x = tree.Root var x = tree.Root
var node = &RBNode{ var node = &RBNode{
Key: key, Key: key,
@ -137,7 +137,7 @@ func (tree *RBTree) Upsert(key, val fixedpoint.Value) {
Color: Red, Color: Red,
} }
for x != tree.Neel { for x != Neel {
y = x y = x
if node.Key == x.Key { if node.Key == x.Key {
@ -153,7 +153,7 @@ func (tree *RBTree) Upsert(key, val fixedpoint.Value) {
node.Parent = y node.Parent = y
if y == tree.Neel { if y == Neel {
tree.Root = node tree.Root = node
} else if node.Key < y.Key { } else if node.Key < y.Key {
y.Left = node y.Left = node
@ -161,15 +161,15 @@ func (tree *RBTree) Upsert(key, val fixedpoint.Value) {
y.Right = node y.Right = node
} }
node.Left = tree.Neel node.Left = Neel
node.Right = tree.Neel node.Right = Neel
node.Color = Red node.Color = Red
tree.InsertFixup(node) tree.InsertFixup(node)
} }
func (tree *RBTree) Insert(key, val fixedpoint.Value) { func (tree *RBTree) Insert(key, val fixedpoint.Value) {
var y = tree.Neel var y = Neel
var x = tree.Root var x = tree.Root
var node = &RBNode{ var node = &RBNode{
Key: key, Key: key,
@ -177,7 +177,7 @@ func (tree *RBTree) Insert(key, val fixedpoint.Value) {
Color: Red, Color: Red,
} }
for x != tree.Neel { for x != Neel {
y = x y = x
if node.Key < x.Key { if node.Key < x.Key {
@ -189,7 +189,7 @@ func (tree *RBTree) Insert(key, val fixedpoint.Value) {
node.Parent = y node.Parent = y
if y == tree.Neel { if y == Neel {
tree.Root = node tree.Root = node
} else if node.Key < y.Key { } else if node.Key < y.Key {
y.Left = node y.Left = node
@ -197,8 +197,8 @@ func (tree *RBTree) Insert(key, val fixedpoint.Value) {
y.Right = node y.Right = node
} }
node.Left = tree.Neel node.Left = Neel
node.Right = tree.Neel node.Right = Neel
node.Color = Red node.Color = Red
tree.InsertFixup(node) tree.InsertFixup(node)
@ -353,6 +353,7 @@ func (tree *RBTree) PreorderOf(current *RBNode, cb func(n *RBNode)) {
} }
} }
// Inorder traverses the tree in ascending order
func (tree *RBTree) Inorder(cb func(n *RBNode)) { func (tree *RBTree) Inorder(cb func(n *RBNode)) {
tree.InorderOf(tree.Root, cb) tree.InorderOf(tree.Root, cb)
} }
@ -365,6 +366,19 @@ func (tree *RBTree) InorderOf(current *RBNode, cb func(n *RBNode)) {
} }
} }
// InorderReverse traverses the tree in descending order
func (tree *RBTree) InorderReverse(cb func(n *RBNode)) {
tree.InorderReverseOf(tree.Root, cb)
}
func (tree *RBTree) InorderReverseOf(current *RBNode, cb func(n *RBNode)) {
if current != nil {
tree.InorderOf(current.Right, cb)
cb(current)
tree.InorderOf(current.Left, cb)
}
}
func (tree *RBTree) Postorder(cb func(n *RBNode)) { func (tree *RBTree) Postorder(cb func(n *RBNode)) {
tree.PostorderOf(tree.Root, cb) tree.PostorderOf(tree.Root, cb)
} }
@ -376,3 +390,20 @@ func (tree *RBTree) PostorderOf(current *RBNode, cb func(n *RBNode)) {
cb(current) cb(current)
} }
} }
func copyNode(node *RBNode) *RBNode {
if node == Neel {
return Neel
}
newNode := *node
newNode.Left = copyNode(node.Left)
newNode.Right = copyNode(node.Right)
return &newNode
}
func (tree *RBTree) Copy() *RBTree {
newTree := NewRBTree()
newTree.Root = copyNode(tree.Root)
return newTree
}

View File

@ -7,6 +7,31 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestTree_Copy(t *testing.T) {
tree := NewRBTree()
tree.Insert(fixedpoint.NewFromFloat(3000.0), fixedpoint.NewFromFloat(1.0))
assert.NotNil(t, tree.Root)
tree.Insert(fixedpoint.NewFromFloat(4000.0), fixedpoint.NewFromFloat(2.0))
tree.Insert(fixedpoint.NewFromFloat(2000.0), fixedpoint.NewFromFloat(3.0))
newTree := tree.Copy()
node1 := newTree.Search(fixedpoint.NewFromFloat(2000.0))
assert.NotNil(t, node1)
assert.Equal(t, fixedpoint.NewFromFloat(2000.0), node1.Key)
assert.Equal(t, fixedpoint.NewFromFloat(3.0), node1.Value)
node2 := newTree.Search(fixedpoint.NewFromFloat(3000.0))
assert.NotNil(t, node2)
assert.Equal(t, fixedpoint.NewFromFloat(3000.0), node2.Key)
assert.Equal(t, fixedpoint.NewFromFloat(1.0), node2.Value)
node3 := newTree.Search(fixedpoint.NewFromFloat(4000.0))
assert.NotNil(t, node3)
assert.Equal(t, fixedpoint.NewFromFloat(4000.0), node3.Key)
assert.Equal(t, fixedpoint.NewFromFloat(2.0), node3.Value)
}
func TestTree(t *testing.T) { func TestTree(t *testing.T) {
tree := NewRBTree() tree := NewRBTree()
tree.Insert(fixedpoint.NewFromFloat(3000.0), fixedpoint.NewFromFloat(10.0)) tree.Insert(fixedpoint.NewFromFloat(3000.0), fixedpoint.NewFromFloat(10.0))
@ -34,4 +59,5 @@ func TestTree(t *testing.T) {
deleted = tree.Delete(fixedpoint.NewFromFloat(1500.0)) deleted = tree.Delete(fixedpoint.NewFromFloat(1500.0))
assert.True(t, deleted) assert.True(t, deleted)
} }