code.vegaprotocol.io/vega@v0.79.0/datanode/gateway/graphql/market_resolvers.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 gql
    17  
    18  import (
    19  	"context"
    20  	"errors"
    21  
    22  	"code.vegaprotocol.io/vega/logging"
    23  	v2 "code.vegaprotocol.io/vega/protos/data-node/api/v2"
    24  	"code.vegaprotocol.io/vega/protos/vega"
    25  	types "code.vegaprotocol.io/vega/protos/vega"
    26  )
    27  
    28  type myMarketResolver VegaResolverRoot
    29  
    30  func (r *myMarketResolver) EnableTxReordering(ctx context.Context, obj *types.Market) (bool, error) {
    31  	return obj.EnableTransactionReordering, nil
    32  }
    33  
    34  func (r *myMarketResolver) LiquidityProvisionsConnection(
    35  	ctx context.Context,
    36  	market *types.Market,
    37  	party *string,
    38  	live *bool,
    39  	pagination *v2.Pagination,
    40  ) (*v2.LiquidityProvisionsConnection, error) {
    41  	var pid string
    42  	if party != nil {
    43  		pid = *party
    44  	}
    45  
    46  	var marketID string
    47  	if market != nil {
    48  		marketID = market.Id
    49  	}
    50  
    51  	var l bool
    52  	if live != nil {
    53  		l = *live
    54  	}
    55  
    56  	req := v2.ListLiquidityProvisionsRequest{
    57  		PartyId:    &pid,
    58  		MarketId:   &marketID,
    59  		Live:       &l,
    60  		Pagination: pagination,
    61  	}
    62  
    63  	res, err := r.tradingDataClientV2.ListLiquidityProvisions(ctx, &req)
    64  	if err != nil {
    65  		r.log.Error("tradingData client", logging.Error(err))
    66  		return nil, err
    67  	}
    68  
    69  	return res.LiquidityProvisions, nil
    70  }
    71  
    72  func (r *myMarketResolver) LiquidityProvisions(ctx context.Context, market *vega.Market, party *string, live *bool, pagination *v2.Pagination) (
    73  	*v2.LiquidityProvisionsWithPendingConnection, error,
    74  ) {
    75  	var pid string
    76  	if party != nil {
    77  		pid = *party
    78  	}
    79  
    80  	var marketID string
    81  	if market != nil {
    82  		marketID = market.Id
    83  	}
    84  
    85  	var l bool
    86  	if live != nil {
    87  		l = *live
    88  	}
    89  
    90  	req := v2.ListAllLiquidityProvisionsRequest{
    91  		PartyId:    &pid,
    92  		MarketId:   &marketID,
    93  		Live:       &l,
    94  		Pagination: pagination,
    95  	}
    96  
    97  	res, err := r.tradingDataClientV2.ListAllLiquidityProvisions(ctx, &req)
    98  	if err != nil {
    99  		r.log.Error("tradingData client", logging.Error(err))
   100  		return nil, err
   101  	}
   102  
   103  	return res.LiquidityProvisions, nil
   104  }
   105  
   106  func (r *myMarketResolver) Data(ctx context.Context, market *types.Market) (*types.MarketData, error) {
   107  	req := v2.GetLatestMarketDataRequest{
   108  		MarketId: market.Id,
   109  	}
   110  	res, err := r.tradingDataClientV2.GetLatestMarketData(ctx, &req)
   111  	if err != nil {
   112  		r.log.Error("tradingData client", logging.Error(err))
   113  		return nil, err
   114  	}
   115  	return res.MarketData, nil
   116  }
   117  
   118  func (r *myMarketResolver) OrdersConnection(
   119  	ctx context.Context,
   120  	market *types.Market,
   121  	pagination *v2.Pagination,
   122  	filter *OrderByPartyIdsFilter,
   123  ) (*v2.OrderConnection, error) {
   124  	req := v2.ListOrdersRequest{
   125  		Pagination: pagination,
   126  		Filter: &v2.OrderFilter{
   127  			MarketIds: []string{market.Id},
   128  		},
   129  	}
   130  
   131  	if filter != nil {
   132  		req.Filter.PartyIds = filter.PartyIds
   133  		if filter.Order != nil {
   134  			req.Filter.Statuses = filter.Order.Statuses
   135  			req.Filter.Types = filter.Order.Types
   136  			req.Filter.TimeInForces = filter.Order.TimeInForces
   137  			req.Filter.ExcludeLiquidity = filter.Order.ExcludeLiquidity
   138  			req.Filter.Reference = filter.Order.Reference
   139  			req.Filter.DateRange = filter.Order.DateRange
   140  			req.Filter.LiveOnly = filter.Order.LiveOnly
   141  		}
   142  	}
   143  
   144  	res, err := r.tradingDataClientV2.ListOrders(ctx, &req)
   145  	if err != nil {
   146  		r.log.Error("tradingData client", logging.Error(err))
   147  		return nil, err
   148  	}
   149  
   150  	return res.Orders, nil
   151  }
   152  
   153  func (r *myMarketResolver) TradesConnection(ctx context.Context, market *types.Market, dateRange *v2.DateRange, pagination *v2.Pagination) (*v2.TradeConnection, error) {
   154  	req := v2.ListTradesRequest{
   155  		MarketIds:  []string{market.Id},
   156  		Pagination: pagination,
   157  		DateRange:  dateRange,
   158  	}
   159  	res, err := r.tradingDataClientV2.ListTrades(ctx, &req)
   160  	if err != nil {
   161  		r.log.Error("tradingData client", logging.Error(err))
   162  		return nil, err
   163  	}
   164  	return res.Trades, nil
   165  }
   166  
   167  func (r *myMarketResolver) Depth(ctx context.Context, market *types.Market, maxDepth *int) (*types.MarketDepth, error) {
   168  	if market == nil {
   169  		return nil, errors.New("market missing or empty")
   170  	}
   171  
   172  	req := v2.GetLatestMarketDepthRequest{MarketId: market.Id}
   173  	if maxDepth != nil {
   174  		if *maxDepth <= 0 {
   175  			return nil, errors.New("invalid maxDepth, must be a positive number")
   176  		}
   177  		reqDepth := uint64(*maxDepth)
   178  		req.MaxDepth = &reqDepth
   179  	}
   180  
   181  	// Look for market depth for the given market (will validate market internally)
   182  	// Note: Market depth is also known as OrderBook depth within the matching-engine
   183  	res, err := r.tradingDataClientV2.GetLatestMarketDepth(ctx, &req)
   184  	if err != nil {
   185  		r.log.Error("trading data client", logging.Error(err))
   186  		return nil, err
   187  	}
   188  
   189  	return &types.MarketDepth{
   190  		MarketId:       res.MarketId,
   191  		Buy:            res.Buy,
   192  		Sell:           res.Sell,
   193  		SequenceNumber: res.SequenceNumber,
   194  	}, nil
   195  }
   196  
   197  func (r *myMarketResolver) AccountsConnection(ctx context.Context, market *types.Market, partyID *string, pagination *v2.Pagination, includeDerivedParties *bool) (*v2.AccountsConnection, error) {
   198  	filter := v2.AccountFilter{MarketIds: []string{market.Id}}
   199  	ptyID := ""
   200  
   201  	if partyID != nil {
   202  		// get margin account for a party
   203  		ptyID = *partyID
   204  		filter.PartyIds = []string{ptyID}
   205  		filter.AccountTypes = []types.AccountType{types.AccountType_ACCOUNT_TYPE_MARGIN}
   206  	} else {
   207  		filter.AccountTypes = []types.AccountType{
   208  			types.AccountType_ACCOUNT_TYPE_INSURANCE,
   209  			types.AccountType_ACCOUNT_TYPE_FEES_LIQUIDITY,
   210  		}
   211  	}
   212  
   213  	req := v2.ListAccountsRequest{Filter: &filter, Pagination: pagination, IncludeDerivedParties: includeDerivedParties}
   214  
   215  	res, err := r.tradingDataClientV2.ListAccounts(ctx, &req)
   216  	if err != nil {
   217  		r.log.Error("unable to get market accounts",
   218  			logging.Error(err),
   219  			logging.String("market-id", market.Id),
   220  			logging.String("party-id", ptyID))
   221  		return nil, err
   222  	}
   223  	return res.Accounts, nil
   224  }
   225  
   226  func (r *myMarketResolver) DecimalPlaces(_ context.Context, obj *types.Market) (int, error) {
   227  	return int(obj.DecimalPlaces), nil
   228  }
   229  
   230  func (r *myMarketResolver) PositionDecimalPlaces(_ context.Context, obj *types.Market) (int, error) {
   231  	return int(obj.PositionDecimalPlaces), nil
   232  }
   233  
   234  func (r *myMarketResolver) OpeningAuction(_ context.Context, obj *types.Market) (*AuctionDuration, error) {
   235  	return &AuctionDuration{
   236  		DurationSecs: int(obj.OpeningAuction.Duration),
   237  		Volume:       int(obj.OpeningAuction.Volume),
   238  	}, nil
   239  }
   240  
   241  func (r *myMarketResolver) PriceMonitoringSettings(_ context.Context, obj *types.Market) (*PriceMonitoringSettings, error) {
   242  	return PriceMonitoringSettingsFromProto(obj.PriceMonitoringSettings)
   243  }
   244  
   245  func (r *myMarketResolver) LiquidityMonitoringParameters(_ context.Context, obj *types.Market) (*LiquidityMonitoringParameters, error) {
   246  	return &LiquidityMonitoringParameters{
   247  		TargetStakeParameters: &TargetStakeParameters{
   248  			TimeWindow:    int(obj.LiquidityMonitoringParameters.TargetStakeParameters.TimeWindow),
   249  			ScalingFactor: obj.LiquidityMonitoringParameters.TargetStakeParameters.ScalingFactor,
   250  		},
   251  	}, nil
   252  }
   253  
   254  func (r *myMarketResolver) MarketProposal(ctx context.Context, obj *types.Market) (ProposalNode, error) {
   255  	resp, err := r.tradingDataClientV2.GetGovernanceData(ctx, &v2.GetGovernanceDataRequest{
   256  		ProposalId: &obj.Id,
   257  	})
   258  	// it's possible to not find a proposal as of now.
   259  	// some market are loaded at startup, without
   260  	// going through the proposal phase
   261  	if err != nil {
   262  		return nil, nil //nolint:nilerr
   263  	}
   264  
   265  	resolver := (*proposalEdgeResolver)(r)
   266  	if resp.GetData().ProposalType == vega.GovernanceData_TYPE_BATCH {
   267  		return resolver.BatchProposal(ctx, resp.GetData())
   268  	}
   269  
   270  	return resp.Data, nil
   271  }
   272  
   273  func (r *myMarketResolver) Proposal(ctx context.Context, obj *types.Market) (*vega.GovernanceData, error) {
   274  	resp, err := r.tradingDataClientV2.GetGovernanceData(ctx, &v2.GetGovernanceDataRequest{
   275  		ProposalId: &obj.Id,
   276  	})
   277  	// it's possible to not find a proposal as of now.
   278  	// some market are loaded at startup, without
   279  	// going through the proposal phase
   280  	if err != nil {
   281  		return nil, nil //nolint:nilerr
   282  	}
   283  
   284  	return resp.Data, nil
   285  }
   286  
   287  func (r *myMarketResolver) RiskFactors(ctx context.Context, obj *types.Market) (*types.RiskFactor, error) {
   288  	rf, err := r.tradingDataClientV2.GetRiskFactors(ctx, &v2.GetRiskFactorsRequest{
   289  		MarketId: obj.Id,
   290  	})
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  
   295  	return rf.RiskFactor, nil
   296  }
   297  
   298  func (r *myMarketResolver) CandlesConnection(ctx context.Context, market *types.Market, sinceRaw string, toRaw *string,
   299  	interval vega.Interval, pagination *v2.Pagination,
   300  ) (*v2.CandleDataConnection, error) {
   301  	return handleCandleConnectionRequest(ctx, r.tradingDataClientV2, market, sinceRaw, toRaw, interval, pagination)
   302  }
   303  
   304  func (r *myMarketResolver) LiquiditySLAParameters(ctx context.Context, obj *types.Market) (*types.LiquiditySLAParameters, error) {
   305  	return obj.LiquiditySlaParams, nil
   306  }
   307  
   308  func (r *myMarketResolver) AllowedEmptyAMMLevels(ctx context.Context, obj *types.Market) (int, error) {
   309  	return int(obj.AllowedEmptyAmmLevels), nil
   310  }