From ac0738d92b76a1f626d345ff62317fd811ee0ef9 Mon Sep 17 00:00:00 2001 From: cyberosa Date: Wed, 4 Sep 2024 11:57:10 +0200 Subject: [PATCH] fixing update liquidity amounts and missing default tokens parameter --- .../behaviours/decision_receive.py | 72 +++++++++++++++---- .../skills/decision_maker_abci/models.py | 27 ++++--- 2 files changed, 72 insertions(+), 27 deletions(-) diff --git a/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py b/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py index 2198b08e6..c16447ee2 100644 --- a/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py +++ b/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py @@ -285,14 +285,23 @@ def _get_mocked_bet(self) -> Bet: shared_state = self.shared_state question_id = shared_state.mock_question_id benchmarking_mode = self.benchmarking_mode - outcome_token_amounts = shared_state.liquidity_amounts.setdefault( + current_liquidity_dictionary = shared_state.liquidity_amounts + + # temporary solution since this situation was faced on the experiments + if len(benchmarking_mode.outcome_token_amounts) == 0: + benchmarking_mode.outcome_token_amounts = [ + 7000000000000000000, + 7000000000000000000, + ] + outcome_token_amounts = current_liquidity_dictionary.setdefault( question_id, benchmarking_mode.outcome_token_amounts ) + outcome_token_marginal_prices = shared_state.liquidity_prices.setdefault( question_id, benchmarking_mode.outcome_token_marginal_prices ) return Bet( - id="", + id=question_id, market="", title="", collateralToken="", @@ -306,14 +315,43 @@ def _get_mocked_bet(self) -> Bet: scaledLiquidityMeasure=10, ) - def _calculate_new_liquidity(self, bet_amount: int, vote: int) -> LiquidityInfo: + def _calculate_new_liquidity(self, net_bet_amount: int, vote: int) -> LiquidityInfo: """Calculate and return the new liquidity information.""" - liquidity_amounts = self.shared_state.current_liquidity_amounts - selected_type_tokens_in_pool = liquidity_amounts[vote] - opposite_vote = vote ^ 1 - other_tokens_in_pool = liquidity_amounts[opposite_vote] - new_selected = selected_type_tokens_in_pool + bet_amount - new_other = other_tokens_in_pool * selected_type_tokens_in_pool / new_selected + token_amounts = self.shared_state.current_liquidity_amounts + k = prod(token_amounts) + prices = self.shared_state.current_liquidity_prices + self.context.logger.info(f"Token prices: {prices}") + bet_per_token = net_bet_amount / BINARY_N_SLOTS + + # calculate the number of the traded tokens + if prices is None: + return 0, 0 + tokens_traded = [int(bet_per_token / prices[i]) for i in range(BINARY_N_SLOTS)] + + # get the shares for the answer that the service has selected + selected_shares = tokens_traded.pop(vote) + self.context.logger.info(f"Selected shares: {selected_shares}") + + # get the shares for the opposite answer + other_shares = tokens_traded.pop() + self.context.logger.info(f"Other shares: {other_shares}") + + # get the number of tokens in the pool for the answer that the service has selected + selected_type_tokens_in_pool = token_amounts.pop(vote) + self.context.logger.info( + f"Selected type tokens in pool: {selected_type_tokens_in_pool}" + ) + + # get the number of tokens in the pool for the opposite answer + other_tokens_in_pool = token_amounts.pop() + self.context.logger.info(f"Other tokens in pool: {other_tokens_in_pool}") + + # the OMEN market then trades the opposite tokens to the tokens of the answer that has been selected, + # preserving the balance of the pool + # here we calculate the number of shares that we get after trading the tokens for the opposite answer + new_other = other_tokens_in_pool + other_shares + new_selected = int(k / new_other) + if vote == 0: return LiquidityInfo( selected_type_tokens_in_pool, @@ -328,10 +366,19 @@ def _calculate_new_liquidity(self, bet_amount: int, vote: int) -> LiquidityInfo: new_selected, ) - def _update_liquidity_info(self, bet_amount: int, vote: int) -> LiquidityInfo: + def _update_liquidity_info(self, net_bet_amount: int, vote: int) -> LiquidityInfo: """Update the liquidity information and the prices after placing a bet for a market.""" - liquidity_info = self._calculate_new_liquidity(bet_amount, vote) - self.shared_state.current_liquidity_prices = liquidity_info.get_new_prices() + liquidity_info = self._calculate_new_liquidity(net_bet_amount, vote) + # to compute the new price we need the previous constants + prices = self.shared_state.current_liquidity_prices + liquidity_constants = [ + liquidity_info.l0_start * prices[0], + liquidity_info.l1_start * prices[1], + ] + + self.shared_state.current_liquidity_prices = liquidity_info.get_new_prices( + liquidity_constants + ) self.shared_state.current_liquidity_amounts = liquidity_info.get_end_liquidity() return liquidity_info @@ -344,7 +391,6 @@ def _is_profitable( confidence: float, ) -> Generator[None, None, Tuple[bool, int]]: """Whether the decision is profitable or not.""" - bet = ( self.sampled_bet if not self.benchmarking_mode.enabled diff --git a/packages/valory/skills/decision_maker_abci/models.py b/packages/valory/skills/decision_maker_abci/models.py index 8c23f59b6..f6f3d0c11 100644 --- a/packages/valory/skills/decision_maker_abci/models.py +++ b/packages/valory/skills/decision_maker_abci/models.py @@ -117,12 +117,11 @@ def validate_end_information(self) -> Tuple[int, int]: # return the values for type checking purposes (`mypy` would complain that they might be `None` otherwise) return self.l0_end, self.l1_end - def get_new_prices(self) -> List[float]: + def get_new_prices(self, liquidity_constants: List) -> List[float]: """Calculate and return the new prices based on the end liquidity.""" l0_end, l1_end = self.validate_end_information() - total_end_liquidity = l0_end + l1_end - new_p0 = l0_end / total_end_liquidity - new_p1 = l1_end / total_end_liquidity + new_p0 = liquidity_constants[0] / l0_end + new_p1 = liquidity_constants[1] / l1_end return [new_p0, new_p1] def get_end_liquidity(self) -> List[int]: @@ -388,11 +387,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: "tool_punishment_multiplier", kwargs, int ) self.contract_timeout: float = self._ensure("contract_timeout", kwargs, float) - self.file_hash_to_strategies: Dict[ - str, List[str] - ] = nested_list_todict_workaround( - kwargs, - "file_hash_to_strategies_json", + self.file_hash_to_strategies: Dict[str, List[str]] = ( + nested_list_todict_workaround( + kwargs, + "file_hash_to_strategies_json", + ) ) self.strategies_kwargs: Dict[str, List[Any]] = nested_list_todict_workaround( kwargs, "strategies_kwargs" @@ -404,11 +403,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: ) self.use_nevermined = self._ensure("use_nevermined", kwargs, bool) self.rpc_sleep_time: int = self._ensure("rpc_sleep_time", kwargs, int) - self.mech_to_subscription_params: Dict[ - str, Any - ] = nested_list_todict_workaround( - kwargs, - "mech_to_subscription_params", + self.mech_to_subscription_params: Dict[str, Any] = ( + nested_list_todict_workaround( + kwargs, + "mech_to_subscription_params", + ) ) self.service_endpoint = self._ensure("service_endpoint", kwargs, str) super().__init__(*args, **kwargs)