11import ctypes
2+ from fractions import Fraction
23from functools import wraps
34import inspect
45import json
@@ -591,8 +592,83 @@ async def create_market_order(
591592 market_index ,
592593 client_order_index ,
593594 base_amount ,
594- avg_execution_price ,
595+ price = avg_execution_price ,
596+ is_ask = is_ask ,
597+ order_type = self .ORDER_TYPE_MARKET ,
598+ time_in_force = self .ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL ,
599+ order_expiry = self .DEFAULT_IOC_EXPIRY ,
600+ reduce_only = reduce_only ,
601+ nonce = nonce ,
602+ api_key_index = api_key_index ,
603+ )
604+
605+ # returns best price as integer
606+ async def get_best_price (self , market_index , is_ask , ob_orders = None ) -> int :
607+ if ob_orders is None :
608+ ob_orders = await self .order_api .order_book_orders (market_index , 1 )
609+ ideal_price = int ((ob_orders .bids [0 ].price if is_ask else ob_orders .asks [0 ].price ).replace ("." , "" ))
610+ return ideal_price
611+
612+ async def get_potential_execution_price (self , market_index , amount , is_ask , is_amount_base = True , ob_orders = None ) -> (float , int ):
613+ if ob_orders is None :
614+ ob_orders = await self .order_api .order_book_orders (market_index , 100 )
615+ matched_usd_amount , matched_size = 0 , 0
616+ for ob_order in (ob_orders .bids if is_ask else ob_orders .asks ):
617+ if (is_amount_base and matched_size == amount ) or (not is_amount_base and matched_usd_amount == amount ):
618+ break
619+ curr_order_price = int (ob_order .price .replace ("." , "" ))
620+ curr_order_size = int (ob_order .remaining_base_amount .replace ("." , "" ))
621+ max_possible_order_size = amount - matched_size if is_amount_base else Fraction (amount - matched_usd_amount , curr_order_price )
622+
623+ to_be_used_order_size = min (max_possible_order_size , curr_order_size )
624+ matched_usd_amount += curr_order_price * to_be_used_order_size
625+ matched_size += to_be_used_order_size
626+
627+ potential_execution_price = matched_usd_amount / matched_size
628+
629+ return potential_execution_price , (matched_size if is_amount_base else matched_usd_amount )
630+
631+ async def create_market_order_quote_amount (
632+ self ,
633+ market_index ,
634+ client_order_index ,
635+ quote_amount ,
636+ max_slippage ,
637+ is_ask ,
638+ reduce_only : bool = False ,
639+ nonce : int = DEFAULT_NONCE ,
640+ api_key_index : int = DEFAULT_API_KEY_INDEX ,
641+ ideal_price = None
642+ ):
643+ quote_amount = int (quote_amount * 1e6 )
644+ ob_orders = await self .order_api .order_book_orders (market_index , 100 )
645+ if ideal_price is None :
646+ logging .debug (
647+ "Doing an API call to get the current ideal price. You can also provide it yourself to avoid this." )
648+ ideal_price = await self .get_best_price (market_index , is_ask , ob_orders = ob_orders )
649+ acceptable_execution_price = round (ideal_price * (1 + max_slippage * (- 1 if is_ask else 1 )))
650+
651+ potential_execution_price , matched_usd_amount = await self .get_potential_execution_price (
652+ market_index ,
653+ quote_amount ,
595654 is_ask ,
655+ is_amount_base = False ,
656+ ob_orders = ob_orders
657+ )
658+
659+ if (is_ask and potential_execution_price < acceptable_execution_price ) or (not is_ask and potential_execution_price > acceptable_execution_price ):
660+ return None , None , "Excessive slippage"
661+ if matched_usd_amount < quote_amount :
662+ return None , None , "Cannot be sure slippage will be acceptable due to the high size"
663+
664+ # one can choose between int or round depending on purpose, doesn't really much
665+ base_amount = int (quote_amount / potential_execution_price )
666+ return await self .create_order (
667+ market_index ,
668+ client_order_index ,
669+ base_amount ,
670+ price = round (acceptable_execution_price ), # just in case, limits size for slippage
671+ is_ask = is_ask ,
596672 order_type = self .ORDER_TYPE_MARKET ,
597673 time_in_force = self .ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL ,
598674 order_expiry = self .DEFAULT_IOC_EXPIRY ,
@@ -615,10 +691,9 @@ async def create_market_order_limited_slippage(
615691 ideal_price = None
616692 ) -> Union [Tuple [CreateOrder , RespSendTx , None ], Tuple [None , None , str ]]:
617693 if ideal_price is None :
618- order_book_orders = await self .order_api .order_book_orders (market_index , 1 )
619694 logging .debug (
620695 "Create market order limited slippage is doing an API call to get the current ideal price. You can also provide it yourself to avoid this." )
621- ideal_price = int (( order_book_orders . bids [ 0 ]. price if is_ask else order_book_orders . asks [ 0 ]. price ). replace ( "." , "" ) )
696+ ideal_price = await self . get_best_price ( market_index , is_ask )
622697
623698 acceptable_execution_price = round (ideal_price * (1 + max_slippage * (- 1 if is_ask else 1 )))
624699 return await self .create_order (
@@ -648,21 +723,17 @@ async def create_market_order_if_slippage(
648723 api_key_index : int = DEFAULT_API_KEY_INDEX ,
649724 ideal_price = None
650725 ) -> Union [Tuple [CreateOrder , RespSendTx , None ], Tuple [None , None , str ]]:
651- order_book_orders = await self .order_api .order_book_orders (market_index , 100 )
726+ ob_orders = await self .order_api .order_book_orders (market_index , 100 )
652727 if ideal_price is None :
653- ideal_price = int ((order_book_orders .bids [0 ].price if is_ask else order_book_orders .asks [0 ].price ).replace ("." , "" ))
654-
655- matched_usd_amount , matched_size = 0 , 0
656- for order_book_order in (order_book_orders .bids if is_ask else order_book_orders .asks ):
657- if matched_size == base_amount :
658- break
659- curr_order_price = int (order_book_order .price .replace ("." , "" ))
660- curr_order_size = int (order_book_order .remaining_base_amount .replace ("." , "" ))
661- to_be_used_order_size = min (base_amount - matched_size , curr_order_size )
662- matched_usd_amount += curr_order_price * to_be_used_order_size
663- matched_size += to_be_used_order_size
728+ ideal_price = await self .get_best_price (market_index , is_ask , ob_orders )
729+ potential_execution_price , matched_size = await self .get_potential_execution_price (
730+ market_index ,
731+ base_amount ,
732+ is_ask ,
733+ is_amount_base = True ,
734+ ob_orders = ob_orders
735+ )
664736
665- potential_execution_price = matched_usd_amount / matched_size
666737 acceptable_execution_price = ideal_price * (1 + max_slippage * (- 1 if is_ask else 1 ))
667738 if (is_ask and potential_execution_price < acceptable_execution_price ) or (not is_ask and potential_execution_price > acceptable_execution_price ):
668739 return None , None , "Excessive slippage"
0 commit comments