prediction-market-agent-tooling 0.51.0__tar.gz → 0.52.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/PKG-INFO +1 -1
  2. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/agent.py +5 -0
  3. prediction_market_agent_tooling-0.52.0/prediction_market_agent_tooling/markets/metaculus/data_models.py +104 -0
  4. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/metaculus/metaculus.py +5 -6
  5. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/data_models.py +9 -1
  6. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +165 -73
  7. prediction_market_agent_tooling-0.52.0/prediction_market_agent_tooling/tools/is_invalid.py +92 -0
  8. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/utils.py +3 -1
  9. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/pyproject.toml +1 -1
  10. prediction_market_agent_tooling-0.51.0/prediction_market_agent_tooling/markets/metaculus/data_models.py +0 -97
  11. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/LICENSE +0 -0
  12. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/README.md +0 -0
  13. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/debuggingcontract.abi.json +0 -0
  14. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/depositablewrapper_erc20.abi.json +0 -0
  15. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
  16. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/erc4626.abi.json +0 -0
  17. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_agentresultmapping.abi.json +0 -0
  18. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
  19. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
  20. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
  21. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
  22. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
  23. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
  24. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
  25. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_thumbnailmapping.abi.json +0 -0
  26. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/proxy.abi.json +0 -0
  27. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
  28. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
  29. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
  30. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/benchmark/utils.py +0 -0
  31. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/config.py +0 -0
  32. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
  33. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/betting_strategy.py +0 -0
  34. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/constants.py +0 -0
  35. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
  36. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
  37. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
  38. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/gtypes.py +0 -0
  39. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/jobs/__init__.py +0 -0
  40. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/jobs/jobs.py +0 -0
  41. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/jobs/jobs_models.py +0 -0
  42. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/jobs/omen/omen_jobs.py +0 -0
  43. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/loggers.py +0 -0
  44. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/agent_market.py +0 -0
  45. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/categorize.py +0 -0
  46. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/data_models.py +0 -0
  47. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
  48. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
  49. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
  50. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/manifold/manifold.py +0 -0
  51. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
  52. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/markets.py +0 -0
  53. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/metaculus/api.py +0 -0
  54. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
  55. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/omen.py +0 -0
  56. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +0 -0
  57. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +0 -0
  58. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
  59. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
  60. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +0 -0
  61. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
  62. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
  63. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/markets/manifold.py +0 -0
  64. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/markets/metaculus.py +0 -0
  65. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/markets/omen.py +0 -0
  66. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/markets/polymarket.py +0 -0
  67. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/monitor.py +0 -0
  68. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/monitor_app.py +0 -0
  69. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/monitor_settings.py +0 -0
  70. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/py.typed +0 -0
  71. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/balances.py +0 -0
  72. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
  73. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +0 -0
  74. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +0 -0
  75. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
  76. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/betting_strategies/utils.py +0 -0
  77. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/cache.py +0 -0
  78. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/contract.py +0 -0
  79. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/costs.py +0 -0
  80. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/datetime_utc.py +0 -0
  81. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/gnosis_rpc.py +0 -0
  82. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/google.py +0 -0
  83. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
  84. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/httpx_cached_client.py +0 -0
  85. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/image_gen/image_gen.py +0 -0
  86. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/image_gen/market_thumbnail_gen.py +0 -0
  87. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/ipfs/ipfs_handler.py +0 -0
  88. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
  89. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/langfuse_.py +0 -0
  90. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/langfuse_client_utils.py +0 -0
  91. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/omen/reality_accuracy.py +0 -0
  92. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
  93. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/safe.py +0 -0
  94. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/singleton.py +0 -0
  95. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/streamlit_user_login.py +0 -0
  96. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/tavily_storage/tavily_models.py +0 -0
  97. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/tavily_storage/tavily_storage.py +0 -0
  98. {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/web3_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prediction-market-agent-tooling
3
- Version: 0.51.0
3
+ Version: 0.52.0
4
4
  Summary: Tools to benchmark, deploy and monitor prediction market agents.
5
5
  Author: Gnosis
6
6
  Requires-Python: >=3.10,<3.12
@@ -66,6 +66,7 @@ from prediction_market_agent_tooling.monitor.monitor_app import (
66
66
  )
67
67
  from prediction_market_agent_tooling.tools.hexbytes_custom import HexBytes
68
68
  from prediction_market_agent_tooling.tools.ipfs.ipfs_handler import IPFSHandler
69
+ from prediction_market_agent_tooling.tools.is_invalid import is_invalid
69
70
  from prediction_market_agent_tooling.tools.is_predictable import is_predictable_binary
70
71
  from prediction_market_agent_tooling.tools.langfuse_ import langfuse_context, observe
71
72
  from prediction_market_agent_tooling.tools.utils import DatetimeUTC, utcnow
@@ -295,6 +296,7 @@ class DeployableTraderAgent(DeployableAgent):
295
296
  bet_on_n_markets_per_run: int = 1
296
297
  min_required_balance_to_operate: xDai | None = xdai_type(1)
297
298
  min_balance_to_keep_in_native_currency: xDai | None = xdai_type(0.1)
299
+ allow_invalid_questions: bool = False
298
300
 
299
301
  def __init__(
300
302
  self,
@@ -403,6 +405,9 @@ class DeployableTraderAgent(DeployableAgent):
403
405
  if not is_predictable_binary(market.question):
404
406
  return False
405
407
 
408
+ if not self.allow_invalid_questions and is_invalid(market.question):
409
+ return False
410
+
406
411
  return True
407
412
 
408
413
  def answer_binary_market(self, market: AgentMarket) -> ProbabilisticAnswer | None:
@@ -0,0 +1,104 @@
1
+ from enum import Enum
2
+ from typing import Any
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from prediction_market_agent_tooling.gtypes import Probability
7
+ from prediction_market_agent_tooling.tools.utils import DatetimeUTC
8
+
9
+
10
+ class QuestionType(str, Enum):
11
+ binary = "binary"
12
+
13
+
14
+ class AggregationItem(BaseModel):
15
+ start_time: DatetimeUTC
16
+ end_time: DatetimeUTC | None
17
+ forecast_values: list[float] | None
18
+ forecaster_count: int
19
+ interval_lower_bounds: list[float] | None
20
+ centers: list[float] | None
21
+ interval_upper_bounds: list[float] | None
22
+ means: list[float] | None
23
+ histogram: list[float] | None
24
+
25
+
26
+ class Aggregation(BaseModel):
27
+ history: list[AggregationItem]
28
+ latest: AggregationItem | None
29
+ score_data: dict[str, Any]
30
+
31
+
32
+ class Aggregations(BaseModel):
33
+ recency_weighted: Aggregation
34
+ unweighted: Aggregation
35
+ single_aggregation: Aggregation
36
+ metaculus_prediction: Aggregation
37
+
38
+
39
+ class MyForecast(BaseModel):
40
+ start_time: DatetimeUTC
41
+ end_time: DatetimeUTC | None
42
+ forecast_values: list[float] | None
43
+ interval_lower_bounds: list[float] | None
44
+ centers: list[float] | None
45
+ interval_upper_bounds: list[float] | None
46
+
47
+
48
+ class MyAggregation(BaseModel):
49
+ history: list[MyForecast]
50
+ latest: MyForecast | None
51
+ score_data: dict[str, Any]
52
+
53
+
54
+ class Question(BaseModel):
55
+ aggregations: Aggregations
56
+ my_forecasts: MyAggregation
57
+ type: QuestionType
58
+ possibilities: dict[str, str] | None
59
+
60
+
61
+ class MetaculusQuestion(BaseModel):
62
+ id: int
63
+ author_id: int
64
+ author_username: str
65
+ title: str
66
+ created_at: DatetimeUTC
67
+ published_at: DatetimeUTC
68
+ scheduled_close_time: DatetimeUTC
69
+ scheduled_resolve_time: DatetimeUTC
70
+ user_permission: str
71
+ comment_count: int
72
+ question: Question
73
+ # TODO add the rest of the fields https://github.com/gnosis/prediction-market-agent-tooling/issues/301
74
+
75
+ @property
76
+ def page_url(self) -> str:
77
+ return f"https://www.metaculus.com/questions/{self.id}/"
78
+
79
+ @property
80
+ def p_yes(self) -> Probability:
81
+ if self.question.type != QuestionType.binary:
82
+ raise ValueError(f"Only binary markets can have p_yes.")
83
+ if (
84
+ self.question.aggregations.recency_weighted is None
85
+ or self.question.aggregations.recency_weighted.latest is None
86
+ or self.question.aggregations.recency_weighted.latest.forecast_values
87
+ is None
88
+ ):
89
+ # If no value is provided (i.e. the question is new and has not been answered yet), we default to 0.5.
90
+ return Probability(0.5)
91
+ if len(self.question.aggregations.recency_weighted.latest.forecast_values) != 2:
92
+ raise ValueError(
93
+ f"Invalid logic, assumed that binary markets will have two forecasts, got: {self.question.aggregations.recency_weighted.latest.forecast_values}"
94
+ )
95
+ # Experimentally figured out that they store "Yes" at index 1.
96
+ return Probability(
97
+ self.question.aggregations.recency_weighted.latest.forecast_values[1]
98
+ )
99
+
100
+
101
+ class MetaculusQuestions(BaseModel):
102
+ next: str | None
103
+ previous: str | None
104
+ results: list[MetaculusQuestion]
@@ -37,13 +37,12 @@ class MetaculusAgentMarket(AgentMarket):
37
37
  question=model.title,
38
38
  outcomes=[],
39
39
  resolution=None,
40
- current_p_yes=Probability(model.community_prediction.full.p_yes),
41
- created_time=model.created_time,
42
- close_time=model.close_time,
43
- url=model.url,
40
+ current_p_yes=model.p_yes,
41
+ created_time=model.created_at,
42
+ close_time=model.scheduled_close_time,
43
+ url=model.page_url,
44
44
  volume=None,
45
- have_predicted=model.my_predictions is not None
46
- and len(model.my_predictions.predictions) > 0,
45
+ have_predicted=model.question.my_forecasts.latest is not None,
47
46
  outcome_token_pool=None,
48
47
  )
49
48
 
@@ -73,6 +73,10 @@ class Question(BaseModel):
73
73
  answerFinalizedTimestamp: t.Optional[DatetimeUTC] = None
74
74
  currentAnswer: t.Optional[str] = None
75
75
 
76
+ @property
77
+ def question_id(self) -> HexBytes:
78
+ return self.id
79
+
76
80
  @property
77
81
  def question_raw(self) -> str:
78
82
  # Based on https://github.com/protofire/omen-exchange/blob/2cfdf6bfe37afa8b169731d51fea69d42321d66c/app/src/hooks/graph/useGraphMarketMakerData.tsx#L217.
@@ -583,7 +587,7 @@ class RealityQuestion(BaseModel):
583
587
  historyHash: HexBytes | None
584
588
  updatedTimestamp: int
585
589
  contentHash: HexBytes
586
- questionId: HexBytes
590
+ questionId: HexBytes # This is the `id` on question from omen subgraph.
587
591
  answerFinalizedTimestamp: int
588
592
  currentScheduledFinalizationTimestamp: int
589
593
 
@@ -660,6 +664,10 @@ def format_realitio_question(
660
664
  template_id: int,
661
665
  ) -> str:
662
666
  """If you add a new template id here, also add to the parsing function below."""
667
+
668
+ # Escape characters for JSON troubles on Reality.eth.
669
+ question = question.replace('"', '\\"')
670
+
663
671
  if template_id == 2:
664
672
  return "␟".join(
665
673
  [
@@ -218,30 +218,45 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
218
218
 
219
219
  def _build_where_statements(
220
220
  self,
221
- creator: t.Optional[HexAddress] = None,
222
- creator_in: t.Optional[t.Sequence[HexAddress]] = None,
223
- outcomes: list[str] = OMEN_BINARY_MARKET_OUTCOMES,
224
- created_after: t.Optional[DatetimeUTC] = None,
225
- opened_before: t.Optional[DatetimeUTC] = None,
226
- opened_after: t.Optional[DatetimeUTC] = None,
227
- finalized_before: t.Optional[DatetimeUTC] = None,
228
- finalized_after: t.Optional[DatetimeUTC] = None,
229
- resolved: bool | None = None,
230
- liquidity_bigger_than: Wei | None = None,
231
- condition_id_in: list[HexBytes] | None = None,
232
- id_in: list[str] | None = None,
233
- excluded_questions: set[str] | None = None,
234
- collateral_token_address_in: tuple[ChecksumAddress, ...] | None = None,
235
- category: str | None = None,
221
+ creator: HexAddress | None,
222
+ creator_in: t.Sequence[HexAddress] | None,
223
+ outcomes: list[str],
224
+ created_after: DatetimeUTC | None,
225
+ question_opened_before: DatetimeUTC | None,
226
+ question_opened_after: DatetimeUTC | None,
227
+ question_finalized_before: DatetimeUTC | None,
228
+ question_finalized_after: DatetimeUTC | None,
229
+ question_with_answers: bool | None,
230
+ question_id: HexBytes | None,
231
+ question_id_in: list[HexBytes] | None,
232
+ question_current_answer_before: DatetimeUTC | None,
233
+ question_excluded_titles: set[str] | None,
234
+ resolved: bool | None,
235
+ liquidity_bigger_than: Wei | None,
236
+ condition_id_in: list[HexBytes] | None,
237
+ id_in: list[str] | None,
238
+ collateral_token_address_in: tuple[ChecksumAddress, ...] | None,
239
+ category: str | None,
236
240
  ) -> dict[str, t.Any]:
237
241
  where_stms: dict[str, t.Any] = {
238
242
  "isPendingArbitration": False,
239
243
  "outcomes": outcomes,
240
244
  "title_not": None,
241
- "question_": {},
242
245
  "condition_": {},
243
246
  }
244
247
 
248
+ where_stms["question_"] = self.get_omen_question_filters(
249
+ question_id=question_id,
250
+ opened_before=question_opened_before,
251
+ opened_after=question_opened_after,
252
+ finalized_before=question_finalized_before,
253
+ finalized_after=question_finalized_after,
254
+ with_answers=question_with_answers,
255
+ current_answer_before=question_current_answer_before,
256
+ question_id_in=question_id_in,
257
+ excluded_titles=question_excluded_titles,
258
+ )
259
+
245
260
  if collateral_token_address_in:
246
261
  where_stms["collateralToken_in"] = [
247
262
  x.lower() for x in collateral_token_address_in
@@ -256,11 +271,6 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
256
271
  if created_after:
257
272
  where_stms["creationTimestamp_gt"] = to_int_timestamp(created_after)
258
273
 
259
- if opened_before:
260
- where_stms["question_"]["openingTimestamp_lt"] = to_int_timestamp(
261
- opened_before
262
- )
263
-
264
274
  if liquidity_bigger_than is not None:
265
275
  where_stms["liquidityParameter_gt"] = liquidity_bigger_than
266
276
 
@@ -277,30 +287,9 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
277
287
  else:
278
288
  where_stms["resolutionTimestamp"] = None
279
289
 
280
- if opened_after:
281
- where_stms["question_"]["openingTimestamp_gt"] = to_int_timestamp(
282
- opened_after
283
- )
284
-
285
- if finalized_before:
286
- where_stms["answerFinalizedTimestamp_lt"] = to_int_timestamp(
287
- finalized_before
288
- )
289
-
290
- if finalized_after:
291
- where_stms["answerFinalizedTimestamp_gt"] = to_int_timestamp(
292
- finalized_after
293
- )
294
-
295
290
  if category:
296
291
  where_stms["category"] = category
297
292
 
298
- # `excluded_question_titles` can not be an empty list, otherwise the API bugs out and returns nothing.
299
- excluded_question_titles = [""]
300
- if excluded_questions:
301
- excluded_question_titles = [i for i in excluded_questions]
302
-
303
- where_stms["question_"]["title_not_in"] = excluded_question_titles
304
293
  return where_stms
305
294
 
306
295
  def _build_sort_params(
@@ -378,12 +367,12 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
378
367
  return self.get_omen_binary_markets(
379
368
  limit=limit,
380
369
  resolved=resolved,
381
- opened_after=opened_after,
370
+ question_opened_after=opened_after,
382
371
  liquidity_bigger_than=liquidity_bigger_than,
383
372
  sort_direction=sort_direction,
384
373
  sort_by_field=sort_by_field,
385
374
  created_after=created_after,
386
- excluded_questions=excluded_questions,
375
+ question_excluded_titles=excluded_questions,
387
376
  collateral_token_address_in=collateral_token_address_in,
388
377
  category=category,
389
378
  )
@@ -391,18 +380,22 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
391
380
  def get_omen_binary_markets(
392
381
  self,
393
382
  limit: t.Optional[int],
394
- created_after: t.Optional[DatetimeUTC] = None,
395
- opened_before: t.Optional[DatetimeUTC] = None,
396
- opened_after: t.Optional[DatetimeUTC] = None,
397
- finalized_before: t.Optional[DatetimeUTC] = None,
398
- finalized_after: t.Optional[DatetimeUTC] = None,
383
+ creator: HexAddress | None = None,
384
+ creator_in: t.Sequence[HexAddress] | None = None,
385
+ created_after: DatetimeUTC | None = None,
386
+ question_opened_before: DatetimeUTC | None = None,
387
+ question_opened_after: DatetimeUTC | None = None,
388
+ question_finalized_before: DatetimeUTC | None = None,
389
+ question_finalized_after: DatetimeUTC | None = None,
390
+ question_with_answers: bool | None = None,
391
+ question_id: HexBytes | None = None,
392
+ question_id_in: list[HexBytes] | None = None,
393
+ question_current_answer_before: DatetimeUTC | None = None,
394
+ question_excluded_titles: set[str] | None = None,
399
395
  resolved: bool | None = None,
400
- creator: t.Optional[HexAddress] = None,
401
- creator_in: t.Optional[t.Sequence[HexAddress]] = None,
402
396
  liquidity_bigger_than: Wei | None = None,
403
397
  condition_id_in: list[HexBytes] | None = None,
404
398
  id_in: list[str] | None = None,
405
- excluded_questions: set[str] | None = None, # question titles
406
399
  sort_by_field: FieldPath | None = None,
407
400
  sort_direction: str | None = None,
408
401
  outcomes: list[str] = OMEN_BINARY_MARKET_OUTCOMES,
@@ -419,14 +412,18 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
419
412
  creator_in=creator_in,
420
413
  outcomes=outcomes,
421
414
  created_after=created_after,
422
- opened_before=opened_before,
423
- opened_after=opened_after,
424
- finalized_before=finalized_before,
425
- finalized_after=finalized_after,
415
+ question_opened_before=question_opened_before,
416
+ question_opened_after=question_opened_after,
417
+ question_finalized_before=question_finalized_before,
418
+ question_finalized_after=question_finalized_after,
419
+ question_with_answers=question_with_answers,
420
+ question_id=question_id,
421
+ question_id_in=question_id_in,
422
+ question_current_answer_before=question_current_answer_before,
423
+ question_excluded_titles=question_excluded_titles,
426
424
  resolved=resolved,
427
425
  condition_id_in=condition_id_in,
428
426
  id_in=id_in,
429
- excluded_questions=excluded_questions,
430
427
  liquidity_bigger_than=liquidity_bigger_than,
431
428
  collateral_token_address_in=collateral_token_address_in,
432
429
  category=category,
@@ -644,15 +641,21 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
644
641
 
645
642
  @staticmethod
646
643
  def get_reality_question_filters(
647
- user: HexAddress | None = None,
648
- claimed: bool | None = None,
649
- current_answer_before: DatetimeUTC | None = None,
650
- finalized_before: DatetimeUTC | None = None,
651
- finalized_after: DatetimeUTC | None = None,
652
- id_in: list[str] | None = None,
653
- question_id: HexBytes | None = None,
654
- question_id_in: list[HexBytes] | None = None,
644
+ user: HexAddress | None,
645
+ claimed: bool | None,
646
+ current_answer_before: DatetimeUTC | None,
647
+ finalized_before: DatetimeUTC | None,
648
+ finalized_after: DatetimeUTC | None,
649
+ with_answers: bool | None,
650
+ question_id: HexBytes | None,
651
+ question_id_in: list[HexBytes] | None,
652
+ opened_before: t.Optional[DatetimeUTC],
653
+ opened_after: t.Optional[DatetimeUTC],
654
+ excluded_titles: set[str] | None,
655
655
  ) -> dict[str, t.Any]:
656
+ """
657
+ Be aware, both Omen subgraph and Reality subgraph are indexing questions, but their fields are a bit different.
658
+ """
656
659
  where_stms: dict[str, t.Any] = {}
657
660
 
658
661
  if user is not None:
@@ -672,6 +675,12 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
672
675
  current_answer_before
673
676
  )
674
677
 
678
+ if opened_before:
679
+ where_stms["openingTimestamp_lt"] = to_int_timestamp(opened_before)
680
+
681
+ if opened_after:
682
+ where_stms["openingTimestamp_gt"] = to_int_timestamp(opened_after)
683
+
675
684
  if finalized_before is not None:
676
685
  where_stms["answerFinalizedTimestamp_lt"] = to_int_timestamp(
677
686
  finalized_before
@@ -682,12 +691,77 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
682
691
  finalized_after
683
692
  )
684
693
 
685
- if id_in is not None:
686
- where_stms["id_in"] = id_in
694
+ if with_answers is not None:
695
+ if with_answers:
696
+ where_stms["answerFinalizedTimestamp_not"] = None
697
+ else:
698
+ where_stms["answerFinalizedTimestamp"] = None
687
699
 
688
700
  if question_id_in is not None:
701
+ # Be aware: On Omen subgraph, question's `id` represents `questionId` on reality subgraph. And `id` on reality subraph is just a weird concat of multiple things from the question.
689
702
  where_stms["questionId_in"] = [x.hex() for x in question_id_in]
690
703
 
704
+ if excluded_titles:
705
+ # Be aware: This is called `title_not_in` on Omen subgraph.
706
+ where_stms["qTitle_not_in"] = [i for i in excluded_titles]
707
+
708
+ return where_stms
709
+
710
+ @staticmethod
711
+ def get_omen_question_filters(
712
+ current_answer_before: DatetimeUTC | None,
713
+ finalized_before: DatetimeUTC | None,
714
+ finalized_after: DatetimeUTC | None,
715
+ with_answers: bool | None,
716
+ question_id: HexBytes | None,
717
+ question_id_in: list[HexBytes] | None,
718
+ opened_before: t.Optional[DatetimeUTC],
719
+ opened_after: t.Optional[DatetimeUTC],
720
+ excluded_titles: set[str] | None,
721
+ ) -> dict[str, t.Any]:
722
+ """
723
+ Be aware, both Omen subgraph and Reality subgraph are indexing questions, but their fields are a bit different.
724
+ """
725
+ where_stms: dict[str, t.Any] = {}
726
+
727
+ if question_id is not None:
728
+ where_stms["questionId"] = question_id.hex()
729
+
730
+ if current_answer_before is not None:
731
+ where_stms["currentAnswerTimestamp_lt"] = to_int_timestamp(
732
+ current_answer_before
733
+ )
734
+
735
+ if opened_before:
736
+ where_stms["openingTimestamp_lt"] = to_int_timestamp(opened_before)
737
+
738
+ if opened_after:
739
+ where_stms["openingTimestamp_gt"] = to_int_timestamp(opened_after)
740
+
741
+ if finalized_before is not None:
742
+ where_stms["answerFinalizedTimestamp_lt"] = to_int_timestamp(
743
+ finalized_before
744
+ )
745
+
746
+ if finalized_after is not None:
747
+ where_stms["answerFinalizedTimestamp_gt"] = to_int_timestamp(
748
+ finalized_after
749
+ )
750
+
751
+ if with_answers is not None:
752
+ if with_answers:
753
+ where_stms["answerFinalizedTimestamp_not"] = None
754
+ else:
755
+ where_stms["answerFinalizedTimestamp"] = None
756
+
757
+ if question_id_in is not None:
758
+ # Be aware: On Omen subgraph, question's `id` represents `questionId` on reality subgraph. And `id` on reality subraph is just a weird concat of multiple things from the question.
759
+ where_stms["id_in"] = [x.hex() for x in question_id_in]
760
+
761
+ if excluded_titles:
762
+ # Be aware: This is called `qTitle_not_in` on Omen subgraph.
763
+ where_stms["title_not_in"] = [i for i in excluded_titles]
764
+
691
765
  return where_stms
692
766
 
693
767
  def get_questions(
@@ -698,17 +772,25 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
698
772
  current_answer_before: DatetimeUTC | None = None,
699
773
  finalized_before: DatetimeUTC | None = None,
700
774
  finalized_after: DatetimeUTC | None = None,
701
- id_in: list[str] | None = None,
775
+ with_answers: bool | None = None,
702
776
  question_id_in: list[HexBytes] | None = None,
777
+ question_id: HexBytes | None = None,
778
+ opened_before: DatetimeUTC | None = None,
779
+ opened_after: DatetimeUTC | None = None,
780
+ excluded_titles: set[str] | None = None,
703
781
  ) -> list[RealityQuestion]:
704
782
  where_stms: dict[str, t.Any] = self.get_reality_question_filters(
705
783
  user=user,
706
784
  claimed=claimed,
707
785
  finalized_before=finalized_before,
708
786
  finalized_after=finalized_after,
787
+ with_answers=with_answers,
709
788
  current_answer_before=current_answer_before,
710
- id_in=id_in,
711
789
  question_id_in=question_id_in,
790
+ question_id=question_id,
791
+ opened_before=opened_before,
792
+ opened_after=opened_after,
793
+ excluded_titles=excluded_titles,
712
794
  )
713
795
  questions = self.realityeth_subgraph.Query.questions(
714
796
  first=(
@@ -738,12 +820,17 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
738
820
  self,
739
821
  limit: int | None,
740
822
  user: HexAddress | None = None,
741
- question_id: HexBytes | None = None,
823
+ question_user: HexAddress | None = None,
742
824
  question_claimed: bool | None = None,
743
- question_finalized_before: DatetimeUTC | None = None,
744
- question_finalized_after: DatetimeUTC | None = None,
745
- question_current_answer_before: DatetimeUTC | None = None,
825
+ question_opened_before: t.Optional[DatetimeUTC] = None,
826
+ question_opened_after: t.Optional[DatetimeUTC] = None,
827
+ question_finalized_before: t.Optional[DatetimeUTC] = None,
828
+ question_finalized_after: t.Optional[DatetimeUTC] = None,
829
+ question_with_answers: bool | None = None,
830
+ question_id: HexBytes | None = None,
746
831
  question_id_in: list[HexBytes] | None = None,
832
+ question_current_answer_before: DatetimeUTC | None = None,
833
+ question_excluded_titles: set[str] | None = None,
747
834
  ) -> list[RealityResponse]:
748
835
  where_stms: dict[str, t.Any] = {}
749
836
 
@@ -751,12 +838,17 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
751
838
  where_stms["user"] = user.lower()
752
839
 
753
840
  where_stms["question_"] = self.get_reality_question_filters(
841
+ user=question_user,
754
842
  question_id=question_id,
755
843
  claimed=question_claimed,
844
+ opened_before=question_opened_before,
845
+ opened_after=question_opened_after,
756
846
  finalized_before=question_finalized_before,
757
847
  finalized_after=question_finalized_after,
848
+ with_answers=question_with_answers,
758
849
  current_answer_before=question_current_answer_before,
759
850
  question_id_in=question_id_in,
851
+ excluded_titles=question_excluded_titles,
760
852
  )
761
853
 
762
854
  responses = self.realityeth_subgraph.Query.responses(
@@ -0,0 +1,92 @@
1
+ import tenacity
2
+
3
+ from prediction_market_agent_tooling.config import APIKeys
4
+ from prediction_market_agent_tooling.loggers import logger
5
+ from prediction_market_agent_tooling.tools.cache import persistent_inmemory_cache
6
+ from prediction_market_agent_tooling.tools.is_predictable import (
7
+ parse_decision_yes_no_completion,
8
+ )
9
+ from prediction_market_agent_tooling.tools.langfuse_ import (
10
+ get_langfuse_langchain_config,
11
+ observe,
12
+ )
13
+ from prediction_market_agent_tooling.tools.utils import (
14
+ LLM_SEED,
15
+ LLM_SUPER_LOW_TEMPERATURE,
16
+ )
17
+
18
+ # I tried to make it return a JSON, but it didn't work well in combo with asking it to do chain of thought.
19
+ # Rules are almost copy-pasted from https://cdn.kleros.link/ipfs/QmZM12kkguXFk2C94ykrKpambt4iUVKsVsxGxDEdLS68ws/omen-rules.pdf,
20
+ # with some small prompting mods and I removed the point about "The outcome of the market must be known by its Resolution Date.", because that can not be verified before-hand.
21
+ # and also point about "in which none of the answers are valid will resolve as invalid" and "in which multiple answers are valid will resolve as invalid.", because before hand we can not know if one of the outcomes happened or not.
22
+ QUESTION_IS_INVALID_PROMPT = """Main signs about an invalid question (sometimes referred to as a "market"):
23
+ - The market's question is about immoral violence, death or assassination.
24
+ - The violent event can be caused by a single conscious being.
25
+ - The violent event is done illegally.
26
+ - The market should not directly incentivize immoral violent (such as murder, rape or unjust imprisonment) actions which could likely be performed by any participant.
27
+ - Invalid: Will Donald Trump be alive on the 01/12/2021? (Anyone could bet on “No” and kill him for a guaranteed profit. Anyone could bet on “Yes” to effectively put a bounty on his head).
28
+ - Invalid: Will Hera be a victim of swatting in 2020? (Anyone could falsely call the emergency services on him in order to win the bet)
29
+ - This does not prevent markets:
30
+ - Whose topics are violent events not caused by conscious beings.
31
+ - Valid: How many people will die from COVID19 in 2020? (Viruses don’t use prediction markets).
32
+ - Whose main source of uncertainty is not related to a potential violent action.
33
+ - Valid: Will Trump win the 2020 US presidential election? (The main source of uncertainty is the vote of US citizens, not a potential murder of a presidential candidate).
34
+ - Which could give an incentive only to specific participants to commit an immoral violent action, but are in practice unlikely.
35
+ - Valid: Will the US be engaged in a military conflict with a UN member state in 2021? (It’s unlikely for the US to declare war in order to win a bet on this market).
36
+ - Valid: Will Derek Chauvin go to jail for the murder of George Flyod? (It’s unlikely that the jurors would collude to make a wrong verdict in order to win this market).
37
+ - Questions with relative dates will resolve as invalid. Dates must be stated in absolute terms, not relative depending on the current time.
38
+ - Invalid: Who will be the president of the United States in 6 months? (“in 6 months depends on the current time”).
39
+ - Questions about moral values and not facts will be resolved as invalid.
40
+ - Invalid: “Is it ethical to eat meat?”.
41
+
42
+ Follow a chain of thought to evaluate if the question is invalid:
43
+
44
+ First, write the parts of the following question:
45
+
46
+ "{question}"
47
+
48
+ Then, write down what is the future event of the question, what it refers to and when that event will happen if the question contains it.
49
+
50
+ Then, explain why do you think it is or isn't invalid.
51
+
52
+ Finally, write your final decision, write `decision: ` followed by either "yes it is invalid" or "no it isn't invalid" about the question. Don't write anything else after that. You must include "yes" or "no".
53
+ """
54
+
55
+
56
+ @persistent_inmemory_cache
57
+ @tenacity.retry(stop=tenacity.stop_after_attempt(3), wait=tenacity.wait_fixed(1))
58
+ @observe()
59
+ def is_invalid(
60
+ question: str,
61
+ engine: str = "gpt-4o",
62
+ temperature: float = LLM_SUPER_LOW_TEMPERATURE,
63
+ seed: int = LLM_SEED,
64
+ prompt_template: str = QUESTION_IS_INVALID_PROMPT,
65
+ max_tokens: int = 1024,
66
+ ) -> bool:
67
+ """
68
+ Evaluate if the question is actually answerable.
69
+ """
70
+ try:
71
+ from langchain.prompts import ChatPromptTemplate
72
+ from langchain_openai import ChatOpenAI
73
+ except ImportError:
74
+ logger.error("langchain not installed, skipping is_invalid")
75
+ return True
76
+
77
+ llm = ChatOpenAI(
78
+ model=engine,
79
+ temperature=temperature,
80
+ seed=seed,
81
+ api_key=APIKeys().openai_api_key_secretstr_v1,
82
+ )
83
+
84
+ prompt = ChatPromptTemplate.from_template(template=prompt_template)
85
+ messages = prompt.format_messages(question=question)
86
+ completion = str(
87
+ llm.invoke(
88
+ messages, max_tokens=max_tokens, config=get_langfuse_langchain_config()
89
+ ).content
90
+ )
91
+
92
+ return parse_decision_yes_no_completion(question, completion)
@@ -22,8 +22,10 @@ from prediction_market_agent_tooling.loggers import logger
22
22
  T = TypeVar("T")
23
23
 
24
24
  # t=0 is mathematically impossible and it's not clear how OpenAI (and others) handle it, as a result, even with t=0, gpt-4-turbo produces very different outputs,
25
- # it seems that using a very low temperature is the best way to have as consistent outputs as possible: https://community.openai.com/t/why-the-api-output-is-inconsistent-even-after-the-temperature-is-set-to-0/329541/12
25
+ # see this experiment to figure out if you should use LLM_SUPER_LOW_TEMPERATURE or just 0: https://github.com/gnosis/prediction-market-agent/pull/438.
26
26
  LLM_SUPER_LOW_TEMPERATURE = 0.00000001
27
+ # For consistent results, also include seed for models that supports it.
28
+ LLM_SEED = 0
27
29
 
28
30
 
29
31
  def check_not_none(
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "prediction-market-agent-tooling"
3
- version = "0.51.0"
3
+ version = "0.52.0"
4
4
  description = "Tools to benchmark, deploy and monitor prediction market agents."
5
5
  authors = ["Gnosis"]
6
6
  readme = "README.md"
@@ -1,97 +0,0 @@
1
- from enum import Enum
2
- from typing import Any
3
-
4
- from pydantic import BaseModel
5
-
6
- from prediction_market_agent_tooling.tools.utils import DatetimeUTC
7
-
8
-
9
- class QuestionType(str, Enum):
10
- forecast = "forecast"
11
- notebook = "notebook"
12
- discussion = "discussion"
13
- claim = "claim"
14
- group = "group"
15
- conditional_group = "conditional_group"
16
- multiple_choice = "multiple_choice"
17
-
18
-
19
- class CommunityPrediction(BaseModel):
20
- y: list[float]
21
- q1: float | None = None
22
- q2: float | None = None
23
- q3: float | None = None
24
-
25
- @property
26
- def p_yes(self) -> float:
27
- """
28
- q2 corresponds to the median, or 'second quartile' of the distribution.
29
-
30
- If no value is provided (i.e. the question is new and has not been
31
- answered yet), we default to 0.5.
32
- """
33
- return self.q2 if self.q2 is not None else 0.5
34
-
35
-
36
- class Prediction(BaseModel):
37
- t: DatetimeUTC
38
- x: float
39
-
40
-
41
- class UserPredictions(BaseModel):
42
- id: int
43
- predictions: list[Prediction]
44
- points_won: float | None = None
45
- user: int
46
- username: str
47
- question: int
48
-
49
-
50
- class CommunityPredictionStats(BaseModel):
51
- full: CommunityPrediction
52
- unweighted: CommunityPrediction
53
-
54
-
55
- class MetaculusQuestion(BaseModel):
56
- """
57
- https://www.metaculus.com/api2/schema/redoc/#tag/questions/operation/questions_retrieve
58
- """
59
-
60
- active_state: Any
61
- url: str
62
- page_url: str
63
- id: int
64
- author: int
65
- author_name: str
66
- author_id: int
67
- title: str
68
- title_short: str
69
- group_label: str | None = None
70
- resolution: int | None
71
- resolved_option: int | None
72
- created_time: DatetimeUTC
73
- publish_time: DatetimeUTC | None = None
74
- close_time: DatetimeUTC | None = None
75
- effected_close_time: DatetimeUTC | None
76
- resolve_time: DatetimeUTC | None = None
77
- possibilities: dict[Any, Any] | None = None
78
- scoring: dict[Any, Any] = {}
79
- type: QuestionType | None = None
80
- user_perms: Any
81
- weekly_movement: float | None
82
- weekly_movement_direction: int | None = None
83
- cp_reveal_time: DatetimeUTC | None = None
84
- edited_time: DatetimeUTC
85
- last_activity_time: DatetimeUTC
86
- activity: float
87
- comment_count: int
88
- votes: int
89
- community_prediction: CommunityPredictionStats
90
- my_predictions: UserPredictions | None = None
91
- # TODO add the rest of the fields https://github.com/gnosis/prediction-market-agent-tooling/issues/301
92
-
93
-
94
- class MetaculusQuestions(BaseModel):
95
- next: str | None
96
- previous: str | None
97
- results: list[MetaculusQuestion]