From 07d10d2824aaf2811024bd7e4666609d3b308861 Mon Sep 17 00:00:00 2001 From: matthewpendrey Date: Sun, 7 Nov 2021 12:57:21 +0000 Subject: [PATCH] added GetTickSize method to Listing --- model/listing.go | 18 ++++++ model/listing_test.go | 113 ++++++++++++++++++++++----------- ordermanagement/parentorder.go | 5 +- strategy/strategy.go | 9 ++- 4 files changed, 101 insertions(+), 44 deletions(-) diff --git a/model/listing.go b/model/listing.go index a01b16e..1e7d1b5 100644 --- a/model/listing.go +++ b/model/listing.go @@ -25,6 +25,24 @@ func (m *Listing) RoundToNearestTick(price float64) (*Decimal64, error) { return nil, fmt.Errorf("no tick table entry for price:%v", price) } + +func (m *Listing) GetTickSizeForPriceLevel( price float64) (*Decimal64, error) { + + for _, entry := range m.TickSize.Entries { + delta := entry.TickSize.ToFloat() / 1000 + lowerBound := entry.LowerPriceBound.ToFloat() + upperBound := entry.UpperPriceBound.ToFloat() + + if compare(price, lowerBound, delta) >= 0 && + compare(price, upperBound, delta) <= 0 { + return entry.TickSize, nil + } + } + + return nil, fmt.Errorf("no tick table entry for price:%v", price) +} + + func compare(f1 float64, f2 float64, delta float64) int { diff := f1 - f2 diff --git a/model/listing_test.go b/model/listing_test.go index 8f9f21c..09872ed 100644 --- a/model/listing_test.go +++ b/model/listing_test.go @@ -2,33 +2,72 @@ package model import "testing" -func TestListing_RoundToTickSize(t *testing.T) { - - tst := &TickSizeTable{ - Entries: []*TickSizeEntry{ - { - LowerPriceBound: &Decimal64{Mantissa: -100, Exponent: 0}, - UpperPriceBound: &Decimal64{Mantissa: -10, Exponent: 0}, - TickSize: &Decimal64{Mantissa: 1, Exponent: -1}, - }, - { - LowerPriceBound: &Decimal64{Mantissa: -10, Exponent: 0}, - UpperPriceBound: &Decimal64{Mantissa: 10, Exponent: 0}, - TickSize: &Decimal64{Mantissa: 1, Exponent: -2}, - }, - { - LowerPriceBound: &Decimal64{Mantissa: 10, Exponent: 0}, - UpperPriceBound: &Decimal64{Mantissa: 100, Exponent: 0}, - TickSize: &Decimal64{Mantissa: 1, Exponent: -1}, - }, - { - LowerPriceBound: &Decimal64{Mantissa: 100, Exponent: 0}, - UpperPriceBound: &Decimal64{Mantissa: 1000, Exponent: 0}, - TickSize: &Decimal64{Mantissa: 1, Exponent: 0}, - }, +var tickSizeTable = &TickSizeTable{ + Entries: []*TickSizeEntry{ + { + LowerPriceBound: &Decimal64{Mantissa: -100, Exponent: 0}, + UpperPriceBound: &Decimal64{Mantissa: -10, Exponent: 0}, + TickSize: &Decimal64{Mantissa: 1, Exponent: -1}, + }, + { + LowerPriceBound: &Decimal64{Mantissa: -10, Exponent: 0}, + UpperPriceBound: &Decimal64{Mantissa: 10, Exponent: 0}, + TickSize: &Decimal64{Mantissa: 1, Exponent: -2}, + }, + { + LowerPriceBound: &Decimal64{Mantissa: 10, Exponent: 0}, + UpperPriceBound: &Decimal64{Mantissa: 100, Exponent: 0}, + TickSize: &Decimal64{Mantissa: 1, Exponent: -1}, + }, + { + LowerPriceBound: &Decimal64{Mantissa: 100, Exponent: 0}, + UpperPriceBound: &Decimal64{Mantissa: 1000, Exponent: 0}, + TickSize: &Decimal64{Mantissa: 1, Exponent: 0}, }, + }, +} + +func TestListing_GetTickSizeForPriceLevel(t *testing.T) { + + tests := []struct { + name string + tst *TickSizeTable + price float64 + result *Decimal64 + wantErr bool + }{ + {"test", tickSizeTable, 9.13211, + &Decimal64{Mantissa: 1, Exponent: -2}, false}, + {"test", tickSizeTable, 253.4, + &Decimal64{Mantissa: 1, Exponent: 0}, false}, + {"test", tickSizeTable, 1253.4, + nil, true}, + {"test", tickSizeTable, -125.4, + nil, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Listing{ + TickSize: tt.tst, + } + + d, err := m.GetTickSizeForPriceLevel(tt.price) + if (err != nil) != tt.wantErr { + t.Errorf("GetTickSizeForPriceLevel() error = %v, wantErr %v", err, tt.wantErr) + } + + if !d.Equal(tt.result) { + t.Errorf("GetTickSizeForPriceLevel() tickSize = %v, wanted %v", d, tt.result) + } + + }) } + +} + +func TestListing_RoundToTickSize(t *testing.T) { + tests := []struct { name string tst *TickSizeTable @@ -36,38 +75,38 @@ func TestListing_RoundToTickSize(t *testing.T) { result *Decimal64 wantErr bool }{ - {"test", tst, 9.13211, + {"test", tickSizeTable, 9.13211, &Decimal64{Mantissa: 913, Exponent: -2}, false}, - {"test", tst, 19.132, + {"test", tickSizeTable, 19.132, &Decimal64{Mantissa: 191, Exponent: -1}, false}, - {"test", tst, 200.1, + {"test", tickSizeTable, 200.1, &Decimal64{Mantissa: 200, Exponent: 0}, false}, - {"test", tst, -2.1163, + {"test", tickSizeTable, -2.1163, &Decimal64{Mantissa: -212, Exponent: -2}, false}, - {"test", tst, 2116.3, + {"test", tickSizeTable, 2116.3, nil, true}, - {"test", tst, 9.997, + {"test", tickSizeTable, 9.997, &Decimal64{Mantissa: 10, Exponent: 0}, false}, - {"test", tst, 9.9945, + {"test", tickSizeTable, 9.9945, &Decimal64{Mantissa: 999, Exponent: -2}, false}, - {"test", tst, 9.999945, + {"test", tickSizeTable, 9.999945, &Decimal64{Mantissa: 10, Exponent: 0}, false}, - {"test", tst, 10.00001, + {"test", tickSizeTable, 10.00001, &Decimal64{Mantissa: 10, Exponent: 0}, false}, - {"test", tst, -9.997, + {"test", tickSizeTable, -9.997, &Decimal64{Mantissa: -10, Exponent: 0}, false}, - {"test", tst, -9.9945, + {"test", tickSizeTable, -9.9945, &Decimal64{Mantissa: -999, Exponent: -2}, false}, - {"test", tst, -9.999945, + {"test", tickSizeTable, -9.999945, &Decimal64{Mantissa: -10, Exponent: 0}, false}, - {"test", tst, -10.00001, + {"test", tickSizeTable, -10.00001, &Decimal64{Mantissa: -10, Exponent: 0}, false}, } for _, tt := range tests { diff --git a/ordermanagement/parentorder.go b/ordermanagement/parentorder.go index 7e4a243..69e4df9 100644 --- a/ordermanagement/parentorder.go +++ b/ordermanagement/parentorder.go @@ -11,6 +11,8 @@ func init() { zero = &model.Decimal64{} } +// ParentOrder has a one to many relationship to its child orders. The parent aggregates and summarises state across +// its children. type ParentOrder struct { model.Order ChildOrders map[string]*model.Order @@ -19,8 +21,7 @@ type ParentOrder struct { childOrdersRecovered bool } -// Parent order has a one to many relationship to its child orders. The parent aggregates and summarises state across -// its children.S + func NewParentOrder(order model.Order) *ParentOrder { childOrderRefs := map[string]model.Ref{} diff --git a/strategy/strategy.go b/strategy/strategy.go index 04e64fa..c4348bd 100644 --- a/strategy/strategy.go +++ b/strategy/strategy.go @@ -72,8 +72,7 @@ func NewStrategyFromParentOrder(initialState *model.Order, store func(*model.Ord } - -// Sends a child order to the given destination and ensures the parent order cannot become over exposed. +// SendChildOrder Sends a child order to the given destination and ensures the parent order cannot become over exposed. func (om *Strategy) SendChildOrder(side model.Side, quantity *model.Decimal64, price *model.Decimal64, listingId int32, destination string, execParametersJson string) error { @@ -116,7 +115,7 @@ func (om *Strategy) SendChildOrder(side model.Side, quantity *model.Decimal64, p } -// This func must be called in the strategies event handling loop, see example strategies as per package documentation. +// CheckIfDone must be called in the strategies event handling loop, see example strategies as per package documentation. func (om *Strategy) CheckIfDone() (done bool, err error) { done = false err = om.persistParentOrderChanges() @@ -132,7 +131,7 @@ func (om *Strategy) CheckIfDone() (done bool, err error) { return done, nil } -// Must be called in response to receipt of a child order update in the strategy's event processing loop as per example strategies +// OnChildOrderUpdate must be called in response to receipt of a child order update in the strategy's event processing loop as per example strategies func (om *Strategy) OnChildOrderUpdate(ok bool, co *model.Order) error { if ok { _, err := om.ParentOrder.OnChildOrderUpdate(co) @@ -146,7 +145,7 @@ func (om *Strategy) OnChildOrderUpdate(ok bool, co *model.Order) error { return nil } -// Should only be called from with the strategy's event processing loop as per the example strategies +// CancelChildOrdersAndStrategyOrder should only be called from with the strategy's event processing loop as per the example strategies func (om *Strategy) CancelChildOrdersAndStrategyOrder() error { if !om.ParentOrder.IsTerminalState() { om.Log.Print("cancelling order")