pyaver.orderbook
1from solana.publickey import PublicKey 2from .enums import Side 3from .utils import load_bytes_data, load_multiple_bytes_data 4from .data_classes import Price, SlabOrder 5from .slab import Slab 6from solana.rpc.async_api import AsyncClient 7 8 9class Orderbook: 10 """ 11 Orderbook object 12 13 Contains information on open orders on both the bids and asks of a particular outcome in a market 14 """ 15 16 pubkey: PublicKey 17 """ 18 Orderbook public key 19 """ 20 slab_bids: Slab 21 """ 22 Slab object for bids 23 """ 24 slab_asks: Slab 25 """ 26 Slab object for asks 27 """ 28 slab_bids_pubkey: PublicKey 29 """ 30 Public key of the account containing the bids 31 """ 32 slab_asks_pubkey: PublicKey 33 """ 34 Public key of the account containing the asks 35 """ 36 decimals: int 37 """ 38 Decimal precision for orderbook 39 """ 40 is_inverted: bool 41 """ 42 Whether the bids and asks should be interpretted as inverted when parsing the data. (Used in the case of the second outcome in a two-outcome market.) 43 """ 44 45 def __init__( 46 self, 47 pubkey: PublicKey, 48 slab_bids: Slab, 49 slab_asks: Slab, 50 slab_bids_pubkey: PublicKey, 51 slab_asks_pubkey: PublicKey, 52 decimals: int, 53 is_inverted: bool = False 54 ): 55 """ 56 Initialise an Orderbook object. Do not use this function; use Orderbook.load() instead 57 58 Args: 59 pubkey (PublicKey): Orderbook public key 60 slab_bids (Slab): Slab object for bids 61 slab_asks (Slab): Slab object for asks 62 slab_bids_pubkey (PublicKey): Slab bids public key 63 slab_asks_pubkey (PublicKey): Slab asks public key 64 decimals (int): Decimal precision for orderbook 65 is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False. 66 """ 67 self.decimals = decimals 68 self.pubkey = pubkey 69 self.slab_bids = slab_bids 70 self.slab_asks = slab_asks 71 self.slab_bids_pubkey = slab_bids_pubkey 72 self.slab_asks_pubkey = slab_asks_pubkey 73 self.is_inverted = is_inverted 74 75 @staticmethod 76 async def load( 77 conn: AsyncClient, 78 slab_bids_pubkey: PublicKey, 79 slab_asks_pubkey: PublicKey, 80 orderbook_pubkey: PublicKey, 81 decimals: int, 82 is_inverted: bool = False 83 ): 84 """ 85 Initialise an Orderbook object 86 87 Parameters are found in MarketStoreStates' --> OrderbookAccounts 88 89 Args: 90 conn (AsyncClient): Solana AsyncClient object 91 slab_bids_pubkey (PublicKey): Slab bids public key 92 slab_asks_pubkey (PublicKey): Slab asks public key 93 orderbook_pubkey (PublicKey): Orderbook public key 94 decimals (int): Decimal precision for orderbook 95 is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False. 96 97 Returns: 98 Orderbook: Orderbook object 99 """ 100 101 slab_bids = await Orderbook.load_slab(conn, slab_bids_pubkey) 102 slab_asks = await Orderbook.load_slab(conn, slab_asks_pubkey) 103 104 return Orderbook( 105 pubkey=orderbook_pubkey, 106 slab_bids=slab_bids, 107 slab_asks=slab_asks, 108 slab_asks_pubkey=slab_asks_pubkey, 109 slab_bids_pubkey=slab_bids_pubkey, 110 decimals=decimals, 111 is_inverted=is_inverted 112 ) 113 114 @staticmethod 115 async def load_slab(conn: AsyncClient, slab_address: PublicKey): 116 """ 117 Loads onchain data for a Slab (contains orders for a particular side of the orderbook) 118 119 Args: 120 conn (AsyncClient): Solana AsyncClient object 121 slab_address (PublicKey): Slab public key 122 123 Returns: 124 Slab: Slab object 125 """ 126 data = await load_bytes_data(conn, slab_address) 127 return Slab.from_bytes(data) 128 129 @staticmethod 130 async def load_multiple_slabs(conn: AsyncClient, slab_addresses: list[PublicKey]): 131 """ 132 Loads onchain data for multiple Slabs (contains orders for a particular side of the orderbook) 133 134 Args: 135 conn (AsyncClient): Solana AsyncClient object 136 slab_addresses (list[PublicKey]): List of slab public keys 137 138 Returns: 139 list[Slab]: List of Slab objects 140 """ 141 data = await load_multiple_bytes_data(conn, slab_addresses) 142 slabs = [] 143 for d in data: 144 slabs.append(Slab.from_bytes(d)) 145 return slabs 146 147 def invert(self): 148 """ 149 Returns a version of the orderbook which has been parsed with bids and asks swtiched and 150 prices inverted. (Used for the second outcome in a two-outcome market) 151 152 Returns: 153 Orderbook: Orderbook object 154 """ 155 return Orderbook( 156 self.pubkey, 157 self.slab_asks, 158 self.slab_bids, 159 self.slab_asks_pubkey, 160 self.slab_bids_pubkey, 161 self.decimals, 162 True 163 ) 164 165 166 @staticmethod 167 def convert_price(p: Price, decimals: int): 168 """ 169 Converts price to correct order of magnitude based on decimal precision 170 171 Args: 172 p (Price): Unconverted Price object 173 decimals (int): Decimal precision for orderbook 174 175 Returns: 176 Price: Price object 177 """ 178 exp = 10 ** decimals 179 return Price( 180 price=p.price / exp, 181 #price=round((p.price / 2 ** 32) * exp) / exp, 182 size=p.size / exp 183 ) 184 185 @staticmethod 186 def get_L2_for_slab( 187 slab: Slab, 188 depth: int, 189 increasing : bool, 190 decimals: int, 191 ui_amount=False, 192 is_inverted=False 193 ): 194 """ 195 Get Level 2 market information for a particular slab 196 197 This contains information on orders on the slab aggregated by price tick. 198 199 Args: 200 slab (Slab): Slab object 201 depth (int): Number of orders to return 202 increasing (bool): Sort orders increasing 203 decimals (int): Decimal precision for orderbook 204 ui_amount (bool, optional): Converts prices based on decimal precision if true. Defaults to False. 205 is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False. 206 207 Returns: 208 list[Price]: List of Price objects (size and price) corresponding to orders on the slab 209 """ 210 211 l2_depth = Orderbook.__get_L2(slab, depth, decimals, increasing) 212 if(ui_amount): 213 l2_depth = [Orderbook.convert_price(p, decimals) for p in l2_depth] 214 215 if(is_inverted): 216 l2_depth = [Orderbook.invert_price(p) for p in l2_depth] 217 218 return l2_depth 219 220 @staticmethod 221 def __get_L2(slab: Slab, depth: int, decimals: int, increasing: bool): 222 """Get the Level 2 market information.""" 223 # The first element of the inner list is price, the second is quantity. 224 levels: list[list[int]] = [] 225 for node in slab.items(descending=not increasing): 226 price = Orderbook.__get_price_from_slab(node, decimals) 227 if len(levels) > 0 and levels[len(levels) - 1][0] == price: 228 levels[len(levels) - 1][1] += node.base_quantity 229 elif len(levels) == depth: 230 break 231 else: 232 levels.append([price, node.base_quantity]) 233 return [ 234 Price( 235 price=price_lots, 236 size=size_lots 237 ) 238 for price_lots, size_lots in levels 239 ] 240 241 @staticmethod 242 def __get_L3(slab: Slab, decimals: int, increasing: bool, is_inverted: bool): 243 """Get the Level 1 market information.""" 244 # The first element of the inner list is price, the second is quantity. 245 orders: list[SlabOrder] = [] 246 for node in slab.items(descending = not increasing): 247 orders += [SlabOrder( 248 id = node.key, 249 price = (10**decimals) - Orderbook.__get_price_from_slab(node, decimals) if is_inverted else Orderbook.__get_price_from_slab(node, decimals), 250 price_ui = 1 - Orderbook.__get_price_from_slab(node, decimals) * (10**-decimals) if is_inverted else Orderbook.__get_price_from_slab(node, decimals) * (10**-decimals), 251 base_quantity = node.base_quantity, 252 base_quantity_ui = node.base_quantity * (10**-decimals), 253 user_market = node.user_market, 254 fee_tier = node.fee_tier, 255 )] 256 257 return orders 258 259 @staticmethod 260 def __get_price_from_slab(node, decimals: int): 261 return float(round( ((node.key >> 64)/(2**32)) * 10**decimals)) 262 263 @staticmethod 264 def invert_price(p: Price): 265 """ 266 Inverts prices 267 268 This is used when inverting the second outcome in a two-outcome market. 269 270 When switching prices between bids and asks, the price is `1-p`. 271 272 Example, a BUY on A at a (probability) price of 0.4 is equivelant to a SELL on B at a price of 0.6 (1-0.4) and vice versa. 273 274 Args: 275 p (Price): Price object 276 277 Returns: 278 Price: Price object 279 """ 280 return Price( 281 price=1-p.price, 282 size=p.size 283 ) 284 285 def get_bids_L3(self): 286 """ 287 Gets level 1 market information for bids. 288 289 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 290 291 Returns: 292 list[SlabOrder]: List of slab orders for bids 293 """ 294 is_increasing = False 295 if(self.is_inverted): 296 is_increasing = True 297 298 return Orderbook.__get_L3( 299 self.slab_bids, 300 self.decimals, 301 is_increasing, 302 self.is_inverted 303 ) 304 305 def get_asks_L3(self): 306 """ 307 Gets level 1 market information for asks 308 309 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 310 311 Returns: 312 list[SlabOrder]: List of slab orders for asks 313 """ 314 is_increasing = True 315 if(self.is_inverted): 316 is_increasing = False 317 318 return Orderbook.__get_L3( 319 self.slab_asks, 320 self.decimals, 321 is_increasing, 322 self.is_inverted 323 ) 324 325 326 def get_bids_l2(self, depth: int, ui_amount: bool): 327 """ 328 Gets level 1 market information for bids 329 330 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 331 332 Args: 333 depth (int): Number of orders to return 334 ui_amount (bool): Converts prices based on decimal precision if true. 335 336 Returns: 337 list[Price]: List of Price objects (size and price) corresponding to orders on the slab 338 """ 339 is_increasing = False 340 if(self.is_inverted): 341 is_increasing = True 342 343 return Orderbook.get_L2_for_slab( 344 self.slab_bids, 345 depth, 346 is_increasing, 347 self.decimals, 348 ui_amount, 349 self.is_inverted, 350 ) 351 352 def get_asks_l2(self, depth: int, ui_amount: bool): 353 """ 354 Gets level 1 market information for asks 355 356 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 357 358 Args: 359 depth (int): Number of orders to return 360 ui_amount (bool): Converts prices based on decimal precision if true. 361 362 Returns: 363 list[Price]: List of Price objects (size and probability price) corresponding to orders on the slab 364 """ 365 is_increasing = True 366 if(self.is_inverted): 367 is_increasing = False 368 369 return Orderbook.get_L2_for_slab( 370 self.slab_asks, 371 depth, 372 is_increasing, 373 self.decimals, 374 ui_amount, 375 self.is_inverted, 376 ) 377 378 def get_best_bid_price(self, ui_amount: bool): 379 """ 380 Gets the best bid price 381 382 Args: 383 ui_amount (bool): Converts prices based on decimal precision if true. 384 385 Returns: 386 Price: Price object (size and price) 387 """ 388 bids = self.get_bids_l2(1, ui_amount) 389 if(bids is not None and len(bids) > 0): 390 return bids[0] 391 return None 392 393 def get_best_ask_price(self, ui_amount: bool): 394 """ 395 Gets the best ask price 396 397 Args: 398 ui_amount (bool): Converts prices based on decimal precision if true. 399 400 Returns: 401 Price: Price object (size and price) 402 """ 403 asks = self.get_asks_l2(1, ui_amount) 404 if(asks is not None and len(asks) > 0): 405 return asks[0] 406 return None 407 408 def get_bid_price_by_order_id(self, order_id: int): 409 """ 410 Gets bid Price object by order_id 411 412 Args: 413 order_id (int): Order ID 414 415 Returns: 416 Price: Price object (size and price) 417 """ 418 bid = self.slab_bids.get(order_id) 419 if(bid is None): 420 return None 421 422 bid_price = Price(price=bid.key >> 64, size=bid.base_quantity) 423 bid_price = Orderbook.convert_price(bid_price, self.decimals) 424 425 if(self.is_inverted): 426 bid_price = Orderbook.invert_price(bid_price) 427 428 return bid_price 429 430 def get_ask_price_by_order_id(self, order_id: int): 431 """ 432 Gets ask Price object by order_id 433 434 Args: 435 order_id (int): Order ID 436 437 Returns: 438 Price: Price object (size and price) 439 """ 440 ask = self.slab_asks.get(order_id) 441 if(ask is None): 442 return None 443 444 ask_price = Price(price=ask.key >> 64, size=ask.base_quantity) 445 ask_price = Orderbook.convert_price(ask_price, self.decimals) 446 447 if(self.is_inverted): 448 ask_price = Orderbook.invert_price(ask_price) 449 450 return ask_price 451 452 def estimate_avg_fill_for_base_qty(self, base_qty: int, side: Side, ui_amount: bool): 453 """ 454 Gets estimate of average fill price (probability format) given a base/payout quantity 455 456 Args: 457 base_qty (int): Base quantity 458 side (Side): Side object (bid or ask) 459 ui_amount (bool): Converts prices based on decimal precision if true. 460 461 Returns: 462 dict[str, float]: Dictionary containing `avg_price`, `worst_price`, `filled` 463 """ 464 return self.__estimate_fill_for_qty(base_qty, side, False, ui_amount) 465 466 def estimate_avg_fill_for_quote_qty(self, quote_qty: int, side: Side, ui_amount: bool): 467 """ 468 Gets estimate of average fill price (probability format) given a stake/quote quantity 469 470 Args: 471 quote_qty (int): Base quantity 472 side (Side): Side object (bid or ask) 473 ui_amount (bool): Converts prices based on decimal precision if true. 474 475 Returns: 476 dict[str, float]: Dictionary containing `avg_price`, `worst_price`, `filled` 477 """ 478 return self.__estimate_fill_for_qty(quote_qty, side, True, ui_amount) 479 480 def __estimate_fill_for_qty(self, qty: int, side: Side, quote: bool, ui_amount: bool): 481 """ 482 _summary_ 483 484 Args: 485 qty (int): Quanity 486 side (Side): Side object (bid or ask) 487 quote (bool): Quote quantity if true. Base quantity if false. 488 ui_amount (bool): Converts prices based on decimal precision if true. 489 490 Returns: 491 dict[str, float]: Dictionary containing `avg_price`, `worst_price`, `filled` 492 """ 493 if(side == Side.BUY): 494 prices = self.get_bids_l2(100, ui_amount) 495 elif(side == Side.SELL): 496 prices = self.get_asks_l2(100, ui_amount) 497 498 if(quote): 499 accumulator = lambda p: p.size 500 else: 501 accumulator = lambda p: p.size * p.price 502 503 new_prices: list[Price] = [] 504 cumulative_qty = 0 505 for price in prices: 506 remaining_qty = qty - cumulative_qty 507 if(remaining_qty <= accumulator(price)): 508 cumulative_qty += remaining_qty 509 new_size = remaining_qty if quote else remaining_qty/price.price 510 new_prices.append(Price(price=price.price, size=new_size)) 511 break 512 else: 513 cumulative_qty += accumulator(price) 514 new_prices.append(price) 515 516 return { 517 'avg_price': Orderbook.weighted_average( 518 nums=[p.price for p in new_prices], 519 weights=[p.size for p in new_prices] 520 ), 521 'worst_price': new_prices[-1].price, 522 'filled': cumulative_qty 523 } 524 525 @staticmethod 526 def weighted_average(nums, weights): 527 """ 528 Calculates weighted average 529 530 Args: 531 nums (list[float]): List of values 532 weights (list[float]): List of weights 533 534 Returns: 535 float: Weighted average 536 """ 537 sum = 0 538 weight_sum = 0 539 540 assert len(nums) == len(weights), 'Number of weights and nums do not correspond' 541 542 for i, num in enumerate(nums): 543 weight = weights[i] 544 sum += num * weight 545 weight_sum += weight 546 547 return sum / weight_sum
10class Orderbook: 11 """ 12 Orderbook object 13 14 Contains information on open orders on both the bids and asks of a particular outcome in a market 15 """ 16 17 pubkey: PublicKey 18 """ 19 Orderbook public key 20 """ 21 slab_bids: Slab 22 """ 23 Slab object for bids 24 """ 25 slab_asks: Slab 26 """ 27 Slab object for asks 28 """ 29 slab_bids_pubkey: PublicKey 30 """ 31 Public key of the account containing the bids 32 """ 33 slab_asks_pubkey: PublicKey 34 """ 35 Public key of the account containing the asks 36 """ 37 decimals: int 38 """ 39 Decimal precision for orderbook 40 """ 41 is_inverted: bool 42 """ 43 Whether the bids and asks should be interpretted as inverted when parsing the data. (Used in the case of the second outcome in a two-outcome market.) 44 """ 45 46 def __init__( 47 self, 48 pubkey: PublicKey, 49 slab_bids: Slab, 50 slab_asks: Slab, 51 slab_bids_pubkey: PublicKey, 52 slab_asks_pubkey: PublicKey, 53 decimals: int, 54 is_inverted: bool = False 55 ): 56 """ 57 Initialise an Orderbook object. Do not use this function; use Orderbook.load() instead 58 59 Args: 60 pubkey (PublicKey): Orderbook public key 61 slab_bids (Slab): Slab object for bids 62 slab_asks (Slab): Slab object for asks 63 slab_bids_pubkey (PublicKey): Slab bids public key 64 slab_asks_pubkey (PublicKey): Slab asks public key 65 decimals (int): Decimal precision for orderbook 66 is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False. 67 """ 68 self.decimals = decimals 69 self.pubkey = pubkey 70 self.slab_bids = slab_bids 71 self.slab_asks = slab_asks 72 self.slab_bids_pubkey = slab_bids_pubkey 73 self.slab_asks_pubkey = slab_asks_pubkey 74 self.is_inverted = is_inverted 75 76 @staticmethod 77 async def load( 78 conn: AsyncClient, 79 slab_bids_pubkey: PublicKey, 80 slab_asks_pubkey: PublicKey, 81 orderbook_pubkey: PublicKey, 82 decimals: int, 83 is_inverted: bool = False 84 ): 85 """ 86 Initialise an Orderbook object 87 88 Parameters are found in MarketStoreStates' --> OrderbookAccounts 89 90 Args: 91 conn (AsyncClient): Solana AsyncClient object 92 slab_bids_pubkey (PublicKey): Slab bids public key 93 slab_asks_pubkey (PublicKey): Slab asks public key 94 orderbook_pubkey (PublicKey): Orderbook public key 95 decimals (int): Decimal precision for orderbook 96 is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False. 97 98 Returns: 99 Orderbook: Orderbook object 100 """ 101 102 slab_bids = await Orderbook.load_slab(conn, slab_bids_pubkey) 103 slab_asks = await Orderbook.load_slab(conn, slab_asks_pubkey) 104 105 return Orderbook( 106 pubkey=orderbook_pubkey, 107 slab_bids=slab_bids, 108 slab_asks=slab_asks, 109 slab_asks_pubkey=slab_asks_pubkey, 110 slab_bids_pubkey=slab_bids_pubkey, 111 decimals=decimals, 112 is_inverted=is_inverted 113 ) 114 115 @staticmethod 116 async def load_slab(conn: AsyncClient, slab_address: PublicKey): 117 """ 118 Loads onchain data for a Slab (contains orders for a particular side of the orderbook) 119 120 Args: 121 conn (AsyncClient): Solana AsyncClient object 122 slab_address (PublicKey): Slab public key 123 124 Returns: 125 Slab: Slab object 126 """ 127 data = await load_bytes_data(conn, slab_address) 128 return Slab.from_bytes(data) 129 130 @staticmethod 131 async def load_multiple_slabs(conn: AsyncClient, slab_addresses: list[PublicKey]): 132 """ 133 Loads onchain data for multiple Slabs (contains orders for a particular side of the orderbook) 134 135 Args: 136 conn (AsyncClient): Solana AsyncClient object 137 slab_addresses (list[PublicKey]): List of slab public keys 138 139 Returns: 140 list[Slab]: List of Slab objects 141 """ 142 data = await load_multiple_bytes_data(conn, slab_addresses) 143 slabs = [] 144 for d in data: 145 slabs.append(Slab.from_bytes(d)) 146 return slabs 147 148 def invert(self): 149 """ 150 Returns a version of the orderbook which has been parsed with bids and asks swtiched and 151 prices inverted. (Used for the second outcome in a two-outcome market) 152 153 Returns: 154 Orderbook: Orderbook object 155 """ 156 return Orderbook( 157 self.pubkey, 158 self.slab_asks, 159 self.slab_bids, 160 self.slab_asks_pubkey, 161 self.slab_bids_pubkey, 162 self.decimals, 163 True 164 ) 165 166 167 @staticmethod 168 def convert_price(p: Price, decimals: int): 169 """ 170 Converts price to correct order of magnitude based on decimal precision 171 172 Args: 173 p (Price): Unconverted Price object 174 decimals (int): Decimal precision for orderbook 175 176 Returns: 177 Price: Price object 178 """ 179 exp = 10 ** decimals 180 return Price( 181 price=p.price / exp, 182 #price=round((p.price / 2 ** 32) * exp) / exp, 183 size=p.size / exp 184 ) 185 186 @staticmethod 187 def get_L2_for_slab( 188 slab: Slab, 189 depth: int, 190 increasing : bool, 191 decimals: int, 192 ui_amount=False, 193 is_inverted=False 194 ): 195 """ 196 Get Level 2 market information for a particular slab 197 198 This contains information on orders on the slab aggregated by price tick. 199 200 Args: 201 slab (Slab): Slab object 202 depth (int): Number of orders to return 203 increasing (bool): Sort orders increasing 204 decimals (int): Decimal precision for orderbook 205 ui_amount (bool, optional): Converts prices based on decimal precision if true. Defaults to False. 206 is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False. 207 208 Returns: 209 list[Price]: List of Price objects (size and price) corresponding to orders on the slab 210 """ 211 212 l2_depth = Orderbook.__get_L2(slab, depth, decimals, increasing) 213 if(ui_amount): 214 l2_depth = [Orderbook.convert_price(p, decimals) for p in l2_depth] 215 216 if(is_inverted): 217 l2_depth = [Orderbook.invert_price(p) for p in l2_depth] 218 219 return l2_depth 220 221 @staticmethod 222 def __get_L2(slab: Slab, depth: int, decimals: int, increasing: bool): 223 """Get the Level 2 market information.""" 224 # The first element of the inner list is price, the second is quantity. 225 levels: list[list[int]] = [] 226 for node in slab.items(descending=not increasing): 227 price = Orderbook.__get_price_from_slab(node, decimals) 228 if len(levels) > 0 and levels[len(levels) - 1][0] == price: 229 levels[len(levels) - 1][1] += node.base_quantity 230 elif len(levels) == depth: 231 break 232 else: 233 levels.append([price, node.base_quantity]) 234 return [ 235 Price( 236 price=price_lots, 237 size=size_lots 238 ) 239 for price_lots, size_lots in levels 240 ] 241 242 @staticmethod 243 def __get_L3(slab: Slab, decimals: int, increasing: bool, is_inverted: bool): 244 """Get the Level 1 market information.""" 245 # The first element of the inner list is price, the second is quantity. 246 orders: list[SlabOrder] = [] 247 for node in slab.items(descending = not increasing): 248 orders += [SlabOrder( 249 id = node.key, 250 price = (10**decimals) - Orderbook.__get_price_from_slab(node, decimals) if is_inverted else Orderbook.__get_price_from_slab(node, decimals), 251 price_ui = 1 - Orderbook.__get_price_from_slab(node, decimals) * (10**-decimals) if is_inverted else Orderbook.__get_price_from_slab(node, decimals) * (10**-decimals), 252 base_quantity = node.base_quantity, 253 base_quantity_ui = node.base_quantity * (10**-decimals), 254 user_market = node.user_market, 255 fee_tier = node.fee_tier, 256 )] 257 258 return orders 259 260 @staticmethod 261 def __get_price_from_slab(node, decimals: int): 262 return float(round( ((node.key >> 64)/(2**32)) * 10**decimals)) 263 264 @staticmethod 265 def invert_price(p: Price): 266 """ 267 Inverts prices 268 269 This is used when inverting the second outcome in a two-outcome market. 270 271 When switching prices between bids and asks, the price is `1-p`. 272 273 Example, a BUY on A at a (probability) price of 0.4 is equivelant to a SELL on B at a price of 0.6 (1-0.4) and vice versa. 274 275 Args: 276 p (Price): Price object 277 278 Returns: 279 Price: Price object 280 """ 281 return Price( 282 price=1-p.price, 283 size=p.size 284 ) 285 286 def get_bids_L3(self): 287 """ 288 Gets level 1 market information for bids. 289 290 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 291 292 Returns: 293 list[SlabOrder]: List of slab orders for bids 294 """ 295 is_increasing = False 296 if(self.is_inverted): 297 is_increasing = True 298 299 return Orderbook.__get_L3( 300 self.slab_bids, 301 self.decimals, 302 is_increasing, 303 self.is_inverted 304 ) 305 306 def get_asks_L3(self): 307 """ 308 Gets level 1 market information for asks 309 310 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 311 312 Returns: 313 list[SlabOrder]: List of slab orders for asks 314 """ 315 is_increasing = True 316 if(self.is_inverted): 317 is_increasing = False 318 319 return Orderbook.__get_L3( 320 self.slab_asks, 321 self.decimals, 322 is_increasing, 323 self.is_inverted 324 ) 325 326 327 def get_bids_l2(self, depth: int, ui_amount: bool): 328 """ 329 Gets level 1 market information for bids 330 331 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 332 333 Args: 334 depth (int): Number of orders to return 335 ui_amount (bool): Converts prices based on decimal precision if true. 336 337 Returns: 338 list[Price]: List of Price objects (size and price) corresponding to orders on the slab 339 """ 340 is_increasing = False 341 if(self.is_inverted): 342 is_increasing = True 343 344 return Orderbook.get_L2_for_slab( 345 self.slab_bids, 346 depth, 347 is_increasing, 348 self.decimals, 349 ui_amount, 350 self.is_inverted, 351 ) 352 353 def get_asks_l2(self, depth: int, ui_amount: bool): 354 """ 355 Gets level 1 market information for asks 356 357 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 358 359 Args: 360 depth (int): Number of orders to return 361 ui_amount (bool): Converts prices based on decimal precision if true. 362 363 Returns: 364 list[Price]: List of Price objects (size and probability price) corresponding to orders on the slab 365 """ 366 is_increasing = True 367 if(self.is_inverted): 368 is_increasing = False 369 370 return Orderbook.get_L2_for_slab( 371 self.slab_asks, 372 depth, 373 is_increasing, 374 self.decimals, 375 ui_amount, 376 self.is_inverted, 377 ) 378 379 def get_best_bid_price(self, ui_amount: bool): 380 """ 381 Gets the best bid price 382 383 Args: 384 ui_amount (bool): Converts prices based on decimal precision if true. 385 386 Returns: 387 Price: Price object (size and price) 388 """ 389 bids = self.get_bids_l2(1, ui_amount) 390 if(bids is not None and len(bids) > 0): 391 return bids[0] 392 return None 393 394 def get_best_ask_price(self, ui_amount: bool): 395 """ 396 Gets the best ask price 397 398 Args: 399 ui_amount (bool): Converts prices based on decimal precision if true. 400 401 Returns: 402 Price: Price object (size and price) 403 """ 404 asks = self.get_asks_l2(1, ui_amount) 405 if(asks is not None and len(asks) > 0): 406 return asks[0] 407 return None 408 409 def get_bid_price_by_order_id(self, order_id: int): 410 """ 411 Gets bid Price object by order_id 412 413 Args: 414 order_id (int): Order ID 415 416 Returns: 417 Price: Price object (size and price) 418 """ 419 bid = self.slab_bids.get(order_id) 420 if(bid is None): 421 return None 422 423 bid_price = Price(price=bid.key >> 64, size=bid.base_quantity) 424 bid_price = Orderbook.convert_price(bid_price, self.decimals) 425 426 if(self.is_inverted): 427 bid_price = Orderbook.invert_price(bid_price) 428 429 return bid_price 430 431 def get_ask_price_by_order_id(self, order_id: int): 432 """ 433 Gets ask Price object by order_id 434 435 Args: 436 order_id (int): Order ID 437 438 Returns: 439 Price: Price object (size and price) 440 """ 441 ask = self.slab_asks.get(order_id) 442 if(ask is None): 443 return None 444 445 ask_price = Price(price=ask.key >> 64, size=ask.base_quantity) 446 ask_price = Orderbook.convert_price(ask_price, self.decimals) 447 448 if(self.is_inverted): 449 ask_price = Orderbook.invert_price(ask_price) 450 451 return ask_price 452 453 def estimate_avg_fill_for_base_qty(self, base_qty: int, side: Side, ui_amount: bool): 454 """ 455 Gets estimate of average fill price (probability format) given a base/payout quantity 456 457 Args: 458 base_qty (int): Base quantity 459 side (Side): Side object (bid or ask) 460 ui_amount (bool): Converts prices based on decimal precision if true. 461 462 Returns: 463 dict[str, float]: Dictionary containing `avg_price`, `worst_price`, `filled` 464 """ 465 return self.__estimate_fill_for_qty(base_qty, side, False, ui_amount) 466 467 def estimate_avg_fill_for_quote_qty(self, quote_qty: int, side: Side, ui_amount: bool): 468 """ 469 Gets estimate of average fill price (probability format) given a stake/quote quantity 470 471 Args: 472 quote_qty (int): Base quantity 473 side (Side): Side object (bid or ask) 474 ui_amount (bool): Converts prices based on decimal precision if true. 475 476 Returns: 477 dict[str, float]: Dictionary containing `avg_price`, `worst_price`, `filled` 478 """ 479 return self.__estimate_fill_for_qty(quote_qty, side, True, ui_amount) 480 481 def __estimate_fill_for_qty(self, qty: int, side: Side, quote: bool, ui_amount: bool): 482 """ 483 _summary_ 484 485 Args: 486 qty (int): Quanity 487 side (Side): Side object (bid or ask) 488 quote (bool): Quote quantity if true. Base quantity if false. 489 ui_amount (bool): Converts prices based on decimal precision if true. 490 491 Returns: 492 dict[str, float]: Dictionary containing `avg_price`, `worst_price`, `filled` 493 """ 494 if(side == Side.BUY): 495 prices = self.get_bids_l2(100, ui_amount) 496 elif(side == Side.SELL): 497 prices = self.get_asks_l2(100, ui_amount) 498 499 if(quote): 500 accumulator = lambda p: p.size 501 else: 502 accumulator = lambda p: p.size * p.price 503 504 new_prices: list[Price] = [] 505 cumulative_qty = 0 506 for price in prices: 507 remaining_qty = qty - cumulative_qty 508 if(remaining_qty <= accumulator(price)): 509 cumulative_qty += remaining_qty 510 new_size = remaining_qty if quote else remaining_qty/price.price 511 new_prices.append(Price(price=price.price, size=new_size)) 512 break 513 else: 514 cumulative_qty += accumulator(price) 515 new_prices.append(price) 516 517 return { 518 'avg_price': Orderbook.weighted_average( 519 nums=[p.price for p in new_prices], 520 weights=[p.size for p in new_prices] 521 ), 522 'worst_price': new_prices[-1].price, 523 'filled': cumulative_qty 524 } 525 526 @staticmethod 527 def weighted_average(nums, weights): 528 """ 529 Calculates weighted average 530 531 Args: 532 nums (list[float]): List of values 533 weights (list[float]): List of weights 534 535 Returns: 536 float: Weighted average 537 """ 538 sum = 0 539 weight_sum = 0 540 541 assert len(nums) == len(weights), 'Number of weights and nums do not correspond' 542 543 for i, num in enumerate(nums): 544 weight = weights[i] 545 sum += num * weight 546 weight_sum += weight 547 548 return sum / weight_sum
Orderbook object
Contains information on open orders on both the bids and asks of a particular outcome in a market
46 def __init__( 47 self, 48 pubkey: PublicKey, 49 slab_bids: Slab, 50 slab_asks: Slab, 51 slab_bids_pubkey: PublicKey, 52 slab_asks_pubkey: PublicKey, 53 decimals: int, 54 is_inverted: bool = False 55 ): 56 """ 57 Initialise an Orderbook object. Do not use this function; use Orderbook.load() instead 58 59 Args: 60 pubkey (PublicKey): Orderbook public key 61 slab_bids (Slab): Slab object for bids 62 slab_asks (Slab): Slab object for asks 63 slab_bids_pubkey (PublicKey): Slab bids public key 64 slab_asks_pubkey (PublicKey): Slab asks public key 65 decimals (int): Decimal precision for orderbook 66 is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False. 67 """ 68 self.decimals = decimals 69 self.pubkey = pubkey 70 self.slab_bids = slab_bids 71 self.slab_asks = slab_asks 72 self.slab_bids_pubkey = slab_bids_pubkey 73 self.slab_asks_pubkey = slab_asks_pubkey 74 self.is_inverted = is_inverted
Initialise an Orderbook object. Do not use this function; use Orderbook.load() instead
Args
- pubkey (PublicKey): Orderbook public key
- slab_bids (Slab): Slab object for bids
- slab_asks (Slab): Slab object for asks
- slab_bids_pubkey (PublicKey): Slab bids public key
- slab_asks_pubkey (PublicKey): Slab asks public key
- decimals (int): Decimal precision for orderbook
- is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False.
Whether the bids and asks should be interpretted as inverted when parsing the data. (Used in the case of the second outcome in a two-outcome market.)
76 @staticmethod 77 async def load( 78 conn: AsyncClient, 79 slab_bids_pubkey: PublicKey, 80 slab_asks_pubkey: PublicKey, 81 orderbook_pubkey: PublicKey, 82 decimals: int, 83 is_inverted: bool = False 84 ): 85 """ 86 Initialise an Orderbook object 87 88 Parameters are found in MarketStoreStates' --> OrderbookAccounts 89 90 Args: 91 conn (AsyncClient): Solana AsyncClient object 92 slab_bids_pubkey (PublicKey): Slab bids public key 93 slab_asks_pubkey (PublicKey): Slab asks public key 94 orderbook_pubkey (PublicKey): Orderbook public key 95 decimals (int): Decimal precision for orderbook 96 is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False. 97 98 Returns: 99 Orderbook: Orderbook object 100 """ 101 102 slab_bids = await Orderbook.load_slab(conn, slab_bids_pubkey) 103 slab_asks = await Orderbook.load_slab(conn, slab_asks_pubkey) 104 105 return Orderbook( 106 pubkey=orderbook_pubkey, 107 slab_bids=slab_bids, 108 slab_asks=slab_asks, 109 slab_asks_pubkey=slab_asks_pubkey, 110 slab_bids_pubkey=slab_bids_pubkey, 111 decimals=decimals, 112 is_inverted=is_inverted 113 )
Initialise an Orderbook object
Parameters are found in MarketStoreStates' --> OrderbookAccounts
Args
- conn (AsyncClient): Solana AsyncClient object
- slab_bids_pubkey (PublicKey): Slab bids public key
- slab_asks_pubkey (PublicKey): Slab asks public key
- orderbook_pubkey (PublicKey): Orderbook public key
- decimals (int): Decimal precision for orderbook
- is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False.
Returns
Orderbook: Orderbook object
115 @staticmethod 116 async def load_slab(conn: AsyncClient, slab_address: PublicKey): 117 """ 118 Loads onchain data for a Slab (contains orders for a particular side of the orderbook) 119 120 Args: 121 conn (AsyncClient): Solana AsyncClient object 122 slab_address (PublicKey): Slab public key 123 124 Returns: 125 Slab: Slab object 126 """ 127 data = await load_bytes_data(conn, slab_address) 128 return Slab.from_bytes(data)
Loads onchain data for a Slab (contains orders for a particular side of the orderbook)
Args
- conn (AsyncClient): Solana AsyncClient object
- slab_address (PublicKey): Slab public key
Returns
Slab: Slab object
130 @staticmethod 131 async def load_multiple_slabs(conn: AsyncClient, slab_addresses: list[PublicKey]): 132 """ 133 Loads onchain data for multiple Slabs (contains orders for a particular side of the orderbook) 134 135 Args: 136 conn (AsyncClient): Solana AsyncClient object 137 slab_addresses (list[PublicKey]): List of slab public keys 138 139 Returns: 140 list[Slab]: List of Slab objects 141 """ 142 data = await load_multiple_bytes_data(conn, slab_addresses) 143 slabs = [] 144 for d in data: 145 slabs.append(Slab.from_bytes(d)) 146 return slabs
Loads onchain data for multiple Slabs (contains orders for a particular side of the orderbook)
Args
- conn (AsyncClient): Solana AsyncClient object
- slab_addresses (list[PublicKey]): List of slab public keys
Returns
list[Slab]: List of Slab objects
148 def invert(self): 149 """ 150 Returns a version of the orderbook which has been parsed with bids and asks swtiched and 151 prices inverted. (Used for the second outcome in a two-outcome market) 152 153 Returns: 154 Orderbook: Orderbook object 155 """ 156 return Orderbook( 157 self.pubkey, 158 self.slab_asks, 159 self.slab_bids, 160 self.slab_asks_pubkey, 161 self.slab_bids_pubkey, 162 self.decimals, 163 True 164 )
Returns a version of the orderbook which has been parsed with bids and asks swtiched and prices inverted. (Used for the second outcome in a two-outcome market)
Returns
Orderbook: Orderbook object
167 @staticmethod 168 def convert_price(p: Price, decimals: int): 169 """ 170 Converts price to correct order of magnitude based on decimal precision 171 172 Args: 173 p (Price): Unconverted Price object 174 decimals (int): Decimal precision for orderbook 175 176 Returns: 177 Price: Price object 178 """ 179 exp = 10 ** decimals 180 return Price( 181 price=p.price / exp, 182 #price=round((p.price / 2 ** 32) * exp) / exp, 183 size=p.size / exp 184 )
Converts price to correct order of magnitude based on decimal precision
Args
- p (Price): Unconverted Price object
- decimals (int): Decimal precision for orderbook
Returns
Price: Price object
186 @staticmethod 187 def get_L2_for_slab( 188 slab: Slab, 189 depth: int, 190 increasing : bool, 191 decimals: int, 192 ui_amount=False, 193 is_inverted=False 194 ): 195 """ 196 Get Level 2 market information for a particular slab 197 198 This contains information on orders on the slab aggregated by price tick. 199 200 Args: 201 slab (Slab): Slab object 202 depth (int): Number of orders to return 203 increasing (bool): Sort orders increasing 204 decimals (int): Decimal precision for orderbook 205 ui_amount (bool, optional): Converts prices based on decimal precision if true. Defaults to False. 206 is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False. 207 208 Returns: 209 list[Price]: List of Price objects (size and price) corresponding to orders on the slab 210 """ 211 212 l2_depth = Orderbook.__get_L2(slab, depth, decimals, increasing) 213 if(ui_amount): 214 l2_depth = [Orderbook.convert_price(p, decimals) for p in l2_depth] 215 216 if(is_inverted): 217 l2_depth = [Orderbook.invert_price(p) for p in l2_depth] 218 219 return l2_depth
Get Level 2 market information for a particular slab
This contains information on orders on the slab aggregated by price tick.
Args
- slab (Slab): Slab object
- depth (int): Number of orders to return
- increasing (bool): Sort orders increasing
- decimals (int): Decimal precision for orderbook
- ui_amount (bool, optional): Converts prices based on decimal precision if true. Defaults to False.
- is_inverted (bool, optional): Whether the bids and asks have been switched with each other. Defaults to False.
Returns
list[Price]: List of Price objects (size and price) corresponding to orders on the slab
264 @staticmethod 265 def invert_price(p: Price): 266 """ 267 Inverts prices 268 269 This is used when inverting the second outcome in a two-outcome market. 270 271 When switching prices between bids and asks, the price is `1-p`. 272 273 Example, a BUY on A at a (probability) price of 0.4 is equivelant to a SELL on B at a price of 0.6 (1-0.4) and vice versa. 274 275 Args: 276 p (Price): Price object 277 278 Returns: 279 Price: Price object 280 """ 281 return Price( 282 price=1-p.price, 283 size=p.size 284 )
Inverts prices
This is used when inverting the second outcome in a two-outcome market.
When switching prices between bids and asks, the price is 1-p
.
Example, a BUY on A at a (probability) price of 0.4 is equivelant to a SELL on B at a price of 0.6 (1-0.4) and vice versa.
Args
- p (Price): Price object
Returns
Price: Price object
286 def get_bids_L3(self): 287 """ 288 Gets level 1 market information for bids. 289 290 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 291 292 Returns: 293 list[SlabOrder]: List of slab orders for bids 294 """ 295 is_increasing = False 296 if(self.is_inverted): 297 is_increasing = True 298 299 return Orderbook.__get_L3( 300 self.slab_bids, 301 self.decimals, 302 is_increasing, 303 self.is_inverted 304 )
Gets level 1 market information for bids.
See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information
Returns
list[SlabOrder]: List of slab orders for bids
306 def get_asks_L3(self): 307 """ 308 Gets level 1 market information for asks 309 310 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 311 312 Returns: 313 list[SlabOrder]: List of slab orders for asks 314 """ 315 is_increasing = True 316 if(self.is_inverted): 317 is_increasing = False 318 319 return Orderbook.__get_L3( 320 self.slab_asks, 321 self.decimals, 322 is_increasing, 323 self.is_inverted 324 )
Gets level 1 market information for asks
See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information
Returns
list[SlabOrder]: List of slab orders for asks
327 def get_bids_l2(self, depth: int, ui_amount: bool): 328 """ 329 Gets level 1 market information for bids 330 331 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 332 333 Args: 334 depth (int): Number of orders to return 335 ui_amount (bool): Converts prices based on decimal precision if true. 336 337 Returns: 338 list[Price]: List of Price objects (size and price) corresponding to orders on the slab 339 """ 340 is_increasing = False 341 if(self.is_inverted): 342 is_increasing = True 343 344 return Orderbook.get_L2_for_slab( 345 self.slab_bids, 346 depth, 347 is_increasing, 348 self.decimals, 349 ui_amount, 350 self.is_inverted, 351 )
Gets level 1 market information for bids
See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information
Args
- depth (int): Number of orders to return
- ui_amount (bool): Converts prices based on decimal precision if true.
Returns
list[Price]: List of Price objects (size and price) corresponding to orders on the slab
353 def get_asks_l2(self, depth: int, ui_amount: bool): 354 """ 355 Gets level 1 market information for asks 356 357 See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information 358 359 Args: 360 depth (int): Number of orders to return 361 ui_amount (bool): Converts prices based on decimal precision if true. 362 363 Returns: 364 list[Price]: List of Price objects (size and probability price) corresponding to orders on the slab 365 """ 366 is_increasing = True 367 if(self.is_inverted): 368 is_increasing = False 369 370 return Orderbook.get_L2_for_slab( 371 self.slab_asks, 372 depth, 373 is_increasing, 374 self.decimals, 375 ui_amount, 376 self.is_inverted, 377 )
Gets level 1 market information for asks
See https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118 for more information
Args
- depth (int): Number of orders to return
- ui_amount (bool): Converts prices based on decimal precision if true.
Returns
list[Price]: List of Price objects (size and probability price) corresponding to orders on the slab
379 def get_best_bid_price(self, ui_amount: bool): 380 """ 381 Gets the best bid price 382 383 Args: 384 ui_amount (bool): Converts prices based on decimal precision if true. 385 386 Returns: 387 Price: Price object (size and price) 388 """ 389 bids = self.get_bids_l2(1, ui_amount) 390 if(bids is not None and len(bids) > 0): 391 return bids[0] 392 return None
Gets the best bid price
Args
- ui_amount (bool): Converts prices based on decimal precision if true.
Returns
Price: Price object (size and price)
394 def get_best_ask_price(self, ui_amount: bool): 395 """ 396 Gets the best ask price 397 398 Args: 399 ui_amount (bool): Converts prices based on decimal precision if true. 400 401 Returns: 402 Price: Price object (size and price) 403 """ 404 asks = self.get_asks_l2(1, ui_amount) 405 if(asks is not None and len(asks) > 0): 406 return asks[0] 407 return None
Gets the best ask price
Args
- ui_amount (bool): Converts prices based on decimal precision if true.
Returns
Price: Price object (size and price)
409 def get_bid_price_by_order_id(self, order_id: int): 410 """ 411 Gets bid Price object by order_id 412 413 Args: 414 order_id (int): Order ID 415 416 Returns: 417 Price: Price object (size and price) 418 """ 419 bid = self.slab_bids.get(order_id) 420 if(bid is None): 421 return None 422 423 bid_price = Price(price=bid.key >> 64, size=bid.base_quantity) 424 bid_price = Orderbook.convert_price(bid_price, self.decimals) 425 426 if(self.is_inverted): 427 bid_price = Orderbook.invert_price(bid_price) 428 429 return bid_price
Gets bid Price object by order_id
Args
- order_id (int): Order ID
Returns
Price: Price object (size and price)
431 def get_ask_price_by_order_id(self, order_id: int): 432 """ 433 Gets ask Price object by order_id 434 435 Args: 436 order_id (int): Order ID 437 438 Returns: 439 Price: Price object (size and price) 440 """ 441 ask = self.slab_asks.get(order_id) 442 if(ask is None): 443 return None 444 445 ask_price = Price(price=ask.key >> 64, size=ask.base_quantity) 446 ask_price = Orderbook.convert_price(ask_price, self.decimals) 447 448 if(self.is_inverted): 449 ask_price = Orderbook.invert_price(ask_price) 450 451 return ask_price
Gets ask Price object by order_id
Args
- order_id (int): Order ID
Returns
Price: Price object (size and price)
453 def estimate_avg_fill_for_base_qty(self, base_qty: int, side: Side, ui_amount: bool): 454 """ 455 Gets estimate of average fill price (probability format) given a base/payout quantity 456 457 Args: 458 base_qty (int): Base quantity 459 side (Side): Side object (bid or ask) 460 ui_amount (bool): Converts prices based on decimal precision if true. 461 462 Returns: 463 dict[str, float]: Dictionary containing `avg_price`, `worst_price`, `filled` 464 """ 465 return self.__estimate_fill_for_qty(base_qty, side, False, ui_amount)
Gets estimate of average fill price (probability format) given a base/payout quantity
Args
- base_qty (int): Base quantity
- side (Side): Side object (bid or ask)
- ui_amount (bool): Converts prices based on decimal precision if true.
Returns
dict[str, float]: Dictionary containing
avg_price
,worst_price
,filled
467 def estimate_avg_fill_for_quote_qty(self, quote_qty: int, side: Side, ui_amount: bool): 468 """ 469 Gets estimate of average fill price (probability format) given a stake/quote quantity 470 471 Args: 472 quote_qty (int): Base quantity 473 side (Side): Side object (bid or ask) 474 ui_amount (bool): Converts prices based on decimal precision if true. 475 476 Returns: 477 dict[str, float]: Dictionary containing `avg_price`, `worst_price`, `filled` 478 """ 479 return self.__estimate_fill_for_qty(quote_qty, side, True, ui_amount)
Gets estimate of average fill price (probability format) given a stake/quote quantity
Args
- quote_qty (int): Base quantity
- side (Side): Side object (bid or ask)
- ui_amount (bool): Converts prices based on decimal precision if true.
Returns
dict[str, float]: Dictionary containing
avg_price
,worst_price
,filled
526 @staticmethod 527 def weighted_average(nums, weights): 528 """ 529 Calculates weighted average 530 531 Args: 532 nums (list[float]): List of values 533 weights (list[float]): List of weights 534 535 Returns: 536 float: Weighted average 537 """ 538 sum = 0 539 weight_sum = 0 540 541 assert len(nums) == len(weights), 'Number of weights and nums do not correspond' 542 543 for i, num in enumerate(nums): 544 weight = weights[i] 545 sum += num * weight 546 weight_sum += weight 547 548 return sum / weight_sum
Calculates weighted average
Args
- nums (list[float]): List of values
- weights (list[float]): List of weights
Returns
float: Weighted average