Skip to content

Commit

Permalink
Merge pull request #11569 from vegaprotocol/11568-shape-almost-closed…
Browse files Browse the repository at this point in the history
…-amm

fix: orderbook shape on almost closed out AMM can be calculated exactly
  • Loading branch information
jeremyletang authored Aug 13, 2024
2 parents b4637d2 + e680f01 commit aecf399
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
- [11526](https://github.com/vegaprotocol/vega/issues/11526) - `EstimateAMMBounds` now respects the market's decimal places.
- [11486](https://github.com/vegaprotocol/vega/issues/11486) - `AMMs` can now be submitted on markets with more decimal places than asset decimal places.
- [11561](https://github.com/vegaprotocol/vega/issues/11561) - Failing amends on `AMMs` now restore original properly.
- [11568](https://github.com/vegaprotocol/vega/issues/11568) - order book shape on closing `AMM` no longer panics.
- [11540](https://github.com/vegaprotocol/vega/issues/11540) - Fix spam check for spots to use not double count quantum.
- [11542](https://github.com/vegaprotocol/vega/issues/11542) - Fix non determinism in lottery ranking.
- [11544](https://github.com/vegaprotocol/vega/issues/11544) - Fix empty candles stream.
Expand Down
22 changes: 18 additions & 4 deletions core/execution/amm/shape.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func (sm *shapeMaker) calculateBoundaryOrders() (*types.Order, *types.Order) {
bnd1 := sm.makeBoundaryOrder(st, sm.from)

if sm.log.IsDebug() {
sm.log.Debug("creating boundary order",
sm.log.Debug("created boundary order",
logging.String("price", bnd1.Price.String()),
logging.String("side", bnd1.Side.String()),
logging.Uint64("volume", bnd1.Size),
Expand All @@ -143,7 +143,7 @@ func (sm *shapeMaker) calculateBoundaryOrders() (*types.Order, *types.Order) {
bnd2 := sm.makeBoundaryOrder(sm.to, nd)

if sm.log.IsDebug() {
sm.log.Debug("creating boundary order",
sm.log.Debug("created boundary order",
logging.String("price", bnd2.Price.String()),
logging.String("side", bnd2.Side.String()),
logging.Uint64("volume", bnd2.Size),
Expand Down Expand Up @@ -294,10 +294,25 @@ func (sm *shapeMaker) adjustRegion() bool {
// only orders between fair-price -> base
lower = sm.fairPrice.Clone()
upper = sm.pool.lower.high.Clone()

// if the AMM is super close to closing its position the delta between fair-price -> base
// could be very small, but the upshot is we know it will only be one order and can calculate
// directly
if num.UintZero().Sub(upper, lower).LTE(sm.oneTick) {
price := num.UintZero().Sub(sm.pool.lower.high, sm.oneTick)
sm.addOrder(uint64(sm.pos), price, types.SideSell)
return false
}
} else {
// only orders between base -> fair-price
upper = sm.fairPrice.Clone()
lower = sm.pool.lower.high.Clone()

if num.UintZero().Sub(upper, lower).LTE(sm.oneTick) {
price := num.UintZero().Add(sm.pool.lower.high, sm.oneTick)
sm.addOrder(uint64(-sm.pos), price, types.SideBuy)
return false
}
}
}

Expand All @@ -313,7 +328,6 @@ func (sm *shapeMaker) adjustRegion() bool {
// cap the range to the pool's bounds, there will be no orders outside of this
from := num.Max(sm.from, lower)
to := num.Min(sm.to, upper)

switch {
case sm.from.GT(sm.fairPrice):
// if we are expanding entirely in the sell range to calculate the order at price `from`
Expand All @@ -340,7 +354,7 @@ func (sm *shapeMaker) adjustRegion() bool {
func (sm *shapeMaker) makeShape() ([]*types.Order, []*types.Order) {
if !sm.adjustRegion() {
// if there is no overlap between the input region and the AMM's bounds then there are no orders
return nil, nil
return sm.buys, sm.sells
}

// create accurate orders at the boundary of the adjusted region (even if we are going to make approximate internal steps)
Expand Down
57 changes: 57 additions & 0 deletions core/execution/amm/shape_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func TestOrderbookShape(t *testing.T) {
t.Run("test orderbook shape AMM reduce only", testOrderbookShapeReduceOnly)
t.Run("test orderbook shape boundary order when approx", testOrderbookShapeBoundaryOrder)
t.Run("test orderbook shape region not divisible by tick", testOrderbookSubTick)
t.Run("test orderbook shape closing pool close to base", testClosingCloseToBase)
}

func testOrderbookShapeZeroPosition(t *testing.T) {
Expand Down Expand Up @@ -359,3 +360,59 @@ func testOrderbookSubTick(t *testing.T) {

assert.Equal(t, 0, len(sells))
}

func testClosingCloseToBase(t *testing.T) {
p := newTestPoolWithSubmission(t, num.DecimalFromFloat(1), num.DecimalFromFloat(100),
&types.SubmitAMM{
CommitmentAmount: num.NewUint(10000000),
Parameters: &types.ConcentratedLiquidityParameters{
LowerBound: num.NewUint(10),
Base: num.NewUint(15),
UpperBound: num.NewUint(20),
},
},
)

defer p.ctrl.Finish()

// its reducing
p.pool.status = types.AMMPoolStatusReduceOnly

// and it is long one
position := int64(1)
ensurePositionN(t, p.pos, position, num.UintZero(), 2)

// now pretend we are in auction and we have a sell order at 1000, so we need to expand the crossed
// region of 1000 -> 1383
from := num.NewUint(1000)
to := num.NewUint(2000)
buys, sells := p.pool.OrderbookShape(from, to, nil)

// should have one sell of volume 1
assert.Equal(t, 0, len(buys))
assert.Equal(t, 1, len(sells))
assert.Equal(t, 1, int(sells[0].Size))
assert.Equal(t, "14", sells[0].OriginalPrice.String())

// and it is short one
position = int64(-1)
ensurePositionN(t, p.pos, position, num.UintZero(), 2)

buys, sells = p.pool.OrderbookShape(from, to, nil)

// should have one sell of volume 1
assert.Equal(t, 1, len(buys))
assert.Equal(t, 0, len(sells))
assert.Equal(t, 1, int(buys[0].Size))
assert.Equal(t, "16", buys[0].OriginalPrice.String())

// no position
position = int64(0)
ensurePositionN(t, p.pos, position, num.UintZero(), 2)

buys, sells = p.pool.OrderbookShape(from, to, nil)

// should have one sell of volume 1
assert.Equal(t, 0, len(buys))
assert.Equal(t, 0, len(sells))
}

0 comments on commit aecf399

Please sign in to comment.