pyaver.checks
1from .utils import round_price_to_nearest_tick_size 2from .market import AverMarket 3from .enums import MarketStatus, OrderType, Side, SizeFormat 4from .user_host_lifetime import UserHostLifetime 5from .data_classes import UserBalanceState, UserMarketState 6 7###### PLACE ORDER CHECKS 8 9def check_sufficient_lamport_balance(user_balance_state: UserBalanceState): 10 if(user_balance_state.lamport_balance < 5000): 11 raise Exception(f'Payer has insufficient lamports. Lamport balance: {user_balance_state.lamport_balance}') 12 13def check_market_active_pre_event(market_status: MarketStatus): 14 if(market_status != MarketStatus.ACTIVE_PRE_EVENT): 15 raise Exception(f'The current market status does not permit this action. Market status {market_status}') 16 17def check_uhl_self_excluded(uhl: UserHostLifetime): 18 if(uhl.user_host_lifetime_state.is_self_excluded_until): 19 raise Exception('This user is self excluded at this time.') 20 21def check_user_market_full(user_market_state: UserMarketState): 22 if(user_market_state.number_of_orders == user_market_state.max_number_of_orders): 23 raise Exception(f'The UserMarketAccount for this market has reach its maximum capacity for open orders. Open orders: {user_market_state.number_of_orders } Slots: {user_market_state.max_number_of_orders}') 24 25def check_limit_price_error(limit_price: float, market: AverMarket): 26 one_in_market_decimals = 10 ** market.market_state.decimals 27 if(limit_price > one_in_market_decimals): 28 raise Exception(f'Limit prices must be in the range 0 to 1 USDC (0 - 1,000,000). Value provided: {limit_price}') 29 30def check_price_error(limit_price: float, side: Side): 31 if(side == Side.BUY): 32 if(not limit_price > 0): 33 raise Exception(f'The price provided for a BUY order must be strictly greater than 0. Limit price provided: {limit_price}') 34 35 if(side == Side.SELL): 36 if(not limit_price < 1): 37 raise Exception(f'The price provided for a SELL order must be strictly less than 1 USDC (1,000,000). Limit price provided: {limit_price}') 38 39def check_outcome_outside_space(outcome_id: int, market: AverMarket): 40 if(not outcome_id in range(0, market.market_state.number_of_outcomes - 1)): 41 raise Exception(f'The outcome index provided is not within the outcome space for this market. Outcome index provided: {outcome_id}; Outcome indices in this market: 0 to {(market.market_state.number_of_outcomes-1)}') 42 43def check_incorrect_order_type_for_market_order(limit_price: float, order_type: OrderType, side: Side, market: AverMarket): 44 market_order = (limit_price == 1 and side == Side.BUY) or (limit_price == 0 and side == Side.SELL) 45 if(market_order): 46 if(order_type != OrderType.KILL_OR_FILL and order_type != OrderType.IOC): 47 raise Exception(f"When placing a market order (BUY with price = 1, or SELL with price = 0), the order type must to be IOC or KOF") 48 49def check_stake_noop(size_format: SizeFormat, limit_price: float, side: Side): 50 market_order = (limit_price == 1 and side == Side.BUY) or (limit_price == 0 and side == Side.SELL) 51 if(size_format == SizeFormat.STAKE and market_order): 52 raise Exception('Market orders are currently not supports for orders specified in STAKE.') 53 54def check_is_order_valid( 55 outcome_index: int, 56 side: Side, 57 limit_price: float, 58 size: float, 59 size_format: SizeFormat, 60 tokens_available_to_sell: float, 61 tokens_available_to_buy: float, 62): 63 """ 64 Performs clientside checks prior to placing an order 65 66 Args: 67 outcome_index (int): Outcome ID 68 side (Side): Side 69 limit_price (float): Limit price 70 size (float): Size 71 size_format (SizeFormat): SizeFormat object (state or payout) 72 73 Raises: 74 Exception: Insufficient Token Balance 75 76 Returns: 77 bool: True if order is valid 78 """ 79 limit_price = round_price_to_nearest_tick_size(limit_price) 80 81 balance_required = size * limit_price if size_format == SizeFormat.PAYOUT else size 82 current_balance = tokens_available_to_sell if side == Side.SELL else tokens_available_to_buy 83 84 if(current_balance < balance_required): 85 raise Exception(f'Insufficient token balance to support this order. Balance: {current_balance}; Required: {balance_required}') 86 87def check_quote_and_base_size_too_small(market: AverMarket, side: Side, size_format: SizeFormat, outcome_id: int, limit_price: float, size: float): 88 binary_second_outcome = market.market_state.number_of_outcomes == 2 and outcome_id == 1 89 limit_price_rounded = round_price_to_nearest_tick_size(limit_price) 90 91 if(size_format == SizeFormat.PAYOUT): 92 max_base_qty = size 93 if(limit_price != 0): 94 max_quote_qty = limit_price_rounded * max_base_qty 95 else: 96 max_quote_qty = max_base_qty 97 if(side == Side.SELL): 98 max_quote_qty = size 99 else: 100 if(limit_price != 0): 101 if(binary_second_outcome): 102 max_base_qty = size / (1 - limit_price_rounded) 103 max_quote_qty = max_base_qty 104 else: 105 max_quote_qty = size 106 max_base_qty = (max_quote_qty) / limit_price_rounded 107 108 max_quote_qty = max_quote_qty * (10 ** market.market_state.decimals) 109 max_base_qty = max_base_qty * (10 ** market.market_state.decimals) 110 111 if(binary_second_outcome and size_format == SizeFormat.PAYOUT and side == Side.BUY and (max_base_qty - max_quote_qty) < market.market_store_state.min_new_order_quote_size): 112 raise Exception(f'The resulting STAKE size for this order is below the market minimum. Stake: {max_base_qty - max_quote_qty}, Minimum stake: {market.market_store_state.min_new_order_quote_size}') 113 114 115 if((not binary_second_outcome) and max_quote_qty < market.market_store_state.min_new_order_quote_size): 116 raise Exception(f'The resulting STAKE size for this order is below the market minimum. Stake: {max_quote_qty}, Minimum stake: {market.market_store_state.min_new_order_quote_size}') 117 118 if(max_base_qty < market.market_store_state.min_new_order_base_size): 119 raise Exception(f'The resulting PAYOUT size for this order is below the market minimum. Payout: {max_base_qty}, Minimum payout: {market.market_store_state.min_new_order_base_size}') 120 121 122def check_user_permission_and_quote_token_limit_exceeded(market: AverMarket, user_market_state: UserMarketState, size: float, limit_price: float, size_format: SizeFormat): 123 balance_required = size * limit_price if size_format == SizeFormat.PAYOUT else size 124 pmf = market.market_state.permissioned_market_flag 125 126 if((not pmf) or (pmf and user_market_state.user_verification_account is not None)): 127 quote_tokens_limit = market.market_state.max_quote_tokens_in 128 elif(pmf and user_market_state.user_verification_account is None): 129 quote_tokens_limit = market.market_state.max_quote_tokens_in_permission_capped 130 else: 131 raise Exception(f'This wallet does not have the required permissions to interact with this market.') 132 133 if((balance_required + user_market_state.net_quote_tokens_in) > quote_tokens_limit): 134 raise Exception(f'This order would lead to the maximum number of tokens for this market being exceeded. Please adjust your order to remain within market limits. Tokens required for this order {balance_required}; Remaining tokens until limit reached: {quote_token_limit - user_market_state.net_quote_tokens_in}') 135 136##### 137## Cancel order 138 139def check_correct_uma_market_match(user_market_state: UserMarketState, market: AverMarket): 140 if(user_market_state.market.to_base58() != market.market_pubkey.to_base58()): 141 raise Exception('Aver Market is not as expected when placing order') 142 143def check_cancel_order_market_status(market_status: MarketStatus): 144 invalid_statuses = [MarketStatus.INITIALIZED, MarketStatus.RESOLVED, MarketStatus.VOIDED, MarketStatus.UNINITIALIZED, MarketStatus.CEASED_CRANKED_CLOSED, MarketStatus.TRADING_CEASED] 145 146 if(market_status in invalid_statuses): 147 raise Exception(f'The current market status does not permit this action. Market status {market_status}') 148 149def check_order_exists(user_market_state: UserMarketState, order_id: int): 150 for o in user_market_state.orders: 151 if o.order_id - order_id == 0: 152 return 153 raise Exception(f'No order at order_id {order_id} was found for this market.') 154 155#TODO - Calculate min across free outcome positions 156def check_outcome_position_amount_error(user_market_state: UserMarketState): 157 pass 158 159def check_outcome_has_orders(outcome_id: int, user_market_state: UserMarketState): 160 for o in user_market_state.orders: 161 if(o.outcome_id == outcome_id): 162 return 163 raise Exception(f'No open orders found for outcome {outcome_id} in this market.')
22def check_user_market_full(user_market_state: UserMarketState): 23 if(user_market_state.number_of_orders == user_market_state.max_number_of_orders): 24 raise Exception(f'The UserMarketAccount for this market has reach its maximum capacity for open orders. Open orders: {user_market_state.number_of_orders } Slots: {user_market_state.max_number_of_orders}')
31def check_price_error(limit_price: float, side: Side): 32 if(side == Side.BUY): 33 if(not limit_price > 0): 34 raise Exception(f'The price provided for a BUY order must be strictly greater than 0. Limit price provided: {limit_price}') 35 36 if(side == Side.SELL): 37 if(not limit_price < 1): 38 raise Exception(f'The price provided for a SELL order must be strictly less than 1 USDC (1,000,000). Limit price provided: {limit_price}')
40def check_outcome_outside_space(outcome_id: int, market: AverMarket): 41 if(not outcome_id in range(0, market.market_state.number_of_outcomes - 1)): 42 raise Exception(f'The outcome index provided is not within the outcome space for this market. Outcome index provided: {outcome_id}; Outcome indices in this market: 0 to {(market.market_state.number_of_outcomes-1)}')
def
check_incorrect_order_type_for_market_order( limit_price: float, order_type: pyaver.enums.OrderType, side: pyaver.enums.Side, market: pyaver.market.AverMarket)
44def check_incorrect_order_type_for_market_order(limit_price: float, order_type: OrderType, side: Side, market: AverMarket): 45 market_order = (limit_price == 1 and side == Side.BUY) or (limit_price == 0 and side == Side.SELL) 46 if(market_order): 47 if(order_type != OrderType.KILL_OR_FILL and order_type != OrderType.IOC): 48 raise Exception(f"When placing a market order (BUY with price = 1, or SELL with price = 0), the order type must to be IOC or KOF")
def
check_stake_noop( size_format: pyaver.enums.SizeFormat, limit_price: float, side: pyaver.enums.Side)
50def check_stake_noop(size_format: SizeFormat, limit_price: float, side: Side): 51 market_order = (limit_price == 1 and side == Side.BUY) or (limit_price == 0 and side == Side.SELL) 52 if(size_format == SizeFormat.STAKE and market_order): 53 raise Exception('Market orders are currently not supports for orders specified in STAKE.')
def
check_is_order_valid( outcome_index: int, side: pyaver.enums.Side, limit_price: float, size: float, size_format: pyaver.enums.SizeFormat, tokens_available_to_sell: float, tokens_available_to_buy: float)
55def check_is_order_valid( 56 outcome_index: int, 57 side: Side, 58 limit_price: float, 59 size: float, 60 size_format: SizeFormat, 61 tokens_available_to_sell: float, 62 tokens_available_to_buy: float, 63): 64 """ 65 Performs clientside checks prior to placing an order 66 67 Args: 68 outcome_index (int): Outcome ID 69 side (Side): Side 70 limit_price (float): Limit price 71 size (float): Size 72 size_format (SizeFormat): SizeFormat object (state or payout) 73 74 Raises: 75 Exception: Insufficient Token Balance 76 77 Returns: 78 bool: True if order is valid 79 """ 80 limit_price = round_price_to_nearest_tick_size(limit_price) 81 82 balance_required = size * limit_price if size_format == SizeFormat.PAYOUT else size 83 current_balance = tokens_available_to_sell if side == Side.SELL else tokens_available_to_buy 84 85 if(current_balance < balance_required): 86 raise Exception(f'Insufficient token balance to support this order. Balance: {current_balance}; Required: {balance_required}')
Performs clientside checks prior to placing an order
Args
- outcome_index (int): Outcome ID
- side (Side): Side
- limit_price (float): Limit price
- size (float): Size
- size_format (SizeFormat): SizeFormat object (state or payout)
Raises
- Exception: Insufficient Token Balance
Returns
bool: True if order is valid
def
check_quote_and_base_size_too_small( market: pyaver.market.AverMarket, side: pyaver.enums.Side, size_format: pyaver.enums.SizeFormat, outcome_id: int, limit_price: float, size: float)
88def check_quote_and_base_size_too_small(market: AverMarket, side: Side, size_format: SizeFormat, outcome_id: int, limit_price: float, size: float): 89 binary_second_outcome = market.market_state.number_of_outcomes == 2 and outcome_id == 1 90 limit_price_rounded = round_price_to_nearest_tick_size(limit_price) 91 92 if(size_format == SizeFormat.PAYOUT): 93 max_base_qty = size 94 if(limit_price != 0): 95 max_quote_qty = limit_price_rounded * max_base_qty 96 else: 97 max_quote_qty = max_base_qty 98 if(side == Side.SELL): 99 max_quote_qty = size 100 else: 101 if(limit_price != 0): 102 if(binary_second_outcome): 103 max_base_qty = size / (1 - limit_price_rounded) 104 max_quote_qty = max_base_qty 105 else: 106 max_quote_qty = size 107 max_base_qty = (max_quote_qty) / limit_price_rounded 108 109 max_quote_qty = max_quote_qty * (10 ** market.market_state.decimals) 110 max_base_qty = max_base_qty * (10 ** market.market_state.decimals) 111 112 if(binary_second_outcome and size_format == SizeFormat.PAYOUT and side == Side.BUY and (max_base_qty - max_quote_qty) < market.market_store_state.min_new_order_quote_size): 113 raise Exception(f'The resulting STAKE size for this order is below the market minimum. Stake: {max_base_qty - max_quote_qty}, Minimum stake: {market.market_store_state.min_new_order_quote_size}') 114 115 116 if((not binary_second_outcome) and max_quote_qty < market.market_store_state.min_new_order_quote_size): 117 raise Exception(f'The resulting STAKE size for this order is below the market minimum. Stake: {max_quote_qty}, Minimum stake: {market.market_store_state.min_new_order_quote_size}') 118 119 if(max_base_qty < market.market_store_state.min_new_order_base_size): 120 raise Exception(f'The resulting PAYOUT size for this order is below the market minimum. Payout: {max_base_qty}, Minimum payout: {market.market_store_state.min_new_order_base_size}')
def
check_user_permission_and_quote_token_limit_exceeded( market: pyaver.market.AverMarket, user_market_state: pyaver.data_classes.UserMarketState, size: float, limit_price: float, size_format: pyaver.enums.SizeFormat)
123def check_user_permission_and_quote_token_limit_exceeded(market: AverMarket, user_market_state: UserMarketState, size: float, limit_price: float, size_format: SizeFormat): 124 balance_required = size * limit_price if size_format == SizeFormat.PAYOUT else size 125 pmf = market.market_state.permissioned_market_flag 126 127 if((not pmf) or (pmf and user_market_state.user_verification_account is not None)): 128 quote_tokens_limit = market.market_state.max_quote_tokens_in 129 elif(pmf and user_market_state.user_verification_account is None): 130 quote_tokens_limit = market.market_state.max_quote_tokens_in_permission_capped 131 else: 132 raise Exception(f'This wallet does not have the required permissions to interact with this market.') 133 134 if((balance_required + user_market_state.net_quote_tokens_in) > quote_tokens_limit): 135 raise Exception(f'This order would lead to the maximum number of tokens for this market being exceeded. Please adjust your order to remain within market limits. Tokens required for this order {balance_required}; Remaining tokens until limit reached: {quote_token_limit - user_market_state.net_quote_tokens_in}')
def
check_correct_uma_market_match( user_market_state: pyaver.data_classes.UserMarketState, market: pyaver.market.AverMarket)
144def check_cancel_order_market_status(market_status: MarketStatus): 145 invalid_statuses = [MarketStatus.INITIALIZED, MarketStatus.RESOLVED, MarketStatus.VOIDED, MarketStatus.UNINITIALIZED, MarketStatus.CEASED_CRANKED_CLOSED, MarketStatus.TRADING_CEASED] 146 147 if(market_status in invalid_statuses): 148 raise Exception(f'The current market status does not permit this action. Market status {market_status}')
def
check_outcome_has_orders( outcome_id: int, user_market_state: pyaver.data_classes.UserMarketState)