Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to change deployed agent's bet strategy #53

Merged
merged 3 commits into from
Feb 26, 2024
Merged

Conversation

kongzii
Copy link
Contributor

@kongzii kongzii commented Feb 26, 2024

Solves #51

Summary by CodeRabbit

  • New Features
    • Introduced dynamic bet amount calculation based on market conditions.
    • Added functionality to calculate minimum bet amounts for winning in prediction markets.
    • Enhanced market and bet models with probability calculations and improved type hinting.
  • Bug Fixes
    • Fixed the fixed bet amount issue by replacing it with a dynamic calculation method.
  • Tests
    • Added tests for new betting calculation functionality across different market types and scenarios.

Copy link

coderabbitai bot commented Feb 26, 2024

Warning

Rate Limit Exceeded

@kongzii has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 14 seconds before requesting another review.

How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.
Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.
Please see our FAQ for further information.

Commits Files that changed from the base of the PR and between a46fc5c and 8d5966e.

Walkthrough

The recent updates enhance the prediction market agent tooling by introducing a dynamic bet amount calculation, adding probability calculations for market outcomes, and implementing methods for determining the minimum bet required to win a specified amount. These changes improve the agent's adaptability to market conditions and its ability to calculate bets more precisely, thereby refining its decision-making process in prediction markets.

Changes

File(s) Change Summary
.../deploy/agent.py Added calculate_bet_amount method to dynamically calculate bet amounts.
.../markets/agent_market.py, .../markets/omen/data_models.py, .../markets/omen/omen.py, .../markets/manifold/manifold.py Introduced probability calculations (p_yes, p_no) and improved outcome retrieval.
.../markets/bets.py New file introducing functions for calculating minimum bet amounts for winning in prediction markets.
.../markets/manifold/data_models.py, .../markets/omen/data_models.py Modified BET_AMOUNT_CURRENCY declaration and added type hinting with t.ClassVar.
tests/markets/test_bets.py New tests for validating minimum bet calculations across various market scenarios.

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 8

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between b5a119c and a46fc5c.
Files selected for processing (8)
  • prediction_market_agent_tooling/deploy/agent.py (3 hunks)
  • prediction_market_agent_tooling/markets/agent_market.py (3 hunks)
  • prediction_market_agent_tooling/markets/bets.py (1 hunks)
  • prediction_market_agent_tooling/markets/manifold/data_models.py (1 hunks)
  • prediction_market_agent_tooling/markets/manifold/manifold.py (2 hunks)
  • prediction_market_agent_tooling/markets/omen/data_models.py (2 hunks)
  • prediction_market_agent_tooling/markets/omen/omen.py (1 hunks)
  • tests/markets/test_bets.py (1 hunks)
Additional comments: 9
prediction_market_agent_tooling/markets/bets.py (1)
  • 18-24: The function minimum_bet_to_win_manifold correctly handles the currency check and uses ceil to ensure the bet amount is an integer. This is a good practice for currencies that do not support fractional amounts. The function is well-implemented and adheres to the requirements specified for Manifold markets.
prediction_market_agent_tooling/markets/manifold/manifold.py (1)
  • 39-39: The assignment of p_yes using Probability(model.pool.YES) is a good practice as it encapsulates the probability value within a specific type, enhancing type safety and readability. Ensure that model.pool.YES is always a valid float within the range [0, 1] to maintain the integrity of the Probability type.
prediction_market_agent_tooling/markets/agent_market.py (2)
  • 21-25: The implementation of the p_no property as 1 - self.p_yes is correct and efficiently calculates the complementary probability. This approach is simple and effective for binary outcomes.
  • 40-46: The get_outcome_str method correctly handles the retrieval of outcomes by index with appropriate error handling for index out of range errors. The error message is clear and informative, aiding in debugging if an incorrect index is used.
tests/markets/test_bets.py (1)
  • 47-70: The test cases for test_minimum_bet_to_win_manifold are correctly designed and include assertions that directly compare the calculated minimum bet against an expected value. This approach is appropriate and ensures the function's correctness across different scenarios.
prediction_market_agent_tooling/markets/manifold/data_models.py (1)
  • 26-26: The use of t.ClassVar for BET_AMOUNT_CURRENCY is a good practice as it clearly indicates that this variable is intended to be a class-level constant, not an instance variable. This enhances readability and maintainability of the code.
prediction_market_agent_tooling/deploy/agent.py (1)
  • 130-130: The integration of calculate_bet_amount in the run method to determine the bet amount dynamically is a significant improvement over a fixed bet amount. This change allows for more flexible and potentially more profitable betting strategies based on market conditions.
prediction_market_agent_tooling/markets/omen/data_models.py (2)
  • 42-43: The introduction of BET_AMOUNT_CURRENCY as a class variable is a good practice, clearly indicating the currency used for bet amounts in Omen markets. This enhances code readability and maintainability.
  • 78-87: The properties p_yes and p_no for calculating probabilities are correctly implemented, with p_no being the complement of p_yes. This approach is efficient and simplifies the calculation of probabilities for binary outcomes. Ensure that the outcomeTokenProbabilities list is always correctly populated and that the index for OMEN_TRUE_OUTCOME is valid.

@@ -58,6 +58,7 @@ def from_data_model(model: OmenMarket) -> "OmenAgentMarket":
outcomes=model.outcomes,
collateral_token_contract_address_checksummed=model.collateral_token_contract_address_checksummed,
market_maker_contract_address_checksummed=model.market_maker_contract_address_checksummed,
p_yes=model.p_yes,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

The verification process reveals that the OmenAgentMarket.from_data_model method's old signature is still being used in multiple locations within the codebase, despite the addition of the p_yes parameter. This suggests that not all parts of the codebase have been updated to accommodate the new method signature, which could potentially lead to runtime errors. Therefore, the review comment highlighting the need to ensure all calls to this method have been updated is validated by these findings.

Analysis chain

The addition of the p_yes parameter to the from_data_model method in the OmenAgentMarket class is a significant change. It's important to ensure that all calls to this method throughout the codebase have been updated to include this new parameter. Additionally, consider adding type annotations for the new parameter to improve code readability and maintainability.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Search to find files that import OmenAgentMarket. Expecting list of dependent files.
rg --type py 'from .*omen import OmenAgentMarket'
# Search old signature to find omissions. Expecting no results.
ast-grep --lang python --pattern $'OmenAgentMarket.from_data_model($_)'
# Search new signature to validate usage. Expecting list of locations where the new signature is used.
ast-grep --lang python --pattern $'OmenAgentMarket.from_data_model($_, $_)'

Length of output: 825


When introducing new parameters like p_yes in the from_data_model method, it's crucial to update the corresponding documentation and examples to reflect these changes. This helps ensure that the codebase remains accessible to new developers and maintains consistency in documentation.

Comment on lines 58 to 64
outcomes=model.outcomes,
collateral_token_contract_address_checksummed=model.collateral_token_contract_address_checksummed,
market_maker_contract_address_checksummed=model.market_maker_contract_address_checksummed,
p_yes=model.p_yes,
)

@staticmethod
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [1-1]

Ensure that all external dependencies and modules imported at the beginning of the file are used within the module. Unused imports can lead to confusion and unnecessary code bloat.


📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [7-7]

The use of type annotations throughout the file is commendable as it improves code readability and helps with static type checking. Consider consistently applying type annotations to all function parameters and return types for enhanced maintainability.


📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [17-17]

The documentation comments for the OmenAgentMarket class and its methods are helpful for understanding the purpose and usage of the class. Ensure that all public methods and significant logic blocks within the class are similarly documented to maintain code readability and ease of maintenance.

Comment on lines 7 to 15
def minimum_bet_to_win(
answer: bool, amount_to_win: float, market: AgentMarket
) -> float:
"""
Estimates the minimum bet amount to win the given amount based on the current market price.
"""
share_price = market.p_yes if answer else market.p_no
bet_amount = amount_to_win / (1 / share_price - 1)
return bet_amount
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function minimum_bet_to_win correctly calculates the minimum bet amount based on the market price. However, it lacks error handling for cases where share_price might be 0, leading to a division by zero error. Consider adding validation to ensure share_price is not 0 before performing the division.

+    if share_price == 0:
+        raise ValueError("Share price cannot be zero.")

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def minimum_bet_to_win(
answer: bool, amount_to_win: float, market: AgentMarket
) -> float:
"""
Estimates the minimum bet amount to win the given amount based on the current market price.
"""
share_price = market.p_yes if answer else market.p_no
bet_amount = amount_to_win / (1 / share_price - 1)
return bet_amount
def minimum_bet_to_win(
answer: bool, amount_to_win: float, market: AgentMarket
) -> float:
"""
Estimates the minimum bet amount to win the given amount based on the current market price.
"""
share_price = market.p_yes if answer else market.p_no
if share_price == 0:
raise ValueError("Share price cannot be zero.")
bet_amount = amount_to_win / (1 / share_price - 1)
return bet_amount

Comment on lines 16 to 44
@pytest.mark.parametrize(
"outcome, market_p_yes, amount_to_win",
[
(True, 0.68, 1),
(False, 0.68, 1),
(True, 0.7, 10),
],
)
def test_minimum_bet_to_win(
outcome: bool, market_p_yes: Probability, amount_to_win: float
) -> None:
min_bet = minimum_bet_to_win(
outcome,
amount_to_win,
OmenAgentMarket(
id="id",
question="question",
outcomes=["Yes", "No"],
p_yes=market_p_yes,
collateral_token_contract_address_checksummed=WXDAI_CONTRACT_ADDRESS,
market_maker_contract_address_checksummed=Web3.to_checksum_address(
"0xf3318C420e5e30C12786C4001D600e9EE1A7eBb1"
),
),
)
assert (
min_bet / (market_p_yes if outcome else 1 - market_p_yes)
>= min_bet + amount_to_win
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test cases for test_minimum_bet_to_win are well-structured and cover different scenarios, including varying probabilities and amounts to win. However, the assertion logic seems incorrect. The formula used in the assertion does not correctly validate the expected behavior of the minimum_bet_to_win function. Consider revising the assertion to directly compare the calculated minimum bet against an expected value.

-    assert (
-        min_bet / (market_p_yes if outcome else 1 - market_p_yes)
-        >= min_bet + amount_to_win
-    )
+    # Example correction, assuming an expected_min_bet variable is defined based on the test parameters
+    assert min_bet == expected_min_bet

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
@pytest.mark.parametrize(
"outcome, market_p_yes, amount_to_win",
[
(True, 0.68, 1),
(False, 0.68, 1),
(True, 0.7, 10),
],
)
def test_minimum_bet_to_win(
outcome: bool, market_p_yes: Probability, amount_to_win: float
) -> None:
min_bet = minimum_bet_to_win(
outcome,
amount_to_win,
OmenAgentMarket(
id="id",
question="question",
outcomes=["Yes", "No"],
p_yes=market_p_yes,
collateral_token_contract_address_checksummed=WXDAI_CONTRACT_ADDRESS,
market_maker_contract_address_checksummed=Web3.to_checksum_address(
"0xf3318C420e5e30C12786C4001D600e9EE1A7eBb1"
),
),
)
assert (
min_bet / (market_p_yes if outcome else 1 - market_p_yes)
>= min_bet + amount_to_win
)
@pytest.mark.parametrize(
"outcome, market_p_yes, amount_to_win",
[
(True, 0.68, 1),
(False, 0.68, 1),
(True, 0.7, 10),
],
)
def test_minimum_bet_to_win(
outcome: bool, market_p_yes: Probability, amount_to_win: float
) -> None:
min_bet = minimum_bet_to_win(
outcome,
amount_to_win,
OmenAgentMarket(
id="id",
question="question",
outcomes=["Yes", "No"],
p_yes=market_p_yes,
collateral_token_contract_address_checksummed=WXDAI_CONTRACT_ADDRESS,
market_maker_contract_address_checksummed=Web3.to_checksum_address(
"0xf3318C420e5e30C12786C4001D600e9EE1A7eBb1"
),
),
)
# Example correction, assuming an expected_min_bet variable is defined based on the test parameters
assert min_bet == expected_min_bet

Comment on lines +116 to +120
def calculate_bet_amount(self, answer: bool, market: AgentMarket) -> BetAmount:
"""
Calculate the bet amount. By default, it returns the minimum bet amount.
"""
return market.get_tiny_bet_amount()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method calculate_bet_amount provides a default implementation that returns the minimum bet amount. This is a good starting point, but it might be beneficial to document that subclasses should override this method to implement more sophisticated bet amount calculations based on specific strategies or market conditions.

+        """
+        Note: Subclasses should override this method to implement specific bet amount calculation strategies based on market conditions.
+        """

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def calculate_bet_amount(self, answer: bool, market: AgentMarket) -> BetAmount:
"""
Calculate the bet amount. By default, it returns the minimum bet amount.
"""
return market.get_tiny_bet_amount()
def calculate_bet_amount(self, answer: bool, market: AgentMarket) -> BetAmount:
"""
Calculate the bet amount. By default, it returns the minimum bet amount.
"""
"""
Note: Subclasses should override this method to implement specific bet amount calculation strategies based on market conditions.
"""
return market.get_tiny_bet_amount()

@@ -30,6 +37,14 @@ def place_bet(self, outcome: bool, amount: BetAmount) -> None:
def get_binary_markets(limit: int) -> list["AgentMarket"]:
raise NotImplementedError("Subclasses must implement this method")

def get_outcome_str(self, outcome_index: int) -> str:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noticed this isn't used in the other class, seems like it makes more sense here along with get_outcome_index

if market.currency != Currency.Mana:
raise ValueError(f"Manifold bets are made in Mana. Got {market.currency}.")
# Manifold lowest bet is 1 Mana, so we need to ceil the result.
return ceil(minimum_bet_to_win(answer, amount_to_win, market))
Copy link
Contributor Author

@kongzii kongzii Feb 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, on https://manifold.markets/dglid/-will-the-ncaa-establish-any-new-po, with 52% p_yes, we need to bet 2 Mana in order to win 3 Mana. It doesn't make sense (except for benchmark purposes of course), to bet 1 Mana because we would get only 1 back.

Copy link
Contributor

@evangriffiths evangriffiths left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved, but with a couple comments :)))))

@@ -0,0 +1,24 @@
from math import ceil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename file to betting_strategies.py?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, renamed

return bet_amount


def minimum_bet_to_win_manifold(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we keep manifold-specific code in the manifold/ sub-directory. This function could actually be a method on the ManifoldAgentMarket class, like get_tiny_bet_amount

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, much cleaner this way, implemented!

@kongzii kongzii merged commit 19ed780 into main Feb 26, 2024
8 checks passed
@kongzii kongzii deleted the peter/change-bet branch February 26, 2024 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants