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

Refactor prediction_market_agent_tooling/markets #23

Merged
merged 5 commits into from
Feb 21, 2024
Merged

Conversation

evangriffiths
Copy link
Contributor

@evangriffiths evangriffiths commented Feb 20, 2024

Just a refactor, no functional changes. Directory structure before:

% tree             
.
├── prediction_market_agent_tooling
│   ├── markets
│   │   ├── data_models.py
│   │   ├── manifold.py
│   │   ├── markets.py
│   │   └── omen.py

after:

% tree
.
├── prediction_market_agent_tooling
│   ├── markets
│   │   ├── agent_market.py
│   │   ├── data_models.py
│   │   ├── manifold
│   │   │   ├── api.py
│   │   │   ├── data_models.py
│   │   │   └── manifold.py
│   │   ├── markets.py
│   │   └── omen
│   │       ├── data_models.py
│   │       └── omen.py

Each market type now has a class derived from AgentMarket that is used to take actions. Now if you want to add support for a new market, you only have to create a new directory under markets and implement this new derived class (and also add the market to the MARKET_TYPE_MAP).

Unfortunately there isn't a clean separation in Omen between the API functions and the OmenAgentMarket class, so they both have to live inside omen.py to avoid circular import issues. This can fix fixed later on if desired.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Introduced the AgentMarket class for a unified market template across prediction markets.
    • Added new data models for Manifold and Omen markets to facilitate interaction with market data.
  • Refactor
    • Refactored betting logic in binary markets by integrating it directly into the AgentMarket class.
    • Simplified market type handling and retrieval logic with AgentMarket subclasses for Manifold and Omen markets.
  • Bug Fixes
    • Updated import statements across various files to reflect new module paths and class locations.
  • Documentation
    • Removed unused imports, classes, methods, and docstrings to clean up the codebase.

Copy link

coderabbitai bot commented Feb 20, 2024

Walkthrough

The recent updates focus on refactoring and reorganizing the prediction market agent tooling, particularly around the handling and interaction with Manifold and Omen prediction markets. Major changes include the introduction of the AgentMarket class to streamline betting operations, reorganization of data models, and adjustments in import paths to reflect these structural changes. This overhaul simplifies the codebase, aiming for clearer, more direct interactions with market data and operations.

Changes

File(s) Summary
examples/monitor/monitor.py
prediction_market_agent_tooling/.../agent_example.py
prediction_market_agent_tooling/monitor/markets/manifold.py
tests/deploy/test_deploy.py
tests/markets/test_manifold.py
tests/markets/test_omen.py
Updated import statements to reflect new module paths and structural changes.
prediction_market_agent_tooling/deploy/agent.py Refactored betting logic by removing place_bet and integrating betting directly into AgentMarket. Removed get_tiny_bet function.
prediction_market_agent_tooling/markets/agent_market.py
prediction_market_agent_tooling/markets/manifold/manifold.py
prediction_market_agent_tooling/markets/omen/omen.py
Introduced AgentMarket classes for Manifold and Omen markets, enabling streamlined predictions and betting operations.
prediction_market_agent_tooling/markets/data_models.py Removed various classes, methods, and imports related to market data models.
prediction_market_agent_tooling/markets/manifold/api.py
prediction_market_agent_tooling/markets/manifold/data_models.py
Reorganized codebase to better structure Manifold data models and updated import paths accordingly.
prediction_market_agent_tooling/markets/markets.py Refactored to use AgentMarket subclasses for market type handling and retrieval.
prediction_market_agent_tooling/markets/omen/data_models.py Defined OmenMarket data model for Omen prediction markets.
scripts/bet_omen.py Updated to use OmenAgentMarket for market operations.

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: 10

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between d226831 and 6de6c17.
Files selected for processing (16)
  • examples/monitor/monitor.py (1 hunks)
  • prediction_market_agent_tooling/deploy/agent.py (2 hunks)
  • prediction_market_agent_tooling/deploy/agent_example.py (1 hunks)
  • prediction_market_agent_tooling/markets/agent_market.py (1 hunks)
  • prediction_market_agent_tooling/markets/data_models.py (2 hunks)
  • prediction_market_agent_tooling/markets/manifold/api.py (1 hunks)
  • prediction_market_agent_tooling/markets/manifold/data_models.py (1 hunks)
  • prediction_market_agent_tooling/markets/manifold/manifold.py (1 hunks)
  • prediction_market_agent_tooling/markets/markets.py (1 hunks)
  • prediction_market_agent_tooling/markets/omen/data_models.py (1 hunks)
  • prediction_market_agent_tooling/markets/omen/omen.py (17 hunks)
  • prediction_market_agent_tooling/monitor/markets/manifold.py (1 hunks)
  • scripts/bet_omen.py (3 hunks)
  • tests/deploy/test_deploy.py (1 hunks)
  • tests/markets/test_manifold.py (1 hunks)
  • tests/markets/test_omen.py (3 hunks)
Additional comments: 7
tests/markets/test_manifold.py (1)
  • 4-7: The updated import statements correctly reflect the structural changes in the codebase, ensuring that the specific functions pick_binary_market and place_bet are directly imported from prediction_market_agent_tooling.markets.manifold.api. This change aligns with the PR objectives to streamline the codebase and improve maintainability.
prediction_market_agent_tooling/markets/manifold/data_models.py (5)
  • 21-53: The ManifoldMarket class is well-structured and uses appropriate types for its fields. However, ensure that the p field (line 44), representing probability, is always within the range [0, 1]. This might require additional validation logic.

Consider adding a validator method within the ManifoldMarket class to ensure p is within the expected range.

  • 54-66: The method is_resolved_non_cancelled provides a clear way to check if a market is resolved and not cancelled. This is a good example of encapsulating logic within the model for maintainability and readability.
  • 72-76: The ProfitCached model uses Mana for its fields, which is consistent with the domain model. Ensure that the Mana type correctly handles the precision required for financial calculations.
  • 107-111: The ManifoldBetFills model uses Decimal for the shares field, which is appropriate for financial calculations. Ensure consistency in using Decimal for all financial-related fields across models.
  • 166-186: The ManifoldContractMetric model is comprehensive and uses appropriate types for its fields. Ensure that the totalShares dictionary's keys and values are correctly handled in all use cases, especially considering the dynamic nature of dictionary keys.
prediction_market_agent_tooling/markets/omen/omen.py (1)
  • 56-61: The static method get_binary_markets in the OmenAgentMarket class is a good example of providing a clear interface for retrieving market data. Ensure that the get_omen_binary_markets function it calls is correctly implemented and handles potential errors or edge cases.

Comment on lines +13 to +15
market = pick_binary_market()
print("Placing bet on market:", market.question)
manifold.place_bet(mana_type(0.01), market.id, True)
place_bet(mana_type(1), market.id, True)
Copy link

Choose a reason for hiding this comment

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

The usage of pick_binary_market to select a market and then placing a bet on it using place_bet demonstrates a clear and straightforward test of the functionality. However, consider adding more comprehensive tests to cover edge cases or failure scenarios to ensure robustness.

Consider adding tests that cover various scenarios, including invalid market IDs, handling of API failures, and verification of the bet placement outcome.

Comment on lines +16 to +18
class ManifoldPool(BaseModel):
NO: float
YES: float
Copy link

Choose a reason for hiding this comment

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

The ManifoldPool class defines NO and YES as float. Consider using Decimal for financial calculations to avoid floating-point arithmetic issues.

-    NO: float
-    YES: float
+    NO: Decimal
+    YES: Decimal

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
class ManifoldPool(BaseModel):
NO: float
YES: float
class ManifoldPool(BaseModel):
NO: Decimal
YES: Decimal

Comment on lines +79 to +104
class ManifoldUser(BaseModel):
"""
https://docs.manifold.markets/api#get-v0userusername
"""

id: str
createdTime: datetime
name: str
username: str
url: str
avatarUrl: t.Optional[str] = None
bio: t.Optional[str] = None
bannerUrl: t.Optional[str] = None
website: t.Optional[str] = None
twitterHandle: t.Optional[str] = None
discordHandle: t.Optional[str] = None
isBot: t.Optional[bool] = None
isAdmin: t.Optional[bool] = None
isTrustworthy: t.Optional[bool] = None
isBannedFromPosting: t.Optional[bool] = None
userDeleted: t.Optional[bool] = None
balance: Mana
totalDeposits: Mana
lastBetTime: t.Optional[datetime] = None
currentBettingStreak: t.Optional[int] = None
profitCached: ProfitCached
Copy link

Choose a reason for hiding this comment

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

The ManifoldUser model includes optional fields for various user attributes. Consider adding documentation or comments to clarify under what conditions these fields might be None. This can improve the maintainability of the code by making it easier for future developers to understand the data model.

Comment on lines +114 to +120
class ManifoldBetFees(BaseModel):
platformFee: Decimal
liquidityFee: Decimal
creatorFee: Decimal

def get_total(self) -> Decimal:
return Decimal(sum([self.platformFee, self.liquidityFee, self.creatorFee]))
Copy link

Choose a reason for hiding this comment

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

The method get_total in the ManifoldBetFees model is a good example of encapsulating logic within the model. Consider adding error handling for potential arithmetic issues, such as overflow or underflow, when summing the fees.

Comment on lines +123 to +163
class ManifoldBet(BaseModel):
"""
https://docs.manifold.markets/api#get-v0bets
"""

shares: Decimal
probBefore: Probability
isFilled: t.Optional[bool] = None
probAfter: Probability
userId: str
amount: Mana
contractId: str
id: str
fees: ManifoldBetFees
isCancelled: t.Optional[bool] = None
loanAmount: Mana
orderAmount: t.Optional[Mana] = None
fills: t.Optional[list[ManifoldBetFills]] = None
createdTime: datetime
outcome: str

def get_resolved_boolean_outcome(self) -> bool:
outcome = Resolution(self.outcome)
if outcome == Resolution.YES:
return True
elif outcome == Resolution.NO:
return False
else:
should_not_happen(f"Unexpected bet outcome string, '{outcome.value}'.")

def get_profit(self, market_outcome: bool) -> ProfitAmount:
profit = (
self.shares - self.amount
if self.get_resolved_boolean_outcome() == market_outcome
else -self.amount
)
profit -= self.fees.get_total()
return ProfitAmount(
amount=profit,
currency=Currency.Mana,
)
Copy link

Choose a reason for hiding this comment

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

The ManifoldBet model's method get_profit calculates the profit correctly. However, consider adding more detailed documentation to explain the calculation, especially the logic behind subtracting self.amount and adjusting by fees. This can improve code readability and maintainability.

Comment on lines 18 to 54
class OmenAgentMarket(AgentMarket):
"""
Omen's market class that can be used by agents to make predictions.
"""

currency: Currency = Currency.xDai
collateral_token_contract_address_checksummed: ChecksumAddress
market_maker_contract_address_checksummed: ChecksumAddress

def get_tiny_bet_amount(self) -> BetAmount:
return BetAmount(amount=Decimal(0.00001), currency=self.currency)

def place_bet(
self, outcome: bool, amount: BetAmount, omen_auto_deposit: bool = True
) -> None:
if amount.currency != self.currency:
raise ValueError(f"Omen bets are made in xDai. Got {amount.currency}.")
amount_xdai = xDai(amount.amount)
keys = APIKeys()
binary_omen_buy_outcome_tx(
amount=check_not_none(amount_xdai),
from_address=check_not_none(keys.bet_from_address),
from_private_key=check_not_none(keys.bet_from_private_key),
market=self,
binary_outcome=outcome,
auto_deposit=omen_auto_deposit,
)

@staticmethod
def from_data_model(model: OmenMarket) -> "OmenAgentMarket":
return OmenAgentMarket(
id=model.id,
question=model.title,
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,
)
Copy link

Choose a reason for hiding this comment

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

The OmenAgentMarket class introduces methods for handling bets in Omen markets. Ensure that the place_bet method (lines 30-44) correctly handles the currency check and uses secure practices for interacting with external contracts. Consider adding error handling for the external calls to binary_omen_buy_outcome_tx.

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: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 6de6c17 and 60aa39c.
Files selected for processing (2)
  • prediction_market_agent_tooling/deploy/agent.py (2 hunks)
  • prediction_market_agent_tooling/markets/manifold/api.py (1 hunks)
Files skipped from review as they are similar to previous changes (2)
  • prediction_market_agent_tooling/deploy/agent.py
  • prediction_market_agent_tooling/markets/manifold/api.py

)

@staticmethod
def from_data_model(model: ManifoldMarket) -> "ManifoldAgentMarket":
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this method be defined as NonImplemented in AgentMarket?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No it doesn't have to be - these methods are only intended to be called inside the respective markets// modules - not from the base class

Manifold's market class that can be used by agents to make predictions.
"""

currency: Currency = Currency.Mana
Copy link
Contributor

Choose a reason for hiding this comment

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

This could be classvar to avoid mis-initialisation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there an easy way to do this for pydantic classes?

Copy link
Contributor

Choose a reason for hiding this comment

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

t.ClassVar[Currency] = Currency. Mana

should work, but will need the same change in the parent class too

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah nice. So it doesn't fail on initialisation, but it does fail mypy

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: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 60aa39c and 632bb5d.
Files selected for processing (4)
  • prediction_market_agent_tooling/markets/agent_market.py (1 hunks)
  • prediction_market_agent_tooling/markets/manifold/manifold.py (1 hunks)
  • prediction_market_agent_tooling/markets/omen/omen.py (17 hunks)
  • prediction_market_agent_tooling/monitor/monitor_app.py (1 hunks)
Files skipped from review as they are similar to previous changes (3)
  • prediction_market_agent_tooling/markets/agent_market.py
  • prediction_market_agent_tooling/markets/manifold/manifold.py
  • prediction_market_agent_tooling/markets/omen/omen.py
Additional comments: 2
prediction_market_agent_tooling/monitor/monitor_app.py (2)
  • 9-9: The import statement for get_authenticated_user has been updated to reflect the new module location. This change is consistent with the PR's objective of reorganizing the codebase for better maintainability and readability. Ensure that all references to get_authenticated_user throughout the codebase have been updated to match this new import path.
Verification successful

The verification process confirms that the import statement for get_authenticated_user has been correctly updated in monitor_app.py, and there are no instances of the old import path remaining in the codebase. This change aligns with the PR's objective of reorganizing the codebase for better maintainability and readability.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Search for old import paths that might still be in use. Expecting no results.
rg --type py 'from prediction_market_agent_tooling.markets.api import get_authenticated_user'
# Confirm the new import path is used consistently across the codebase.
rg --type py 'from prediction_market_agent_tooling.markets.manifold.api import get_authenticated_user'

Length of output: 343

* 6-12: > 📝 **NOTE** > This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [1-48]

Overall, the file monitor_app.py appears to be correctly updated in line with the PR's objectives, particularly concerning the reorganization of code and updating of import statements. It's important to ensure that the refactor does not introduce regressions, especially in the functionality related to market and agent monitoring. Comprehensive testing should be conducted to verify that the tooling behaves as expected post-refactor.

@evangriffiths evangriffiths merged commit f52a2d2 into main Feb 21, 2024
6 checks passed
@evangriffiths evangriffiths deleted the evan/refactor branch February 21, 2024 11:38
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