From ee2a1b2a0001eb5ba8807bab098b71b45ba62082 Mon Sep 17 00:00:00 2001 From: Pete Barrow Date: Thu, 18 Apr 2024 17:52:41 +0100 Subject: [PATCH] feat: Adding spot market support for perftest --- cmd/perftest.go | 1 + perftest/perftest.go | 57 +++++++++++++++++++++++++++++++++--------- perftest/wallet.go | 59 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 11 deletions(-) diff --git a/cmd/perftest.go b/cmd/perftest.go index ae18d3d..6365d91 100644 --- a/cmd/perftest.go +++ b/cmd/perftest.go @@ -41,6 +41,7 @@ func init() { perfTestCmd.Flags().BoolVarP(&opts.DoNotInitialise, "donotinitialise", "I", false, "skip the initialise steps") perfTestCmd.Flags().BoolVarP(&opts.UseLPsForOrders, "uselpsfororders", "U", true, "allow lp users to place orders during setup") perfTestCmd.Flags().BoolVarP(&opts.BatchOnly, "batchonly", "B", false, "all transactions are sent in batches") + perfTestCmd.Flags().BoolVarP(&opts.SpotMarkets, "spotmarkets", "P", false, "use spot markets") perfTestCmd.MarkFlagRequired("address") perfTestCmd.MarkFlagRequired("wallet") perfTestCmd.MarkFlagRequired("faucet") diff --git a/perftest/perftest.go b/perftest/perftest.go index 5f9be79..7300801 100644 --- a/perftest/perftest.go +++ b/perftest/perftest.go @@ -45,6 +45,7 @@ type Opts struct { DoNotInitialise bool UseLPsForOrders bool BatchOnly bool + SpotMarkets bool } type perfLoadTesting struct { @@ -125,6 +126,20 @@ func (p *perfLoadTesting) depositTokens(assets map[string]string, opts Opts) err } } + // If we are using spot markets we need to top up both assets + if opts.SpotMarkets { + asset := assets["fBTC"] + for _, user := range p.users { + for t := 0; t < 50; t++ { + err := topUpAsset(opts.FaucetURL, user.pubKey, asset, 1000000) + if err != nil { + return err + } + time.Sleep(time.Millisecond * 5) + } + } + } + // If the first user has no tokens, top everyone up // quickly without checking if they need it asset := assets["fUSDC"] @@ -260,9 +275,16 @@ func (p *perfLoadTesting) proposeAndEnactMarket(opts Opts) ([]string, error) { if len(markets) == 0 { for i := 0; i < opts.MarketCount; i++ { - err := p.wallet.NewMarket(i, p.users[0]) - if err != nil { - return nil, err + if opts.SpotMarkets { + err := p.wallet.NewSpotMarket(i, p.users[0]) + if err != nil { + return nil, err + } + } else { + err := p.wallet.NewMarket(i, p.users[0]) + if err != nil { + return nil, err + } } propID, err := p.dataNode.getPendingProposalID(20) if err != nil { @@ -292,25 +314,25 @@ func (p *perfLoadTesting) proposeAndEnactMarket(opts Opts) ([]string, error) { if market.State != proto.Market_STATE_ACTIVE { p.wallet.SendOrder(p.users[0], &commandspb.OrderSubmission{MarketId: market.Id, Price: fmt.Sprint(opts.StartingMidPrice + 100), - Size: 100, + Size: 5, Side: proto.Side_SIDE_SELL, Type: proto.Order_TYPE_LIMIT, TimeInForce: proto.Order_TIME_IN_FORCE_GTC}) p.wallet.SendOrder(p.users[1], &commandspb.OrderSubmission{MarketId: market.Id, Price: fmt.Sprint(opts.StartingMidPrice - 100), - Size: 100, + Size: 5, Side: proto.Side_SIDE_BUY, Type: proto.Order_TYPE_LIMIT, TimeInForce: proto.Order_TIME_IN_FORCE_GTC}) p.wallet.SendOrder(p.users[0], &commandspb.OrderSubmission{MarketId: market.Id, Price: fmt.Sprint(opts.StartingMidPrice), - Size: 5, + Size: 1, Side: proto.Side_SIDE_BUY, Type: proto.Order_TYPE_LIMIT, TimeInForce: proto.Order_TIME_IN_FORCE_GTC}) p.wallet.SendOrder(p.users[1], &commandspb.OrderSubmission{MarketId: market.Id, Price: fmt.Sprint(opts.StartingMidPrice), - Size: 5, + Size: 1, Side: proto.Side_SIDE_SELL, Type: proto.Order_TYPE_LIMIT, TimeInForce: proto.Order_TIME_IN_FORCE_GTC}) @@ -496,21 +518,34 @@ func (p *perfLoadTesting) sendSLAOrders(marketID string, deleteFirst bool, opts } // Send new ones - commitmentAmount := uint64(1000000000.0 * p.stakeScale) - orderSize := (commitmentAmount / uint64(opts.StartingMidPrice) * 2) + var ( + commitmentAmount uint64 + orderSizeBuy uint64 + orderSizeSell uint64 + ) + // Spot markets scale order size depending on the side of the book the orders are placed. + if opts.SpotMarkets { + commitmentAmount = uint64(10000000.0 * p.stakeScale) + orderSizeBuy = (commitmentAmount / uint64(opts.StartingMidPrice) * 2) + orderSizeSell = (commitmentAmount / uint64(opts.StartingMidPrice) * 2) / 10 + } else { + commitmentAmount = uint64(1000000000.0 * p.stakeScale) + orderSizeBuy = (commitmentAmount / uint64(opts.StartingMidPrice) * 2) + orderSizeSell = (commitmentAmount / uint64(opts.StartingMidPrice) * 2) + } for p := 0; p < opts.SLAPriceLevels; p++ { // Send in an order for both buy and sell side to cover the commitment // Orders go before the commitment otherwise we can be punished for not having the orders on in time batch.orders = append(batch.orders, &commandspb.OrderSubmission{MarketId: marketID, Price: fmt.Sprint(opts.StartingMidPrice + int64(opts.PriceLevels+1+p)), - Size: orderSize / uint64(opts.SLAPriceLevels), + Size: orderSizeSell / uint64(opts.SLAPriceLevels), Side: proto.Side_SIDE_SELL, Type: proto.Order_TYPE_LIMIT, TimeInForce: proto.Order_TIME_IN_FORCE_GTC}) batch.orders = append(batch.orders, &commandspb.OrderSubmission{MarketId: marketID, Price: fmt.Sprint(opts.StartingMidPrice - int64(opts.PriceLevels+1+p)), - Size: orderSize / uint64(opts.SLAPriceLevels), + Size: orderSizeBuy / uint64(opts.SLAPriceLevels), Side: proto.Side_SIDE_BUY, Type: proto.Order_TYPE_LIMIT, TimeInForce: proto.Order_TIME_IN_FORCE_GTC}) diff --git a/perftest/wallet.go b/perftest/wallet.go index 9667103..a519165 100644 --- a/perftest/wallet.go +++ b/perftest/wallet.go @@ -236,6 +236,65 @@ func (w walletWrapper) NewMarket(offset int, user UserDetails) error { return err } +func (w walletWrapper) NewSpotMarket(offset int, user UserDetails) error { + // marketName := fmt.Sprintf("JUN 2023 BTV vs USD future %d", offset) + newMarket := map[string]interface{}{ + "rationale": map[string]interface{}{ + "description": "desc", + "title": "title", + }, + "terms": map[string]interface{}{ + "closingTimestamp": w.SecondsFromNowInSecs(15), + "enactmentTimestamp": w.SecondsFromNowInSecs(30), + "newSpotMarket": map[string]interface{}{ + "changes": map[string]interface{}{ + "tickSize": "1", + "sizeDecimalPlaces": "2", + "priceDecimalPlaces": "2", + "instrument": map[string]interface{}{ + "name": "NAME", + "code": "CODE", + "spot": map[string]interface{}{ + "baseAsset": "fBTC", + "quoteAsset": "fUSDC", + "name": "OURPRODUCT", + }, + }, + "simple": map[string]interface{}{ + "factorLong": "0.15", + "factorShort": "0.25", + "maxMoveUp": "1000000", + "minMoveDown": "-1000000", + "probabilityOfTrading": "0.9", + }, + "slaParams": map[string]interface{}{ + "priceRange": "1", + "commitmentMinTimeFraction": "1.0", + "performanceHysteresisEpochs": 60, + "slaCompetitionFactor": "1.0", + }, + "targetStakeParameters": map[string]interface{}{ + "timeWindow": "10", + "scalingFactor": "5.0", + }, + "priceMonitoringParameters": map[string]interface{}{ + "triggers": []interface{}{ + map[string]interface{}{ + "horizon": "6000000", + "probability": "0.999999999", + "auctionExtension": 1, + }, + }, + }, + }, + }, + }, + } + + _, err := w.sendTransaction(user, "proposalSubmission", newMarket) + return err +} + // GetFirstKey gives us the first public key linked to our wallet func (w walletWrapper) GetFirstKey(longLivedToken string) (string, error) { post, _ := json.Marshal(map[string]interface{}{