-
Notifications
You must be signed in to change notification settings - Fork 8
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
Introduce fees
into AgentMarket itself (not just OmenAgentMarket)
#506
Changes from 3 commits
2e8bb2f
36185a2
0759a21
95a93ef
994f0d9
e1ba292
70f0349
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -162,3 +162,5 @@ cython_debug/ | |
|
||
tests_files/* | ||
!tests_files/.gitkeep | ||
|
||
bet_strategy_benchmark* |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
|
||
from prediction_market_agent_tooling.gtypes import xDai | ||
from prediction_market_agent_tooling.loggers import logger | ||
from prediction_market_agent_tooling.markets.agent_market import AgentMarket | ||
from prediction_market_agent_tooling.markets.agent_market import AgentMarket, MarketFees | ||
from prediction_market_agent_tooling.markets.data_models import ( | ||
Currency, | ||
Position, | ||
|
@@ -178,7 +178,7 @@ def calculate_trades( | |
if self.max_price_impact: | ||
# Adjust amount | ||
max_price_impact_bet_amount = self.calculate_bet_amount_for_price_impact( | ||
market, kelly_bet, 0 | ||
market, kelly_bet | ||
) | ||
|
||
# We just don't want Kelly size to extrapolate price_impact - hence we take the min. | ||
|
@@ -196,15 +196,20 @@ def calculate_trades( | |
return trades | ||
|
||
def calculate_price_impact_for_bet_amount( | ||
self, buy_direction: bool, bet_amount: float, yes: float, no: float, fee: float | ||
self, | ||
buy_direction: bool, | ||
bet_amount: float, | ||
yes: float, | ||
no: float, | ||
fees: MarketFees, | ||
) -> float: | ||
Comment on lines
+199
to
205
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling to prevent division by zero In the method Apply this diff to add the check: def calculate_price_impact_for_bet_amount(
self,
buy_direction: bool,
bet_amount: float,
yes: float,
no: float,
fees: MarketFees,
) -> float:
total_outcome_tokens = yes + no
+ if total_outcome_tokens == 0:
+ raise ValueError("Total outcome tokens cannot be zero")
expected_price = (
no / total_outcome_tokens if buy_direction else yes / total_outcome_tokens
)
tokens_to_buy = get_buy_outcome_token_amount(
bet_amount, buy_direction, yes, no, fees
)
actual_price = bet_amount / tokens_to_buy
# price_impact should always be > 0
price_impact = (actual_price - expected_price) / expected_price
return price_impact
|
||
total_outcome_tokens = yes + no | ||
expected_price = ( | ||
no / total_outcome_tokens if buy_direction else yes / total_outcome_tokens | ||
) | ||
|
||
tokens_to_buy = get_buy_outcome_token_amount( | ||
bet_amount, buy_direction, yes, no, fee | ||
bet_amount, buy_direction, yes, no, fees | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure When calculating Apply this diff to add the check: tokens_to_buy = get_buy_outcome_token_amount(
bet_amount, buy_direction, yes, no, fees
)
+ if tokens_to_buy == 0:
+ raise ValueError("Tokens to buy cannot be zero")
actual_price = bet_amount / tokens_to_buy
|
||
) | ||
|
||
actual_price = bet_amount / tokens_to_buy | ||
|
@@ -216,7 +221,6 @@ def calculate_bet_amount_for_price_impact( | |
self, | ||
market: AgentMarket, | ||
kelly_bet: SimpleBet, | ||
fee: float, | ||
) -> float: | ||
def calculate_price_impact_deviation_from_target_price_impact( | ||
bet_amount: xDai, | ||
|
@@ -226,7 +230,7 @@ def calculate_price_impact_deviation_from_target_price_impact( | |
bet_amount, | ||
yes_outcome_pool_size, | ||
no_outcome_pool_size, | ||
fee, | ||
MarketFees.get_zero_fees(), # TODO: Use market.fees | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is bunch of TODOs like this, going to do them in #507, to separate fees introduction to Kelly in case of issues. Will also run the bet benchmark there. |
||
) | ||
# We return abs for the algorithm to converge to 0 instead of the min (and possibly negative) value. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -75,7 +75,7 @@ def from_omen_agent_market(market: OmenAgentMarket) -> "OmenJobAgentMarket": | |
market_maker_contract_address_checksummed=market.market_maker_contract_address_checksummed, | ||
condition=market.condition, | ||
finalized_time=market.finalized_time, | ||
fee=market.fee, | ||
fees=market.fees, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Inconsistent Renaming of The change from
Ensure that all instances of 🔗 Analysis chainApprove change and suggest improvements The change from
To verify the impact of this change, you can run the following script: This script will help identify any inconsistencies or places where further updates might be needed. 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Check for occurrences of 'fee' and 'fees' related to OmenJobAgentMarket or OmenAgentMarket
# Search for 'fee' occurrences
echo "Occurrences of 'fee':"
rg --type python -i '\bfee\b' --context 3
echo -e "\nOccurrences of 'fees':"
rg --type python -i '\bfees\b' --context 3
echo -e "\nOccurrences of 'OmenJobAgentMarket':"
rg --type python 'OmenJobAgentMarket' --context 3
echo -e "\nOccurrences of 'OmenAgentMarket':"
rg --type python 'OmenAgentMarket' --context 3
Length of output: 619 Script: #!/bin/bash
# Description: Check for occurrences of 'fee' and 'fees' related to OmenJobAgentMarket or OmenAgentMarket in Python files
# Search for 'fee' occurrences
echo "Occurrences of 'fee':"
rg -i '\bfee\b' --context 3 --glob "*.py"
echo -e "\nOccurrences of 'fees':"
rg -i '\bfees\b' --context 3 --glob "*.py"
echo -e "\nOccurrences of 'OmenJobAgentMarket':"
rg 'OmenJobAgentMarket' --context 3 --glob "*.py"
echo -e "\nOccurrences of 'OmenAgentMarket':"
rg 'OmenAgentMarket' --context 3 --glob "*.py"
Length of output: 108510 |
||
) | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
from enum import Enum | ||
|
||
from eth_typing import ChecksumAddress | ||
from pydantic import BaseModel, field_validator | ||
from pydantic import BaseModel, field_validator, model_validator | ||
from pydantic_core.core_schema import FieldValidationInfo | ||
|
||
from prediction_market_agent_tooling.config import APIKeys | ||
|
@@ -16,6 +16,7 @@ | |
ResolvedBet, | ||
TokenAmount, | ||
) | ||
from prediction_market_agent_tooling.markets.market_fees import MarketFees | ||
from prediction_market_agent_tooling.tools.utils import ( | ||
DatetimeUTC, | ||
check_not_none, | ||
|
@@ -60,6 +61,7 @@ class AgentMarket(BaseModel): | |
current_p_yes: Probability | ||
url: str | ||
volume: float | None # Should be in currency of `currency` above. | ||
fees: MarketFees | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leveled the fees to AgentMarket itself, but because Manifold has an absolute, constant fee, it's now a model with |
||
|
||
@field_validator("outcome_token_pool") | ||
def validate_outcome_token_pool( | ||
|
@@ -77,6 +79,14 @@ def validate_outcome_token_pool( | |
) | ||
return outcome_token_pool | ||
|
||
@model_validator(mode="before") | ||
def handle_legacy_fee(cls, data: dict[str, t.Any]) -> dict[str, t.Any]: | ||
# Backward compatibility for older `AgentMarket` without `fees`. | ||
if "fees" not in data and "fee" in data: | ||
data["fees"] = MarketFees(absolute=0.0, bet_proportion=data["fee"]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This fixed running of |
||
del data["fee"] | ||
return data | ||
|
||
Comment on lines
+82
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add tests for handling legacy 'fee' data The Consider adding or updating unit tests to verify that markets with the legacy |
||
@property | ||
def current_p_no(self) -> Probability: | ||
return Probability(1 - self.current_p_yes) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
from prediction_market_agent_tooling.markets.agent_market import ( | ||
AgentMarket, | ||
FilterBy, | ||
MarketFees, | ||
SortBy, | ||
) | ||
from prediction_market_agent_tooling.markets.data_models import BetAmount, Currency | ||
|
@@ -33,6 +34,13 @@ class ManifoldAgentMarket(AgentMarket): | |
currency: t.ClassVar[Currency] = Currency.Mana | ||
base_url: t.ClassVar[str] = MANIFOLD_BASE_URL | ||
|
||
# Manifold has additional fees than `platform_absolute`, but they don't expose them in the API before placing the bet, see https://docs.manifold.markets/api. | ||
# So we just consider them as 0, which anyway is true for all markets I randomly checked on Manifold. | ||
fees: MarketFees = MarketFees( | ||
bet_proportion=0, | ||
absolute=0.25, # For doing trades via API. | ||
) | ||
Comment on lines
+37
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Potential issues with the assumption of zero The search revealed references to proportional fees in the codebase, such as in Consider reviewing how proportional fees are handled across different markets to ensure consistency and accuracy. 🔗 Analysis chainApprove the addition of The introduction of the However, there's a potential concern: The comment states that the zero To verify this assumption, we can run the following script to check for any mentions of non-zero proportional fees in the codebase: If this search returns results, it might indicate that there are cases where proportional fees are considered, and we should review the assumption made in this code. 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Search for mentions of non-zero proportional fees in the codebase
# Test: Look for mentions of proportional fees
rg --type python "proportional.*fee|fee.*proportional"
Length of output: 87 Script: #!/bin/bash
# Description: Search for mentions of non-zero proportional fees in Python files
rg "proportional.*fee|fee.*proportional" --glob '*.py'
Length of output: 523 |
||
|
||
def get_last_trade_p_yes(self) -> Probability: | ||
"""On Manifold, probablities aren't updated after the closure, so we can just use the current probability""" | ||
return self.current_p_yes | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from pydantic import BaseModel, Field | ||
|
||
|
||
class MarketFees(BaseModel): | ||
bet_proportion: float = Field( | ||
..., ge=0.0, lt=1.0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fancy way to. validate bet propotion, so I removed it in other places of the code, where MarketFees is now accepted. |
||
) # proportion of the bet, from 0 to 1 | ||
absolute: float # absolute value paid in the currency of the market | ||
|
||
@staticmethod | ||
def get_zero_fees( | ||
bet_proportion: float = 0.0, | ||
absolute: float = 0.0, | ||
) -> "MarketFees": | ||
return MarketFees( | ||
bet_proportion=bet_proportion, | ||
absolute=absolute, | ||
) | ||
|
||
def total_fee_absolute_value(self, bet_amount: float) -> float: | ||
""" | ||
Returns the total fee in absolute terms, including both proportional and fixed fees. | ||
""" | ||
return self.bet_proportion * bet_amount + self.absolute | ||
|
||
def total_fee_relative_value(self, bet_amount: float) -> float: | ||
""" | ||
Returns the total fee relative to the bet amount, including both proportional and fixed fees. | ||
""" | ||
if bet_amount == 0: | ||
return 0.0 | ||
total_fee = self.total_fee_absolute_value(bet_amount) | ||
return total_fee / bet_amount | ||
Comment on lines
+20
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like these are unused. Planning to use in later PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
def get_bet_size_after_fees(self, bet_amount: float) -> float: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! This is a really neat replacement for the |
||
return bet_amount * (1 - self.bet_proportion) - self.absolute |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -22,6 +22,7 @@ | |||||||||||||||||||||||
from prediction_market_agent_tooling.markets.agent_market import ( | ||||||||||||||||||||||||
AgentMarket, | ||||||||||||||||||||||||
FilterBy, | ||||||||||||||||||||||||
MarketFees, | ||||||||||||||||||||||||
SortBy, | ||||||||||||||||||||||||
) | ||||||||||||||||||||||||
from prediction_market_agent_tooling.markets.data_models import ( | ||||||||||||||||||||||||
|
@@ -101,7 +102,6 @@ class OmenAgentMarket(AgentMarket): | |||||||||||||||||||||||
finalized_time: DatetimeUTC | None | ||||||||||||||||||||||||
created_time: DatetimeUTC | ||||||||||||||||||||||||
close_time: DatetimeUTC | ||||||||||||||||||||||||
fee: float # proportion, from 0 to 1 | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
_binary_market_p_yes_history: list[Probability] | None = None | ||||||||||||||||||||||||
description: str | None = ( | ||||||||||||||||||||||||
|
@@ -240,7 +240,7 @@ def calculate_sell_amount_in_collateral( | |||||||||||||||||||||||
shares_to_sell=amount.amount, | ||||||||||||||||||||||||
holdings=wei_to_xdai(pool_balance[self.get_index_set(sell_str)]), | ||||||||||||||||||||||||
other_holdings=wei_to_xdai(pool_balance[self.get_index_set(other_str)]), | ||||||||||||||||||||||||
fee=self.fee, | ||||||||||||||||||||||||
fees=self.fees, | ||||||||||||||||||||||||
) | ||||||||||||||||||||||||
return xDai(collateral) | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
|
@@ -352,7 +352,12 @@ def from_data_model(model: OmenMarket) -> "OmenAgentMarket": | |||||||||||||||||||||||
url=model.url, | ||||||||||||||||||||||||
volume=wei_to_xdai(model.collateralVolume), | ||||||||||||||||||||||||
close_time=model.close_time, | ||||||||||||||||||||||||
fee=float(wei_to_xdai(model.fee)) if model.fee is not None else 0.0, | ||||||||||||||||||||||||
fees=MarketFees( | ||||||||||||||||||||||||
bet_proportion=( | ||||||||||||||||||||||||
float(wei_to_xdai(model.fee)) if model.fee is not None else 0.0 | ||||||||||||||||||||||||
), | ||||||||||||||||||||||||
absolute=0, | ||||||||||||||||||||||||
), | ||||||||||||||||||||||||
outcome_token_pool={ | ||||||||||||||||||||||||
model.outcomes[i]: wei_to_xdai(Wei(model.outcomeTokenAmounts[i])) | ||||||||||||||||||||||||
for i in range(len(model.outcomes)) | ||||||||||||||||||||||||
|
@@ -598,7 +603,7 @@ def get_buy_token_amount( | |||||||||||||||||||||||
buy_direction=direction, | ||||||||||||||||||||||||
yes_outcome_pool_size=outcome_token_pool[OMEN_TRUE_OUTCOME], | ||||||||||||||||||||||||
no_outcome_pool_size=outcome_token_pool[OMEN_FALSE_OUTCOME], | ||||||||||||||||||||||||
fee=self.fee, | ||||||||||||||||||||||||
fees=self.fees, | ||||||||||||||||||||||||
) | ||||||||||||||||||||||||
return TokenAmount(amount=amount, currency=self.currency) | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
|
@@ -628,10 +633,10 @@ def get_new_p_yes(self, bet_amount: BetAmount, direction: bool) -> Probability: | |||||||||||||||||||||||
no_outcome_pool_size = outcome_token_pool[self.get_outcome_str_from_bool(False)] | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
new_yes_outcome_pool_size = yes_outcome_pool_size + ( | ||||||||||||||||||||||||
bet_amount.amount * (1 - self.fee) | ||||||||||||||||||||||||
self.fees.get_bet_size_after_fees(bet_amount.amount) | ||||||||||||||||||||||||
) | ||||||||||||||||||||||||
new_no_outcome_pool_size = no_outcome_pool_size + ( | ||||||||||||||||||||||||
bet_amount.amount * (1 - self.fee) | ||||||||||||||||||||||||
self.fees.get_bet_size_after_fees(bet_amount.amount) | ||||||||||||||||||||||||
Comment on lines
+636
to
+639
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential error in updating outcome pool sizes in The same amount Apply this diff to correct the pool size updates: def get_new_p_yes(self, bet_amount: BetAmount, direction: bool) -> Probability:
if not self.has_token_pool():
raise ValueError("Outcome token pool is required to calculate new p_yes.")
outcome_token_pool = check_not_none(self.outcome_token_pool)
yes_outcome_pool_size = outcome_token_pool[self.get_outcome_str_from_bool(True)]
no_outcome_pool_size = outcome_token_pool[self.get_outcome_str_from_bool(False)]
- new_yes_outcome_pool_size = yes_outcome_pool_size + (
- self.fees.get_bet_size_after_fees(bet_amount.amount)
- )
- new_no_outcome_pool_size = no_outcome_pool_size + (
- self.fees.get_bet_size_after_fees(bet_amount.amount)
- )
+ if direction:
+ new_yes_outcome_pool_size = yes_outcome_pool_size + self.fees.get_bet_size_after_fees(bet_amount.amount)
+ new_no_outcome_pool_size = no_outcome_pool_size
+ else:
+ new_yes_outcome_pool_size = yes_outcome_pool_size
+ new_no_outcome_pool_size = no_outcome_pool_size + self.fees.get_bet_size_after_fees(bet_amount.amount)
received_token_amount = self.get_buy_token_amount(bet_amount, direction).amount
if direction:
new_yes_outcome_pool_size -= received_token_amount
else:
new_no_outcome_pool_size -= received_token_amount
new_p_yes = new_no_outcome_pool_size / (
new_yes_outcome_pool_size + new_no_outcome_pool_size
)
return Probability(new_p_yes) 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||
) | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
received_token_amount = self.get_buy_token_amount(bet_amount, direction).amount | ||||||||||||||||||||||||
|
@@ -1104,7 +1109,6 @@ def omen_remove_fund_market_tx( | |||||||||||||||||||||||
market_contract.removeFunding(api_keys=api_keys, remove_funding=shares, web3=web3) | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
conditional_tokens = OmenConditionalTokenContract() | ||||||||||||||||||||||||
parent_collection_id = build_parent_collection_id() | ||||||||||||||||||||||||
amount_per_index_set = get_conditional_tokens_balance_for_market( | ||||||||||||||||||||||||
market, from_address, web3 | ||||||||||||||||||||||||
) | ||||||||||||||||||||||||
|
@@ -1116,7 +1120,6 @@ def omen_remove_fund_market_tx( | |||||||||||||||||||||||
result = conditional_tokens.mergePositions( | ||||||||||||||||||||||||
api_keys=api_keys, | ||||||||||||||||||||||||
collateral_token_address=market.collateral_token_contract_address_checksummed, | ||||||||||||||||||||||||
parent_collection_id=parent_collection_id, | ||||||||||||||||||||||||
conditionId=market.condition.id, | ||||||||||||||||||||||||
index_sets=market.condition.index_sets, | ||||||||||||||||||||||||
amount=amount_to_merge, | ||||||||||||||||||||||||
|
@@ -1266,14 +1269,14 @@ def get_buy_outcome_token_amount( | |||||||||||||||||||||||
buy_direction: bool, | ||||||||||||||||||||||||
yes_outcome_pool_size: float, | ||||||||||||||||||||||||
no_outcome_pool_size: float, | ||||||||||||||||||||||||
fee: float, | ||||||||||||||||||||||||
fees: MarketFees, | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Missing An instance of
Please update this call to include the 🔗 Analysis chainUpdating The function 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Find all calls to 'get_buy_outcome_token_amount' missing the new 'fees' parameter.
# Test: Search for function calls without 'fees' argument. Expect: No occurrences.
rg --type python --fixed-strings 'get_buy_outcome_token_amount(' --not -g 'omen.py' --no-heading -A 0 -B 0 | grep -v 'fees='
Length of output: 555 Script: #!/bin/bash
# Description: Find all calls to 'get_buy_outcome_token_amount' missing the new 'fees' parameter.
# Corrected: Use '--glob' to exclude 'omen.py' instead of the invalid '--not' flag.
rg --type python --fixed-strings 'get_buy_outcome_token_amount(' --glob '!omen.py' --no-heading | grep -v 'fees='
Length of output: 144 Script: #!/bin/bash
# Description: Find all calls to 'get_buy_outcome_token_amount' missing the new 'fees' parameter.
# Corrected: Use '--type py' instead of 'python'.
rg --type py --fixed-strings 'get_buy_outcome_token_amount(' --glob '!omen.py' --no-heading | grep -v 'fees='
Length of output: 222 |
||||||||||||||||||||||||
) -> float: | ||||||||||||||||||||||||
""" | ||||||||||||||||||||||||
Calculates the amount of outcome tokens received for a given investment | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
Taken from https://github.com/gnosis/conditional-tokens-market-makers/blob/6814c0247c745680bb13298d4f0dd7f5b574d0db/contracts/FixedProductMarketMaker.sol#L264 | ||||||||||||||||||||||||
""" | ||||||||||||||||||||||||
investment_amount_minus_fees = investment_amount * (1 - fee) | ||||||||||||||||||||||||
investment_amount_minus_fees = fees.get_bet_size_after_fees(investment_amount) | ||||||||||||||||||||||||
buy_token_pool_balance = ( | ||||||||||||||||||||||||
yes_outcome_pool_size if buy_direction else no_outcome_pool_size | ||||||||||||||||||||||||
) | ||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -163,10 +163,10 @@ def mergePositions( | |
self, | ||
api_keys: APIKeys, | ||
collateral_token_address: ChecksumAddress, | ||
parent_collection_id: HexStr, | ||
conditionId: HexBytes, | ||
index_sets: t.List[int], | ||
amount: Wei, | ||
parent_collection_id: HexStr = build_parent_collection_id(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider moving the default value calculation inside the function body. While providing a default value for To address this, consider the following approach: def mergePositions(
self,
api_keys: APIKeys,
collateral_token_address: ChecksumAddress,
conditionId: HexBytes,
index_sets: t.List[int],
amount: Wei,
parent_collection_id: HexStr | None = None,
web3: Web3 | None = None,
) -> TxReceipt:
if parent_collection_id is None:
parent_collection_id = build_parent_collection_id()
# Rest of the function implementation... This approach ensures that 🧰 Tools🪛 Ruff
|
||
web3: Web3 | None = None, | ||
) -> TxReceipt: | ||
return self.send( | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,3 +1,4 @@ | ||||||||||||
from prediction_market_agent_tooling.markets.market_fees import MarketFees | ||||||||||||
from prediction_market_agent_tooling.tools.betting_strategies.utils import SimpleBet | ||||||||||||
|
||||||||||||
|
||||||||||||
|
@@ -61,7 +62,7 @@ def get_kelly_bet_full( | |||||||||||
estimated_p_yes: float, | ||||||||||||
confidence: float, | ||||||||||||
max_bet: float, | ||||||||||||
fee: float = 0.0, # proportion, 0 to 1 | ||||||||||||
fees: MarketFees = MarketFees.get_zero_fees(), # TODO: Remove default value. | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid function calls in default arguments Using a function call like As indicated by the TODO comment and the static analysis hint (B008), consider removing the default value from the function signature and setting it inside the function instead. Here's how you can modify the code: def get_kelly_bet_full(
yes_outcome_pool_size: float,
no_outcome_pool_size: float,
estimated_p_yes: float,
confidence: float,
max_bet: float,
- fees: MarketFees = MarketFees.get_zero_fees(), # TODO: Remove default value.
+ fees: MarketFees = None, # TODO: Remove default value.
) -> SimpleBet:
+ if fees is None:
+ fees = MarketFees.get_zero_fees() 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff
|
||||||||||||
) -> SimpleBet: | ||||||||||||
""" | ||||||||||||
Calculate the optimal bet amount using the Kelly Criterion for a binary outcome market. | ||||||||||||
|
@@ -86,9 +87,14 @@ def get_kelly_bet_full( | |||||||||||
limitations under the License. | ||||||||||||
``` | ||||||||||||
""" | ||||||||||||
fee = fees.bet_proportion | ||||||||||||
if fees.absolute > 0: | ||||||||||||
raise RuntimeError( | ||||||||||||
f"Kelly works only with bet-proportional fees, but the fees are {fees=}." | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just had a look at the below formula. Without trying to re-derive, I wonder if, for the numerator, you replace all instances of Not sure about the denominator though |
||||||||||||
) | ||||||||||||
|
||||||||||||
check_is_valid_probability(estimated_p_yes) | ||||||||||||
check_is_valid_probability(confidence) | ||||||||||||
check_is_valid_probability(fee) | ||||||||||||
|
||||||||||||
if max_bet == 0: | ||||||||||||
return SimpleBet(direction=True, size=0) | ||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, a happy directory tree now 😌