Skip to content

Commit

Permalink
float math instead
Browse files Browse the repository at this point in the history
  • Loading branch information
buck54321 committed Sep 24, 2023
1 parent babf274 commit 3c1bca5
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 18 deletions.
8 changes: 2 additions & 6 deletions dex/calc/parcels.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@ package calc
// Parcels calculates the number of parcels associated with the given order
// quantities, lot size and parcel size. Any quantity currently settling
// should be summed in with the makerQty.
func Parcels(makerQty, takerQty, lotSize uint64, parcelSize uint32) uint32 {
func Parcels(makerQty, takerQty, lotSize uint64, parcelSize uint32) float64 {
parcelWeight := makerQty + takerQty*2
parcelQty := lotSize * uint64(parcelSize)
parcels := parcelWeight / parcelQty
if parcelWeight%parcelQty != 0 {
parcels++
}
return uint32(parcels)
return float64(parcelWeight) / float64(parcelQty)
}
6 changes: 3 additions & 3 deletions server/market/market.go
Original file line number Diff line number Diff line change
Expand Up @@ -1737,11 +1737,11 @@ func (m *Market) ParcelSize() uint32 {
// settling quantity. Parcels is used as part of order validation for global
// parcel limits. Parcels is not called for the market for which the order is
// for, which will use m.checkParcelLimit to validate in processOrder.
func (m *Market) Parcels(user account.AccountID, settlingQty uint64) uint32 {
func (m *Market) Parcels(user account.AccountID, settlingQty uint64) float64 {
return m.parcels(user, settlingQty)
}

func (m *Market) parcels(user account.AccountID, addParcelWeight uint64) uint32 {
func (m *Market) parcels(user account.AccountID, addParcelWeight uint64) float64 {
likelyTaker, baseQty := m.analysisHelpers()
var takerQty, makerQty uint64
m.epochMtx.RLock()
Expand Down Expand Up @@ -1839,7 +1839,7 @@ func (m *Market) processOrder(rec *orderRecord, epoch *EpochQueue, notifyChan ch
if likelyTaker(ord) {
orderWeight *= 2
}
calcParcels := func(settlingWeight uint64) uint32 {
calcParcels := func(settlingWeight uint64) float64 {
return m.parcels(user, settlingWeight+orderWeight)
}
if !m.checkParcelLimit(user, calcParcels) {
Expand Down
2 changes: 1 addition & 1 deletion server/market/market_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ const (
tUserTier, tUserScore, tMaxScore = int64(1), int32(30), int32(60)
)

var parcelLimit = calcParcelLimit(tUserTier, tUserScore, tMaxScore)
var parcelLimit = float64(calcParcelLimit(tUserTier, tUserScore, tMaxScore))

func newTestMarket(opts ...interface{}) (*Market, *TArchivist, *TAuth, func(), error) {
// The DEX will make MasterCoinLockers for each asset.
Expand Down
20 changes: 15 additions & 5 deletions server/market/orderrouter.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ type MarketTunnel interface {
CheckUnfilled(assetID uint32, user account.AccountID) (unbooked []*order.LimitOrder)

// Parcels calculates the number of active parcels for the market.
Parcels(user account.AccountID, settlingQty uint64) uint32
Parcels(user account.AccountID, settlingQty uint64) float64
}

type MarketParcelCalculator func(settlingQty uint64) (parcels uint32)
type MarketParcelCalculator func(settlingQty uint64) (parcels float64)

// orderRecord contains the information necessary to respond to an order
// request.
Expand Down Expand Up @@ -703,6 +703,16 @@ func (r *OrderRouter) CheckParcelLimit(user account.AccountID, targetMarketName
if tier <= 0 {
return false
}

roundParcels := func(parcels float64) uint32 {
// Rounding to 8 decimal places first should resolve any floating point
// error, then we take the floor. 1e8 is not completetly arbitrary. We
// need to choose a number of decimals of an order > the expected parcel
// size of a low-lot-size market, which I expect wouldn't be greater
// than 1e5.
return uint32(math.Round(parcels*1e8) / 1e8)
}

parcelLimit := calcParcelLimit(tier, score, maxScore)

settlingQuantities := make(map[string]uint64)
Expand All @@ -711,7 +721,7 @@ func (r *OrderRouter) CheckParcelLimit(user account.AccountID, targetMarketName
settlingQuantities[mktName] += qty
}

var otherMarketParcels uint32
var otherMarketParcels float64
var settlingQty uint64
for mktName, mkt := range r.tunnels {
if mktName == targetMarketName {
Expand All @@ -720,13 +730,13 @@ func (r *OrderRouter) CheckParcelLimit(user account.AccountID, targetMarketName
}

otherMarketParcels += mkt.Parcels(user, settlingQuantities[mktName])
if otherMarketParcels > parcelLimit {
if roundParcels(otherMarketParcels) > parcelLimit {
return false
}
}
targetMarketParcels := calcParcels(settlingQty)

return otherMarketParcels+targetMarketParcels <= parcelLimit
return roundParcels(otherMarketParcels+targetMarketParcels) <= parcelLimit
}

func (r *OrderRouter) submitOrderToMarket(tunnel MarketTunnel, oRecord *orderRecord) *msgjson.Error {
Expand Down
6 changes: 3 additions & 3 deletions server/market/routers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ type TMarketTunnel struct {
acctLots uint64
acctRedeems int
base, quote uint32
parcels uint32
parcels float64
}

func tNewMarket(auth *TAuth) *TMarketTunnel {
Expand Down Expand Up @@ -383,7 +383,7 @@ func (m *TMarketTunnel) Quote() uint32 {
return m.quote
}

func (m *TMarketTunnel) Parcels(account.AccountID, uint64) uint32 {
func (m *TMarketTunnel) Parcels(account.AccountID, uint64) float64 {
return m.parcels
}

Expand Down Expand Up @@ -2230,7 +2230,7 @@ func TestParcelLimits(t *testing.T) {
oRecord := &orderRecord{order: lo}

lotSize := mkt0.LotSize()
calcParcels := func(settlingWeight uint64) uint32 {
calcParcels := func(settlingWeight uint64) float64 {
return calc.Parcels(settlingWeight+lo.Quantity, 0, lotSize, 1)
}

Expand Down

0 comments on commit 3c1bca5

Please sign in to comment.