Skip to content

Commit

Permalink
feat: (#51) shopspring integration
Browse files Browse the repository at this point in the history
  • Loading branch information
gandharv-pantelwar committed Aug 1, 2022
1 parent 4634294 commit 0afb90d
Show file tree
Hide file tree
Showing 14 changed files with 234 additions and 119 deletions.
51 changes: 25 additions & 26 deletions engine/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,26 @@ import (
"fmt"
"strconv"

"github.com/ericlagergren/decimal"
"gopkg.in/go-playground/validator.v9"
"github.com/Pantelwar/matching-engine/util"
)

// Order describes the struct of the order
type Order struct {
Amount *decimal.Big `json:"amount"` // validate:"gt=0"`
Price *decimal.Big `json:"price"` // validate:"gt=0"`
ID string `json:"id"` // validate:"required"`
Type Side `json:"type"` // validate:"side_validate"`
Amount *util.StandardBigDecimal `json:"amount"` // validate:"gt=0"`
Price *util.StandardBigDecimal `json:"price"` // validate:"gt=0"`
ID string `json:"id"` // validate:"required"`
Type Side `json:"type"` // validate:"side_validate"`
}

func sideValidation(fl validator.FieldLevel) bool {
if fl.Field().Interface() != Buy && fl.Field().Interface() != Sell {
return false
}
return true
}
// func sideValidation(fl validator.FieldLevel) bool {
// if fl.Field().Interface() != Buy && fl.Field().Interface() != Sell {
// return false
// }
// return true
// }

// NewOrder returns *Order
func NewOrder(id string, orderType Side, amount, price *decimal.Big) *Order {
func NewOrder(id string, orderType Side, amount, price *util.StandardBigDecimal) *Order {
o := &Order{ID: id, Type: orderType, Amount: amount, Price: price}
return o
}
Expand All @@ -48,8 +47,8 @@ func (order *Order) ToJSON() ([]byte, error) {

// String implements Stringer interface
func (order *Order) String() string {
amount, _ := order.Amount.Float64()
price, _ := order.Price.Float64()
amount := order.Amount.Float64()
price := order.Price.Float64()

return fmt.Sprintf("\"%s\":\n\tside: %v\n\tquantity: %s\n\tprice: %s\n", order.ID, order.Type, strconv.FormatFloat(amount, 'f', -1, 64), strconv.FormatFloat(price, 'f', -1, 64))
}
Expand All @@ -72,28 +71,28 @@ func (order *Order) UnmarshalJSON(data []byte) error {
return errors.New("ID is not present")
}
if obj.Type == "" {
return errors.New("Invalid order type")
return errors.New("invalid order type")
}

var ok bool
order.Price, ok = new(decimal.Big).SetString(obj.Price) //.Quantize(8)
if !ok {
fmt.Println("price", order.Price, ok)
return errors.New("Invalid order price")
var err error
order.Price, err = util.NewDecimalFromString(obj.Price) //.Quantize(8)
if err != nil {
fmt.Println("price", order.Price, err.Error())
return errors.New("invalid order price")
}
order.Amount, ok = new(decimal.Big).SetString(obj.Amount) //.Quantize(8)
if !ok {
return errors.New("Invalid order amount")
order.Amount, err = util.NewDecimalFromString(obj.Amount) //.Quantize(8)
if err != nil {
return errors.New("invalid order amount")
}

order.Type = obj.Type
order.ID = obj.ID

price, _ := order.Price.Float64()
price := order.Price.Float64()
if price <= 0 {
return errors.New("Order price should be greater than zero")
}
amount, _ := order.Amount.Float64()
amount := order.Amount.Float64()
if amount <= 0 {
return errors.New("Order amount should be greater than zero")
}
Expand Down
20 changes: 10 additions & 10 deletions engine/order_book.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"sync"

"github.com/Pantelwar/binarytree"
"github.com/ericlagergren/decimal"
"github.com/Pantelwar/matching-engine/util"
)

// OrderBook type
Expand All @@ -28,8 +28,8 @@ type Book struct {
}

type orderinfo struct {
Price *decimal.Big `json:"price"`
Amount *decimal.Big `json:"amount"`
Price *util.StandardBigDecimal `json:"price"`
Amount *util.StandardBigDecimal `json:"amount"`
}

// MarshalJSON implements json.Marshaler interface
Expand All @@ -45,7 +45,7 @@ func (ob *OrderBook) MarshalJSON() ([]byte, error) {
// fmt.Println(" value", i)
var b orderinfo
// res := fmt.Sprintf("%#f -> ", i)
b.Price = new(decimal.Big).SetFloat64(i)
b.Price = util.NewDecimalFromFloat(i)
subNode := node.Data.(*OrderType).Tree.Root.SearchSubTree(i)
// fmt.Printf("subnode: %#v\n", subNode)
// fmt.Printf("volume:%#v, %#v\n\n", subNode.Data.(*OrderNode).Volume, len(subNode.Data.(*OrderNode).Orders))
Expand All @@ -67,7 +67,7 @@ func (ob *OrderBook) MarshalJSON() ([]byte, error) {
// fmt.Println(" value", i)
var b orderinfo
// res := fmt.Sprintf("%#f -> ", i)
b.Price = new(decimal.Big).SetFloat64(i)
b.Price = util.NewDecimalFromFloat(i)
subNode := node.Data.(*OrderType).Tree.Root.SearchSubTree(i)
// fmt.Printf("subnode: %#v\n", subNode)
// fmt.Printf("volume:%#v, %#v\n\n", subNode.Data.(*OrderNode).Volume, len(subNode.Data.(*OrderNode).Orders))
Expand Down Expand Up @@ -153,7 +153,7 @@ func (ob *OrderBook) String() string {
subNode := node.Data.(*OrderType).Tree.Root.SearchSubTree(i)
// fmt.Printf("subnode: %#v\n", subNode)
// fmt.Printf("volume:%#v, %#v\n\n", subNode.Data.(*OrderNode).Volume, len(subNode.Data.(*OrderNode).Orders))
vol, _ := subNode.Data.(*OrderNode).Volume.Float64()
vol := subNode.Data.(*OrderNode).Volume.Float64()
res += strconv.FormatFloat(vol, 'f', -1, 64) //subNode.Data.(*OrderNode).Volume.String() // strings.Trim(subNode.Data.(*OrderNode).Volume.String(), "0")
// fmt.Println("res", res)
orderSideSell = append(orderSideSell, res)
Expand All @@ -179,7 +179,7 @@ func (ob *OrderBook) String() string {
res := strconv.FormatFloat(i, 'f', -1, 64) + " -> "
subNode := node.Data.(*OrderType).Tree.Root.SearchSubTree(i)
// fmt.Printf("subnode: %#v\n", subNode)
vol, _ := subNode.Data.(*OrderNode).Volume.Float64()
vol := subNode.Data.(*OrderNode).Volume.Float64()
res += strconv.FormatFloat(vol, 'f', -1, 64) //subNode.Data.(*OrderNode).Volume.String() // strings.Trim(subNode.Data.(*OrderNode).Volume.String(), "0")
// fmt.Println("res b", res)
orderSideBuy = append(orderSideBuy, res)
Expand Down Expand Up @@ -214,7 +214,7 @@ func NewOrderBook() *OrderBook {

// addBuyOrder a buy order to the order book
func (ob *OrderBook) addBuyOrder(order Order) {
orderPrice, _ := order.Price.Float64()
orderPrice := order.Price.Float64()
startPoint := float64(int(math.Ceil(orderPrice)) / ob.orderLimitRange * ob.orderLimitRange)
endPoint := startPoint + float64(ob.orderLimitRange)
searchNodePrice := (startPoint + endPoint) / 2
Expand Down Expand Up @@ -250,7 +250,7 @@ func (ob *OrderBook) addBuyOrder(order Order) {

// addSellOrder a buy order to the order book
func (ob *OrderBook) addSellOrder(order Order) {
orderPrice, _ := order.Price.Float64()
orderPrice := order.Price.Float64()
startPoint := float64(int(math.Ceil(orderPrice)) / ob.orderLimitRange * ob.orderLimitRange)
endPoint := startPoint + float64(ob.orderLimitRange)
searchNodePrice := (startPoint + endPoint) / 2
Expand Down Expand Up @@ -296,7 +296,7 @@ func (ob *OrderBook) removeSellNode(key float64) error {
}

func (ob *OrderBook) removeOrder(order *Order) error {
orderPrice, _ := order.Price.Float64()
orderPrice := order.Price.Float64()
startPoint := float64(int(math.Ceil(orderPrice)) / ob.orderLimitRange * ob.orderLimitRange)
endPoint := startPoint + float64(ob.orderLimitRange)
searchNodePrice := (startPoint + endPoint) / 2
Expand Down
12 changes: 6 additions & 6 deletions engine/order_book_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import (
"testing"

"github.com/Pantelwar/binarytree"
"github.com/ericlagergren/decimal"
"github.com/Pantelwar/matching-engine/util"
)

func TestNewOrderBook(t *testing.T) {
t.Log(NewOrderBook())
}

func DecimalBig(val string) *decimal.Big {
a, _ := new(decimal.Big).SetString(val)
func DecimalBig(val string) *util.StandardBigDecimal {
a, _ := util.NewDecimalFromString(val)
return a
}

Expand All @@ -40,7 +40,7 @@ func TestAddOrderInBook(t *testing.T) {
t.Fatal("Order should be pushed in orders array")
}

price, _ := tt.input.Price.Float64()
price := tt.input.Price.Float64()
startPoint := float64(int(math.Ceil(price)) / ob.orderLimitRange * ob.orderLimitRange)
endPoint := startPoint + float64(ob.orderLimitRange)
searchNodePrice := (startPoint + endPoint) / 2
Expand Down Expand Up @@ -77,7 +77,7 @@ func TestRemoveOrderNodeFromBook(t *testing.T) {
}
}

price, _ := tests[0].input.Price.Float64()
price := tests[0].input.Price.Float64()
startPoint := float64(int(math.Ceil(price)) / ob.orderLimitRange * ob.orderLimitRange)
endPoint := startPoint + float64(ob.orderLimitRange)
searchNodePrice := (startPoint + endPoint) / 2
Expand All @@ -91,7 +91,7 @@ func TestRemoveOrderNodeFromBook(t *testing.T) {
t.Fatal("Buy Mid Price should be get removed from tree")
}

price, _ = tests[1].input.Price.Float64()
price = tests[1].input.Price.Float64()
startPoint = float64(int(math.Ceil(price)) / ob.orderLimitRange * ob.orderLimitRange)
endPoint = startPoint + float64(ob.orderLimitRange)
searchNodePrice = (startPoint + endPoint) / 2
Expand Down
16 changes: 8 additions & 8 deletions engine/order_node.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package engine

import (
"github.com/ericlagergren/decimal"
"github.com/Pantelwar/matching-engine/util"
)

// OrderNode ...
type OrderNode struct {
Orders []*Order `json:"orders"`
Volume *decimal.Big `json:"volume"`
Orders []*Order `json:"orders"`
Volume *util.StandardBigDecimal `json:"volume"`
}

// NewOrderNode returns new OrderNode struct
func NewOrderNode() *OrderNode {
vol, _ := new(decimal.Big).SetString("0.0")
vol, _ := util.NewDecimalFromString("0.0")
return &OrderNode{Orders: []*Order{}, Volume: vol}
}

Expand All @@ -22,7 +22,7 @@ func (on *OrderNode) addOrder(order Order) {
for _, o := range on.Orders {
if o.ID == order.ID {
if o.Amount != order.Amount {
on.updateVolume(new(decimal.Big).Neg(o.Amount))
on.updateVolume(o.Amount.Neg())
o.Amount = order.Amount
o.Price = order.Price
on.updateVolume(o.Amount)
Expand All @@ -39,14 +39,14 @@ func (on *OrderNode) addOrder(order Order) {
}

// updateVolume updates volume
func (on *OrderNode) updateVolume(value *decimal.Big) {
on.Volume = new(decimal.Big).Add(on.Volume, value)
func (on *OrderNode) updateVolume(value *util.StandardBigDecimal) {
on.Volume = on.Volume.Add(value)
// fmt.Println("onVolume", on.Volume)
}

// removeOrder removes order from OrderNode array
func (on *OrderNode) removeOrder(index int) {
on.updateVolume(new(decimal.Big).Neg(on.Orders[index].Amount))
on.updateVolume(on.Orders[index].Amount.Neg())
on.Orders = append(on.Orders[:index], on.Orders[index+1:]...)
}

Expand Down
8 changes: 4 additions & 4 deletions engine/order_node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func TestAddOrderInNode(t *testing.T) {
volume := DecimalBig("0.0")
for _, tt := range tests {
on.addOrder(*tt.input)
volume = volume.Add(volume, tt.input.Amount)
volume = volume.Add(tt.input.Amount)
}

if len(on.Orders) != len(tests) {
Expand All @@ -46,11 +46,11 @@ func TestRemoveOrderFromNode(t *testing.T) {
volume := DecimalBig("0.0")
for _, tt := range tests {
on.addOrder(*tt.input)
volume = volume.Add(volume, tt.input.Amount)
volume = volume.Add(tt.input.Amount)
}

on.removeOrder(0)
volume = volume.Sub(volume, tests[0].input.Amount)
volume = volume.Sub(tests[0].input.Amount)

if len(on.Orders) != len(tests)-1 {
t.Fatalf("Invalid order length (have: %d, want: %d", len(on.Orders), len(tests))
Expand All @@ -74,7 +74,7 @@ func TestUpdateVolume(t *testing.T) {
volume := DecimalBig("0.0")
for _, tt := range tests {
on.updateVolume(tt.input.Amount)
volume = volume.Add(volume, tt.input.Amount)
volume = volume.Add(tt.input.Amount)
}

if on.Volume.Cmp(volume) != 0 {
Expand Down
4 changes: 2 additions & 2 deletions engine/order_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ func NewOrderType(orderSide Side) *OrderType {
// AddOrderInQueue adds order to the tree
func (ot *OrderType) AddOrderInQueue(order Order) (*OrderNode, error) {
if ot.Type != order.Type {
return nil, errors.New("Invalid order type")
return nil, errors.New("invalid order type")
}
orderNode := NewOrderNode()
orderNode.Orders = append(orderNode.Orders, &order)
orderNode.Volume = order.Amount
orderPrice, _ := order.Price.Float64()
orderPrice := order.Price.Float64()
ot.Tree.Insert(orderPrice, orderNode)
return orderNode, nil
}
2 changes: 1 addition & 1 deletion engine/order_type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestAddOrderInQueue(t *testing.T) {
}
}

price, _ := tests[1].input.Price.Float64()
price := tests[1].input.Price.Float64()
node := ot.Tree.Root.SearchSubTree(price)
if node == nil {
t.Fatal("There should exists a node in orderType.Tree")
Expand Down
Loading

0 comments on commit 0afb90d

Please sign in to comment.