-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Starting matching and orderbook abstractions
- Loading branch information
Showing
6 changed files
with
157 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
language: go | ||
|
||
# Force-enable Go modules. | ||
# This will be unnecessary when Go 1.13 lands. | ||
env: | ||
- GO111MODULE=on | ||
|
||
go: | ||
- 1.12.x | ||
|
||
# script always runs to completion | ||
script: | ||
- go test -v -race ./... # Run all the tests with the race detector enabled |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package match | ||
|
||
// LimitOrderbook provides all of the operations needed for a normal exchange orderbook. This should be a single-pair orderbook. TODO: Determine if this should actually be a single-pair orderbook | ||
type LimitOrderbook interface { | ||
// SetMatchingAlgorithm should set the matching algorithm. TODO: I want this to be a thing. | ||
// SetMatchingAlgorithm(func(book *LimitOrderbook) (err error)) (err error) | ||
// PlaceOrders places multiple orders in the orderbook, and returns orders with their assigned IDs. These orders will all get the same time priority, we assume they come in at the same time. | ||
// TODO: figure out if this is the right thing to do, or if PlaceOrder should be here instead | ||
PlaceOrders(orders []*LimitOrder) (idOrders []*LimitOrder, err error) | ||
// GetBook takes in a trading pair and returns the whole orderbook. | ||
GetBook() (book []*LimitOrder, err error) | ||
// GetOrder gets an order from an OrderID | ||
GetOrder(id *OrderID) (order *LimitOrder, err error) | ||
// CancelOrder cancels an order with order id | ||
CancelOrder(id *OrderID) (err error) | ||
// CalculatePrice returns the calculated price based on the order book. | ||
CalculatePrice() (price Price, err error) | ||
// GetPairs gets the trading pair we can trade on | ||
GetPair() (pair *Pair, err error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package match | ||
|
||
import ( | ||
"encoding/hex" | ||
"fmt" | ||
) | ||
|
||
// OrderID represents an order's unique ID. | ||
// This is a byte array alias because sometimes the ID will be represented as text, and sometimes it will be represented as bytes. | ||
// We conform it to the BinaryMarshaler interface and TextMarshaler interface. | ||
type OrderID []byte | ||
|
||
// MarshalBinary encodes the receiver into a binary form and returns the result. This conforms to the BinaryMarshaler interface | ||
func (o *OrderID) MarshalBinary() (data []byte, err error) { | ||
copy(data, *o) | ||
return | ||
} | ||
|
||
// UnmarshalBinary decodes the form generated by MarshalBinary. This conforms to the BinaryMarshaler interface | ||
func (o *OrderID) UnmarshalBinary(data []byte) (err error) { | ||
copy(*o, data) | ||
return | ||
} | ||
|
||
// MarshalText encodes the receiver into UTF-8-encoded text and returns the result. This conforms to the TextMarshaler interface | ||
func (o *OrderID) MarshalText() (text []byte, err error) { | ||
copy(text, []byte(hex.EncodeToString(*o))) | ||
return | ||
} | ||
|
||
// UnmarshalText deocdes the form generated by MarshalText. This conforms to the TextMarshaler interface | ||
func (o *OrderID) UnmarshalText(text []byte) (err error) { | ||
if _, err = hex.Decode(*o, text); err != nil { | ||
err = fmt.Errorf("Error unmarshalling text OrderID: %s", err) | ||
return | ||
} | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package match | ||
|
||
import ( | ||
"fmt" | ||
"math/big" | ||
) | ||
|
||
// Price represents an exchange rate. It's basically a fancy fraction. It follows the Want / Have method of doing things. Removal of Want/Have is TODO. | ||
// We don't want this to be a big int because that means it can't really be sent over the wire. We're not multiple precision here, but we do want some | ||
// standard, reasonable level of precision | ||
type Price struct { | ||
AmountWant uint64 | ||
AmountHave uint64 | ||
} | ||
|
||
// Note on the Want / Have model: It makes sense from an exchange perspective, but in reality "side", "price", and "volume" are all connected. | ||
|
||
// ToFloat converts the price to a float value | ||
func (p *Price) ToFloat() (price float64, err error) { | ||
if p.AmountHave == 0 { | ||
err = fmt.Errorf("AmountHave cannot be 0 to convert to float") | ||
return | ||
} | ||
price = float64(p.AmountWant) / float64(p.AmountHave) | ||
return | ||
} | ||
|
||
// Cmp compares p and otherPrice and returns: | ||
// | ||
// -1 if x < y | ||
// 0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf) | ||
// +1 if x > y | ||
// | ||
func (p *Price) Cmp(otherPrice *Price) (compIndicator int) { | ||
// Just use math/big's comparison, they already wrote it | ||
price1 := new(big.Float).Quo(new(big.Float).SetUint64(p.AmountWant), new(big.Float).SetUint64(p.AmountHave)) | ||
price2 := new(big.Float).Quo(new(big.Float).SetUint64(otherPrice.AmountWant), new(big.Float).SetUint64(otherPrice.AmountHave)) | ||
compIndicator = price1.Cmp(price2) | ||
return | ||
} |