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

Add AgentMarket.get_most_recent_trade_datetime #512

Merged
merged 7 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions prediction_market_agent_tooling/markets/agent_market.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,6 @@ def get_user_balance(user_id: str) -> float:
@staticmethod
def get_user_id(api_keys: APIKeys) -> str:
raise NotImplementedError("Subclasses must implement this method")

def get_most_recent_trade_datetime(self, user_id: str) -> DatetimeUTC | None:
raise NotImplementedError("Subclasses must implement this method")
15 changes: 15 additions & 0 deletions prediction_market_agent_tooling/markets/omen/omen.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ def liquidate_existing_positions(
amount=token_amount,
auto_withdraw=False,
web3=web3,
api_keys=api_keys,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

another fix for a local chain test - not sure how it was passing before!

)

def place_bet(
Expand Down Expand Up @@ -658,6 +659,20 @@ def get_user_balance(user_id: str) -> float:
def get_user_id(api_keys: APIKeys) -> str:
return api_keys.bet_from_address

def get_most_recent_trade_datetime(self, user_id: str) -> DatetimeUTC | None:
sgh = OmenSubgraphHandler()
trades = sgh.get_trades(
sort_by_field=sgh.trades_subgraph.FpmmTrade.creationTimestamp,
sort_direction="desc",
limit=1,
better_address=Web3.to_checksum_address(user_id),
market_id=Web3.to_checksum_address(self.id),
)
if not trades:
return None

return trades[0].creation_datetime


def get_omen_user_url(address: ChecksumAddress) -> str:
return f"https://gnosisscan.io/address/{address}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ def get_user_positions(

def get_trades(
self,
limit: int | None = None,
better_address: ChecksumAddress | None = None,
start_time: DatetimeUTC | None = None,
end_time: t.Optional[DatetimeUTC] = None,
Expand All @@ -554,6 +555,8 @@ def get_trades(
type_: t.Literal["Buy", "Sell"] | None = None,
market_opening_after: DatetimeUTC | None = None,
collateral_amount_more_than: Wei | None = None,
sort_by_field: FieldPath | None = None,
sort_direction: str | None = None,
) -> list[OmenBet]:
if not end_time:
end_time = utcnow()
Expand All @@ -579,8 +582,17 @@ def get_trades(
if collateral_amount_more_than is not None:
where_stms.append(trade.collateralAmount > collateral_amount_more_than)

# These values can not be set to `None`, but they can be omitted.
optional_params = {}
if sort_by_field is not None:
optional_params["orderBy"] = sort_by_field
if sort_direction is not None:
optional_params["orderDirection"] = sort_direction

trades = self.trades_subgraph.Query.fpmmTrades(
first=sys.maxsize, where=where_stms
first=limit if limit else sys.maxsize,
where=where_stms,
**optional_params,
)
fields = self._get_fields_for_bets(trades)
result = self.sg.query_json(fields)
Expand Down
32 changes: 32 additions & 0 deletions tests/markets/omen/test_omen.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import sys

import numpy as np
import pytest
from eth_account import Account
Expand Down Expand Up @@ -289,3 +291,33 @@ def test_calculate_marginal_prices(
expected_marginal_prices: list[xDai] | None,
) -> None:
assert calculate_marginal_prices(outcome_token_amounts) == expected_marginal_prices


def test_get_most_recent_trade_datetime() -> None:
"""
Tests that `get_most_recent_trade_datetime` returns the correct datetime
from all possible trade datetimes.
"""
market = OmenAgentMarket.from_data_model(pick_binary_market())
user_id = Web3.to_checksum_address(
"0x2DD9f5678484C1F59F97eD334725858b938B4102"
) # A user with trade history

sgh = OmenSubgraphHandler()
market_id = Web3.to_checksum_address("0x1e0e1d092bffebfb4fa90eeba7bfeddcebc9751c")
trades: list[OmenBet] = sgh.get_trades(
limit=sys.maxsize,
better_address=user_id,
market_id=market_id,
)
market = OmenAgentMarket.get_binary_market(id=market_id)
assert len(trades) > 2, "We have made multiple trades in this market"

assert len(set(trade.creation_datetime for trade in trades)) == len(
trades
), "All trades have unique timestamps"
most_recent_trade_0 = max(trades, key=lambda x: x.creation_datetime)
most_recent_trade_datetime_1 = check_not_none(
market.get_most_recent_trade_datetime(user_id=user_id)
)
assert most_recent_trade_0.creation_datetime == most_recent_trade_datetime_1
22 changes: 10 additions & 12 deletions tests_integration_with_local_chain/markets/omen/test_omen.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import os
import time
from datetime import timedelta
from unittest.mock import patch
Expand Down Expand Up @@ -316,24 +315,23 @@ def test_omen_buy_and_sell_outcome(
outcome_str = get_bet_outcome(outcome)
bet_amount = market.get_bet_amount(amount=0.4)

# TODO hack until https://github.com/gnosis/prediction-market-agent-tooling/issues/266 is complete
os.environ[
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Issue has been fixed. I picked up on this as I initially added a test here, but then moved it to tests/markets/omen/test_omen.py. Will just leave this code-tidy here 😃

"BET_FROM_PRIVATE_KEY"
] = test_keys.bet_from_private_key.get_secret_value()
api_keys = APIKeys()

def get_market_outcome_tokens() -> TokenAmount:
return market.get_token_balance(
user_id=api_keys.bet_from_address,
user_id=test_keys.bet_from_address,
outcome=outcome_str,
web3=local_web3,
)

# Check our wallet has sufficient funds
balances = get_balances(address=api_keys.bet_from_address, web3=local_web3)
balances = get_balances(address=test_keys.bet_from_address, web3=local_web3)
assert balances.xdai + balances.wxdai > bet_amount.amount

buy_id = market.place_bet(outcome=outcome, amount=bet_amount, web3=local_web3)
buy_id = market.place_bet(
outcome=outcome,
amount=bet_amount,
web3=local_web3,
api_keys=test_keys,
)

# Check that we now have a position in the market.
outcome_tokens = get_market_outcome_tokens()
Expand All @@ -343,7 +341,7 @@ def get_market_outcome_tokens() -> TokenAmount:
outcome=outcome,
amount=outcome_tokens,
web3=local_web3,
api_keys=api_keys,
api_keys=test_keys,
)

# Check that we have sold our entire stake in the market.
Expand All @@ -355,7 +353,7 @@ def get_market_outcome_tokens() -> TokenAmount:
sell_tx = local_web3.eth.get_transaction(HexStr(sell_id))
for tx in [buy_tx, sell_tx]:
assert tx is not None
assert tx["from"] == api_keys.bet_from_address
assert tx["from"] == test_keys.bet_from_address


def test_deposit_and_withdraw_wxdai(local_web3: Web3, test_keys: APIKeys) -> None:
Expand Down
Loading