code.vegaprotocol.io/vega@v0.79.0/core/execution/future/market_iceberg_test.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package future_test 17 18 import ( 19 "context" 20 "testing" 21 "time" 22 23 "code.vegaprotocol.io/vega/core/events" 24 "code.vegaprotocol.io/vega/core/execution/common" 25 "code.vegaprotocol.io/vega/core/types" 26 vegacontext "code.vegaprotocol.io/vega/libs/context" 27 vgcrypto "code.vegaprotocol.io/vega/libs/crypto" 28 "code.vegaprotocol.io/vega/libs/num" 29 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/require" 32 ) 33 34 func TestMarketSubmitCancelIceberg(t *testing.T) { 35 party1 := "party1" 36 now := time.Unix(100000, 0) 37 ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()) 38 tm := getTestMarket(t, now, nil, nil) 39 defer tm.ctrl.Finish() 40 41 addAccount(t, tm, party1) 42 iceberg := &types.Order{ 43 Type: types.OrderTypeLimit, 44 TimeInForce: types.OrderTimeInForceGTC, 45 Status: types.OrderStatusActive, 46 ID: "someid", 47 Side: types.SideBuy, 48 Party: party1, 49 MarketID: tm.market.GetID(), 50 Size: 100, 51 Price: num.NewUint(100), 52 Remaining: 100, 53 CreatedAt: now.UnixNano(), 54 Reference: "party1-buy-order", 55 Version: common.InitialOrderVersion, 56 IcebergOrder: &types.IcebergOrder{ 57 PeakSize: 10, 58 MinimumVisibleSize: 5, 59 }, 60 } 61 62 // submit order 63 _, err := tm.market.SubmitOrder(context.Background(), iceberg) 64 require.NoError(t, err) 65 66 tm.now = tm.now.Add(time.Second) 67 tm.market.OnTick(ctx, tm.now) 68 require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction 69 70 // check that its on the book and the volume is only the visible peak 71 assert.Equal(t, int64(100), tm.market.GetVolumeOnBook()) 72 73 // and that the position represents the whole iceberg size 74 tm.market.BlockEnd(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())) 75 pos := requirePositionUpdate(t, tm.events) 76 assert.Equal(t, int64(100), pos.PotentialBuys()) 77 78 // now cancel the order and check potential buy returns to 0 79 tm.events = tm.events[:0] 80 _, err = tm.market.CancelOrder(context.Background(), iceberg.Party, iceberg.ID, iceberg.ID) 81 require.NoError(t, err) 82 tm.market.BlockEnd(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())) 83 pos = requirePositionUpdate(t, tm.events) 84 assert.Equal(t, int64(0), pos.PotentialBuys()) 85 } 86 87 func TestMarketAmendIceberg(t *testing.T) { 88 party1 := "party1" 89 now := time.Unix(100000, 0) 90 ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()) 91 tm := getTestMarket(t, now, nil, nil) 92 defer tm.ctrl.Finish() 93 94 addAccount(t, tm, party1) 95 iceberg := &types.Order{ 96 Type: types.OrderTypeLimit, 97 TimeInForce: types.OrderTimeInForceGTC, 98 Status: types.OrderStatusActive, 99 ID: "someid", 100 Side: types.SideBuy, 101 Party: party1, 102 MarketID: tm.market.GetID(), 103 Size: 100, 104 Price: num.NewUint(100), 105 Remaining: 100, 106 CreatedAt: now.UnixNano(), 107 Reference: "party1-buy-order", 108 Version: common.InitialOrderVersion, 109 IcebergOrder: &types.IcebergOrder{ 110 PeakSize: 10, 111 MinimumVisibleSize: 5, 112 }, 113 } 114 115 // submit order 116 _, err := tm.market.SubmitOrder(context.Background(), iceberg) 117 require.NoError(t, err) 118 119 tm.now = tm.now.Add(time.Second) 120 tm.market.OnTick(ctx, tm.now) 121 require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction 122 123 // now reduce the size of the iceberg so that only the reserved amount is reduced 124 amendedOrder := &types.OrderAmendment{ 125 OrderID: iceberg.ID, 126 Price: nil, 127 SizeDelta: -50, 128 TimeInForce: types.OrderTimeInForceGTC, 129 } 130 131 tm.eventCount = 0 132 tm.events = tm.events[:0] 133 _, err = tm.market.AmendOrder(context.Background(), amendedOrder, party1, vgcrypto.RandomHash()) 134 require.NoError(t, err) 135 amended := requireOrderEvent(t, tm.events) 136 assert.Equal(t, uint64(50), amended.Size) 137 assert.Equal(t, iceberg.Remaining, amended.Remaining) 138 assert.Equal(t, uint64(40), amended.IcebergOrder.ReservedRemaining) 139 140 // now increase the size delta and check that reserved remaining is increase, but remaining is the same 141 amendedOrder.SizeDelta = 70 142 tm.eventCount = 0 143 tm.events = tm.events[:0] 144 _, err = tm.market.AmendOrder(context.Background(), amendedOrder, party1, vgcrypto.RandomHash()) 145 require.NoError(t, err) 146 amended = requireOrderEvent(t, tm.events) 147 assert.Equal(t, uint64(120), amended.Size) 148 assert.Equal(t, iceberg.Remaining, amended.Remaining) 149 assert.Equal(t, uint64(110), amended.IcebergOrder.ReservedRemaining) 150 151 // now reduce the size such that reserved is reduce to 0 and some remaining is removed too 152 amendedOrder.SizeDelta = -115 153 tm.eventCount = 0 154 tm.events = tm.events[:0] 155 _, err = tm.market.AmendOrder(context.Background(), amendedOrder, party1, vgcrypto.RandomHash()) 156 require.NoError(t, err) 157 amended = requireOrderEvent(t, tm.events) 158 assert.Equal(t, uint64(5), amended.Size) 159 assert.Equal(t, uint64(5), amended.Remaining) 160 assert.Equal(t, uint64(0), amended.IcebergOrder.ReservedRemaining) 161 } 162 163 func TestMarketAmendIcebergToNoReserve(t *testing.T) { 164 party1 := "party1" 165 now := time.Unix(100000, 0) 166 ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()) 167 tm := getTestMarket(t, now, nil, nil) 168 defer tm.ctrl.Finish() 169 170 addAccount(t, tm, party1) 171 iceberg := &types.Order{ 172 Type: types.OrderTypeLimit, 173 TimeInForce: types.OrderTimeInForceGTC, 174 Status: types.OrderStatusActive, 175 ID: "someid", 176 Side: types.SideBuy, 177 Party: party1, 178 MarketID: tm.market.GetID(), 179 Size: 100, 180 Price: num.NewUint(100), 181 Remaining: 100, 182 CreatedAt: now.UnixNano(), 183 Reference: "party1-buy-order", 184 Version: common.InitialOrderVersion, 185 IcebergOrder: &types.IcebergOrder{ 186 PeakSize: 100, 187 MinimumVisibleSize: 5, 188 }, 189 } 190 191 // submit order 192 _, err := tm.market.SubmitOrder(context.Background(), iceberg) 193 require.NoError(t, err) 194 195 tm.now = tm.now.Add(time.Second) 196 tm.market.OnTick(ctx, tm.now) 197 require.Equal(t, types.MarketStateActive, tm.market.State()) // enter auction 198 199 // now reduce the size of the iceberg so that only the reserved amount is reduced 200 amendedOrder := &types.OrderAmendment{ 201 OrderID: iceberg.ID, 202 Price: nil, 203 SizeDelta: -75, 204 TimeInForce: types.OrderTimeInForceGTC, 205 } 206 207 tm.eventCount = 0 208 tm.events = tm.events[:0] 209 _, err = tm.market.AmendOrder(context.Background(), amendedOrder, party1, vgcrypto.RandomHash()) 210 require.NoError(t, err) 211 amended := requireOrderEvent(t, tm.events) 212 assert.Equal(t, uint64(25), amended.Size) 213 assert.Equal(t, uint64(25), amended.Remaining) 214 assert.Equal(t, uint64(0), amended.IcebergOrder.ReservedRemaining) 215 } 216 217 func requireOrderEvent(t *testing.T, evts []events.Event) *types.Order { 218 t.Helper() 219 for _, e := range evts { 220 switch evt := e.(type) { 221 case *events.Order: 222 o, err := types.OrderFromProto(evt.Order()) 223 require.NoError(t, err) 224 return o 225 } 226 } 227 require.Fail(t, "did not find order event") 228 return nil 229 } 230 231 func requirePositionUpdate(t *testing.T, evts []events.Event) *events.PositionState { 232 t.Helper() 233 for _, e := range evts { 234 switch evt := e.(type) { 235 case *events.PositionState: 236 return evt 237 } 238 } 239 require.Fail(t, "did not find position update event") 240 return nil 241 }