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

Fix/kelly #147

Merged
merged 9 commits into from
Nov 19, 2023
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
10 changes: 5 additions & 5 deletions packages/packages.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"dev": {
"skill/valory/market_manager_abci/0.1.0": "bafybeigesvgfjjtzxnsofhwutsp4pyclxnn62z2luy4xt7yarm64u6pbti",
"skill/valory/decision_maker_abci/0.1.0": "bafybeihuuqnr7egnlak5p23hu6aglo3ih6om2ih42btezylzebayrjah4m",
"skill/valory/trader_abci/0.1.0": "bafybeig2ynpufv4jmw4rhii5k4j7gpoesupoufnr6nzgnljeiyxp3vv6lq",
"skill/valory/decision_maker_abci/0.1.0": "bafybeifr5sqhtsnj2z4jv2lgcridolfbl23plqdbrdjmg2wyltmgr3zsui",
"skill/valory/trader_abci/0.1.0": "bafybeih72cnauzvc4lhpxjwyqxhx2vfxoztucfast7jyl6oqgbaqcctop4",
"contract/valory/market_maker/0.1.0": "bafybeih4r35d3plsjw56ham6xvi6dn4semmuihc53lh3qofpwj242rnjkq",
"agent/valory/trader/0.1.0": "bafybeifgxbaukxagyzfgzg7me2sdr6w73oe2fjofwpzclogzexsft2alxe",
"service/valory/trader/0.1.0": "bafybeifirhjukt7h5ndrbq2kufowmponinvm5q6eos3t6qgzn6mgi4s6ea",
"agent/valory/trader/0.1.0": "bafybeibxipsj5g6mkgz5p6an6berhl5lqc7mkuqjhb3khzvgnmegmjam2q",
"service/valory/trader/0.1.0": "bafybeida22sohxo25ba5pspp75x6jh53ouhvkozp2ylndfitsd5cqwh5oq",
"contract/valory/erc20/0.1.0": "bafybeidpjppgs7jlig2gdpdr3a6q3etbejpxrifjhzlcufpo5zf23dqv7y",
"skill/valory/tx_settlement_multiplexer_abci/0.1.0": "bafybeic56a3mpezdy7ri4onwvoifj725wjep3n5kiqoxa32eel4b7qt6mm",
"skill/valory/tx_settlement_multiplexer_abci/0.1.0": "bafybeig6nwyji7tkrpmc227z6p32gu5l3cge3jznjv5j3wzg4jh6x2rj7y",
"contract/valory/mech/0.1.0": "bafybeigjn4q6mxal2hxzjyzldl4t4aykkpxjnbsgnli2c3xwf6binkmn74",
"contract/valory/realitio/0.1.0": "bafybeiamgkwwqhray4fs2hlipwxkq7mosmi7ev7jut4vneetaaycc4ruji",
"contract/valory/realitio_proxy/0.1.0": "bafybeidx37xzjjmapwacedgzhum6grfzhp5vhouz4zu3pvpgdy5pgb2fr4",
Expand Down
6 changes: 3 additions & 3 deletions packages/valory/agents/trader/aea-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ skills:
- valory/reset_pause_abci:0.1.0:bafybeiflxcl2dtzayyzzddc4f2astzxunyp66meutornanrgeemicdea5q
- valory/termination_abci:0.1.0:bafybeifazwrksp756h7z42qqfcgi6lya6wmhbx46l7ghlaooe45gqnju7q
- valory/transaction_settlement_abci:0.1.0:bafybeigxkdujugzvve2dszkwr5kgfx4uhz2epofo4lorbcnthmzfjegwzi
- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeic56a3mpezdy7ri4onwvoifj725wjep3n5kiqoxa32eel4b7qt6mm
- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeig6nwyji7tkrpmc227z6p32gu5l3cge3jznjv5j3wzg4jh6x2rj7y
- valory/market_manager_abci:0.1.0:bafybeigesvgfjjtzxnsofhwutsp4pyclxnn62z2luy4xt7yarm64u6pbti
- valory/decision_maker_abci:0.1.0:bafybeihuuqnr7egnlak5p23hu6aglo3ih6om2ih42btezylzebayrjah4m
- valory/trader_abci:0.1.0:bafybeig2ynpufv4jmw4rhii5k4j7gpoesupoufnr6nzgnljeiyxp3vv6lq
- valory/decision_maker_abci:0.1.0:bafybeifr5sqhtsnj2z4jv2lgcridolfbl23plqdbrdjmg2wyltmgr3zsui
- valory/trader_abci:0.1.0:bafybeih72cnauzvc4lhpxjwyqxhx2vfxoztucfast7jyl6oqgbaqcctop4
- valory/staking_abci:0.1.0:bafybeifoejd5q6wgmqohhwp46uwk3g4ysr7f5mf2fbmjhxulwzwdy2udui
default_ledger: ethereum
required_ledgers:
Expand Down
2 changes: 1 addition & 1 deletion packages/valory/services/trader/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license: Apache-2.0
fingerprint:
README.md: bafybeigtuothskwyvrhfosps2bu6suauycolj67dpuxqvnicdrdu7yhtvq
fingerprint_ignore_patterns: []
agent: valory/trader:0.1.0:bafybeifgxbaukxagyzfgzg7me2sdr6w73oe2fjofwpzclogzexsft2alxe
agent: valory/trader:0.1.0:bafybeibxipsj5g6mkgz5p6an6berhl5lqc7mkuqjhb3khzvgnmegmjam2q
number_of_agents: 4
deployment: {}
---
Expand Down
95 changes: 50 additions & 45 deletions packages/valory/skills/decision_maker_abci/behaviours/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
from packages.valory.skills.decision_maker_abci.models import (
DecisionMakerParams,
MultisendBatch,
STRATEGY_BET_AMOUNT_PER_CONF_THRESHOLD,
SharedState,
)
from packages.valory.skills.decision_maker_abci.policy import EGreedyPolicy
Expand All @@ -61,7 +62,6 @@
SAFE_GAS = 0
CID_PREFIX = "f01701220"
WXDAI = "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"
EPSILON = 1e-7


def remove_fraction_wei(amount: int, fraction: float) -> int:
Expand All @@ -72,6 +72,46 @@ def remove_fraction_wei(amount: int, fraction: float) -> int:
raise ValueError(f"The given fraction {fraction!r} is not in the range [0, 1].")


def calculate_kelly_bet_amount(
x: int, y: int, p: float, c: float, b: int, f: float
) -> int:
"""Calculate the Kelly bet amount."""
if b == 0:
return 0
numerator = (
-4 * x**2 * y
+ b * y**2 * p * c * f
+ 2 * b * x * y * p * c * f
+ b * x**2 * p * c * f
- 2 * b * y**2 * f
- 2 * b * x * y * f
+ (
(
4 * x**2 * y
- b * y**2 * p * c * f
- 2 * b * x * y * p * c * f
- b * x**2 * p * c * f
+ 2 * b * y**2 * f
+ 2 * b * x * y * f
)
** 2
- (
4
* (x**2 * f - y**2 * f)
* (
-4 * b * x * y**2 * p * c
- 4 * b * x**2 * y * p * c
+ 4 * b * x * y**2
)
)
)
** (1 / 2)
)
denominator = 2 * (x**2 * f - y**2 * f)
kelly_bet_amount = numerator / denominator
return int(kelly_bet_amount)


class DecisionMakerBaseBehaviour(BaseBehaviour, ABC):
"""Represents the base class for the decision-making FSM behaviour."""

Expand Down Expand Up @@ -216,45 +256,6 @@ def check_balance(self) -> WaitableConditionType:
self.context.logger.info(f"The safe has {native} xDAI and {collateral}.")
return True

def _calculate_kelly_bet_amount(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Antipattern to have this as an instance method. It's much harder to test this way

self, x: int, y: int, p: float, c: float, b: int, f: float
) -> int:
"""Calculate the Kelly bet amount."""
if b == 0:
error = "Cannot calculate Kelly bet amount with no bankroll."
self.context.logger.error(error)
return 0
kelly_bet_amount = (
-4 * x**2 * y
+ b * y**2 * p * c * f
+ 2 * b * x * y * p * c * f
+ b * x**2 * p * c * f
- 2 * b * y**2 * f
- 2 * b * x * y * f
+ (
(
4 * x**2 * y
- b * y**2 * p * c * f
- 2 * b * x * y * p * c * f
- b * x**2 * p * c * f
+ 2 * b * y**2 * f
+ 2 * b * x * y * f
)
** 2
- (
4
* (x**2 * f - y**2 * f)
* (
-4 * b * x * y**2 * p * c
- 4 * b * x**2 * y * p * c
+ 4 * b * x * y**2
)
)
)
** (1 / 2)
) / (2 * (x**2 * f - y**2 * f) + EPSILON)
return int(kelly_bet_amount)

def get_max_bet_amount(self, a: int, x: int, y: int, f: float) -> int:
"""Get max bet amount based on available shares."""
if x**2 * f**2 + 2 * x * y * f**2 + y**2 * f**2 == 0:
Expand Down Expand Up @@ -293,17 +294,18 @@ def get_bet_amount(
) -> Generator[None, None, int]:
"""Get the bet amount given a specified trading strategy."""

if strategy == "bet_amount_per_conf_threshold":
# Kelly Criterion does not trade for equally weighted pools.
if (
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rather than using some hack, let's just revert to this strategy when Kelly Criterion would suggest not to trade.

strategy == STRATEGY_BET_AMOUNT_PER_CONF_THRESHOLD
or selected_type_tokens_in_pool == other_tokens_in_pool
):
self.context.logger.info(
"Used trading strategy: Bet amount per confidence threshold"
)
threshold = round(confidence, 1)
bet_amount = self.params.bet_amount_per_threshold[threshold]
return bet_amount

if strategy != "kelly_criterion":
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should be checked once at construction, not here.

raise ValueError(f"Invalid trading strategy: {strategy}")

self.context.logger.info("Used trading strategy: Kelly Criterion")
# bankroll: the max amount of DAI available to trade
yield from self.wait_for_condition_with_sleep(self.check_balance)
Expand All @@ -323,7 +325,10 @@ def get_bet_amount(

fee_fraction = 1 - self.wei_to_native(bet_fee)
self.context.logger.info(f"Fee fraction: {fee_fraction}")
kelly_bet_amount = self._calculate_kelly_bet_amount(
if bankroll_adj == 0:
error = "Cannot calculate Kelly bet amount with no bankroll."
Copy link
Contributor Author

Choose a reason for hiding this comment

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

extracted

self.context.logger.error(error)
kelly_bet_amount = calculate_kelly_bet_amount(
selected_type_tokens_in_pool,
other_tokens_in_pool,
win_probability,
Expand Down
15 changes: 9 additions & 6 deletions packages/valory/skills/decision_maker_abci/behaviours/reedem.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,10 +435,11 @@ def _check_already_redeemed(self) -> WaitableConditionType:
if not result:
n_retries += 1
keep_fraction = (1 - self.params.reduce_factor) ** n_retries
step = int(batch_size * keep_fraction)
msg = f"Repeating this call with a decreased batch size of {step}."
batch_size = int(self.params.event_filtering_batch_size * keep_fraction)
msg = (
f"Repeating this call with a decreased batch size of {batch_size}."
)
self.context.logger.warning(msg)
from_block += step
continue

self.redeeming_progress.payouts.update(self.payouts_batch)
Expand Down Expand Up @@ -568,10 +569,11 @@ def get_claim_params(self) -> WaitableConditionType:
if not result:
n_retries += 1
keep_fraction = (1 - self.params.reduce_factor) ** n_retries
step = int(batch_size * keep_fraction)
msg = f"Repeating this call with a decreased batch size of {step}."
batch_size = int(self.params.event_filtering_batch_size * keep_fraction)
msg = (
f"Repeating this call with a decreased batch size of {batch_size}."
)
self.context.logger.warning(msg)
from_block += step
continue

self.redeeming_progress.answered.extend(self.claim_params_batch)
Expand Down Expand Up @@ -769,6 +771,7 @@ def async_act(self) -> Generator:
self.context.logger.info(msg)
self._load_progress()

success = False
if not self.redeeming_progress.check_finished:
success = yield from self._clean_redeem_info()

Expand Down
11 changes: 10 additions & 1 deletion packages/valory/skills/decision_maker_abci/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
DEFAULT_FROM_BLOCK = "earliest"
ZERO_HEX = HASH_ZERO[2:]
ZERO_BYTES = bytes.fromhex(ZERO_HEX)
STRATEGY_BET_AMOUNT_PER_CONF_THRESHOLD = "bet_amount_per_conf_threshold"
STRATEGY_KELLY_CRITERION = "kelly_criterion"


class PromptTemplate(Template):
Expand Down Expand Up @@ -178,6 +180,13 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:

# the trading strategy to use for placing bets
self.trading_strategy: str = self._ensure("trading_strategy", kwargs, str)
if self.trading_strategy not in [
STRATEGY_BET_AMOUNT_PER_CONF_THRESHOLD,
STRATEGY_KELLY_CRITERION,
]:
raise ValueError(
f"The trading strategy {self.trading_strategy} is not supported!"
)
# the factor of calculated kelly bet to use for placing bets
self.bet_kelly_fraction: float = self._ensure(
"bet_kelly_fraction", kwargs, float
Expand Down Expand Up @@ -235,7 +244,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
@property
def using_kelly(self) -> bool:
"""Get the max bet amount if the `bet_amount_per_conf_threshold` strategy is used."""
return self.trading_strategy == "kelly_criterion"
return self.trading_strategy == STRATEGY_KELLY_CRITERION

@property
def max_bet_amount(self) -> int:
Expand Down
11 changes: 8 additions & 3 deletions packages/valory/skills/decision_maker_abci/skill.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ fingerprint:
README.md: bafybeia367zzdwndvlhw27rvnwodytjo3ms7gbc3q7mhrrjqjgfasnk47i
__init__.py: bafybeih563ujnigeci2ldzh7hakbau6a222vsed7leg3b7lq32vcn3nm4a
behaviours/__init__.py: bafybeih6ddz2ocvm6x6ytvlbcz6oi4snb5ee5xh5h65nq4w2qf7fd7zfky
behaviours/base.py: bafybeicu45h2jj6u462shnb3e7nrp7aynt6ezgpbznpyyjrkjtkkxnht3u
behaviours/base.py: bafybeifwz5zbbaia4q4oll6cldtvt47w2hw2qadptkmmtovmitzgpizyki
behaviours/bet_placement.py: bafybeigtz4uimsqjjwq4r5p3a5v6niqdtqezbuf2ghy6o7syhsh4k5gjfa
behaviours/blacklisting.py: bafybeicl6b4hcmqmekta2mcuhkkydnzk7jmic6k44e6ns3u2ibad3awzvu
behaviours/decision_receive.py: bafybeifacce2ke7oltnwnpdjdqfd74eaaw5wxnjfzk6c5tqdsxsmbzjj3m
behaviours/decision_request.py: bafybeievr7vae43e7jr4eqqhwe3emvgiih7ysa66jcb5g2oz5lbxua232q
behaviours/handle_failed_tx.py: bafybeidxpc6u575ymct5tdwutvzov6zqfdoio5irgldn3fw7q3lg36mmxm
behaviours/reedem.py: bafybeifgsgp655ml4om4ko3j24hqzwjdqcnobiege4lpy5roen5omxtnby
behaviours/reedem.py: bafybeia2xoyrlbh55tv227hezqjck75irk6vmnpglw4lqfpx22a7bsjl4q
behaviours/round_behaviour.py: bafybeig4tdktyu6hapoqymnxh2bgpds547st6a44heue657wkctwe4gjvm
behaviours/sampling.py: bafybeifzhm4sspdvt227ksl5hjn26offgqpwempgbcwbr6dq7gyi2a46sm
behaviours/tool_selection.py: bafybeigfr2frkljrxyfxs5p3j42equzehgaqtkyuxk6eiujyudr6ajqakm
dialogues.py: bafybeigpwuzku3we7axmxeamg7vn656maww6emuztau5pg3ebsoquyfdqm
fsm_specification.yaml: bafybeifnob3ceim2mj7lqagtnpwqjqqxs5eg3oiwc73gwm6x5i2dvvlcya
handlers.py: bafybeihj33szgrcxnpd73s4nvluyxwwsvhjum2cuq3ilhhe6vfola3k7vy
models.py: bafybeifskab7b3nqalkenjgk745ky4h7bsqar73zzvrnygymhjl4qxl2ga
models.py: bafybeifvohs24ddh5lujdx6rgmulzoovs3dmmsza3vieugstq3idv2iday
payloads.py: bafybeifhq6stu4vp2ef4qvihxgpos3yc2zcuaja2safwt7efdidoejgvqa
policy.py: bafybeidpmx4ek3qze63zpuwixyf6t7bdv62ewgkzt3ljrzadiwdw64cueq
redeem_info.py: bafybeibddfxwp3577c3dl2utaowwltquu5fg6crezpumoebw563wxpbfrm
Expand All @@ -41,6 +41,9 @@ fingerprint:
states/redeem.py: bafybeib2y6v3vuvw3upjz75ie7j2bkhclwzp7j77esunabjatdtmdvzqlm
states/sampling.py: bafybeidnvdogjlthjfe7jpaiuezm3xydrbxxukyoss4gx6t5fdin52rsta
states/tool_selection.py: bafybeiaaijv6dukp3bmsptcwkcmumc6wu6ztzkvaqzsqqjbfn4ozgyuykq
tests/__init__.py: bafybeiakpi3k3kc7wrjj7hrluvjcj36lu2gezpmrctwiz5yg2fe7ggnf3i
tests/conftest.py: bafybeic2xlujtbkyqk2zzpo5vorefwa3nwgfwmrk5rx77vu4gfyrn3pv5m
tests/test_behaviours.py: bafybeigfrzuqlxok7zmkyjd4t2p6wovmenx7n3zo7xu5jprv46jkzp2kqa
fingerprint_ignore_patterns: []
connections: []
contracts:
Expand Down Expand Up @@ -243,6 +246,8 @@ models:
dependencies:
hexbytes:
version: ==0.3.1
hypothesis:
version: ==6.21.6
py-multibase:
version: ==1.0.3
py-multicodec:
Expand Down
25 changes: 25 additions & 0 deletions packages/valory/skills/decision_maker_abci/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2021-2023 Valory AG
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------

"""This module contains the tests for valory/decision_maker_abci."""

from aea.configurations.base import PublicId


PUBLIC_ID = PublicId.from_str("valory/decision_maker_abci:0.1.0")
34 changes: 34 additions & 0 deletions packages/valory/skills/decision_maker_abci/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2021-2023 Valory AG
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------

"""Conftest module for io tests."""

import os
from pathlib import Path

from hypothesis import settings


# pylint: skip-file


CI = "CI"
PACKAGE_DIR = Path(__file__).parent.parent
settings.register_profile(CI, deadline=5000)
profile_name = ("default", "CI")[bool(os.getenv("CI"))]
Loading