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.')
def check_sufficient_lamport_balance(user_balance_state: pyaver.data_classes.UserBalanceState)
10def check_sufficient_lamport_balance(user_balance_state: UserBalanceState):
11    if(user_balance_state.lamport_balance < 5000):
12        raise Exception(f'Payer has insufficient lamports. Lamport balance: {user_balance_state.lamport_balance}')
def check_market_active_pre_event(market_status: pyaver.enums.MarketStatus)
14def check_market_active_pre_event(market_status: MarketStatus):
15    if(market_status != MarketStatus.ACTIVE_PRE_EVENT):
16        raise Exception(f'The current market status does not permit this action. Market status {market_status}')
def check_uhl_self_excluded(uhl: pyaver.user_host_lifetime.UserHostLifetime)
18def check_uhl_self_excluded(uhl: UserHostLifetime):
19    if(uhl.user_host_lifetime_state.is_self_excluded_until):
20        raise Exception('This user is self excluded at this time.')
def check_user_market_full(user_market_state: pyaver.data_classes.UserMarketState)
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}')
def check_limit_price_error(limit_price: float, market: pyaver.market.AverMarket)
26def check_limit_price_error(limit_price: float, market: AverMarket):
27    one_in_market_decimals = 10 ** market.market_state.decimals
28    if(limit_price > one_in_market_decimals):
29        raise Exception(f'Limit prices must be in the range 0 to 1 USDC (0 - 1,000,000). Value provided: {limit_price}')
def check_price_error(limit_price: float, side: pyaver.enums.Side)
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}')
def check_outcome_outside_space(outcome_id: int, market: pyaver.market.AverMarket)
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)
140def check_correct_uma_market_match(user_market_state: UserMarketState, market: AverMarket):
141    if(user_market_state.market.to_base58() != market.market_pubkey.to_base58()):
142        raise Exception('Aver Market is not as expected when placing order')
def check_cancel_order_market_status(market_status: pyaver.enums.MarketStatus)
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_order_exists( user_market_state: pyaver.data_classes.UserMarketState, order_id: int)
150def check_order_exists(user_market_state: UserMarketState, order_id: int):
151    for o in user_market_state.orders:
152        if o.order_id - order_id == 0:
153            return
154    raise Exception(f'No order at order_id {order_id} was found for this market.')
def check_outcome_position_amount_error(user_market_state: pyaver.data_classes.UserMarketState)
157def check_outcome_position_amount_error(user_market_state: UserMarketState):
158    pass
def check_outcome_has_orders( outcome_id: int, user_market_state: pyaver.data_classes.UserMarketState)
160def check_outcome_has_orders(outcome_id: int, user_market_state: UserMarketState):
161    for o in user_market_state.orders:
162        if(o.outcome_id == outcome_id):
163            return
164    raise Exception(f'No open orders found for outcome {outcome_id} in this market.')