Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Bet and Strategy #141

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
142 changes: 23 additions & 119 deletions TwitchChannelPointsMiner/classes/entities/Bet.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
import copy
from enum import Enum, auto
from random import uniform

from millify import millify

#from TwitchChannelPointsMiner.utils import char_decision_as_index, float_round
from TwitchChannelPointsMiner.utils import float_round


class Strategy(Enum):
MOST_VOTED = auto()
HIGH_ODDS = auto()
PERCENTAGE = auto()
SMART_MONEY = auto()
SMART = auto()
from TwitchChannelPointsMiner.classes.entities.Strategy import (
OutcomeKeys,
Strategy,
StrategySettings,
)

def __str__(self):
return self.name
from TwitchChannelPointsMiner.utils import float_round


class Condition(Enum):
Expand All @@ -29,20 +22,6 @@ def __str__(self):
return self.name


class OutcomeKeys(object):
# Real key on Bet dict ['']
PERCENTAGE_USERS = "percentage_users"
ODDS_PERCENTAGE = "odds_percentage"
ODDS = "odds"
TOP_POINTS = "top_points"
# Real key on Bet dict [''] - Sum()
TOTAL_USERS = "total_users"
TOTAL_POINTS = "total_points"
# This key does not exist
DECISION_USERS = "decision_users"
DECISION_POINTS = "decision_points"


class DelayMode(Enum):
FROM_START = auto()
FROM_END = auto()
Expand Down Expand Up @@ -72,43 +51,46 @@ class BetSettings(object):
__slots__ = [
"strategy",
"percentage",
"percentage_gap",
"max_points",
"only_doubt",
"minimum_points",
"stealth_mode",
"filter_condition",
"delay",
"delay_mode",
"strategy_settings",
]

def __init__(
self,
strategy: Strategy = None,
percentage: int = None,
percentage_gap: int = None,
max_points: int = None,
only_doubt: bool = None,
minimum_points: int = None,
stealth_mode: bool = None,
filter_condition: FilterCondition = None,
delay: float = None,
delay_mode: DelayMode = None,
strategy_settings: StrategySettings = None,
):
self.strategy = strategy
self.percentage = percentage
self.percentage_gap = percentage_gap
self.max_points = max_points
self.only_doubt = only_doubt
self.minimum_points = minimum_points
self.stealth_mode = stealth_mode
self.filter_condition = filter_condition
self.delay = delay
self.delay_mode = delay_mode
self.strategy_settings = StrategySettings(
strategy=strategy, **strategy_settings
).get_instance()

def default(self):
self.strategy = self.strategy if self.strategy is not None else Strategy.SMART
self.percentage = self.percentage if self.percentage is not None else 5
self.percentage_gap = (
self.percentage_gap if self.percentage_gap is not None else 20
)
self.only_doubt = self.only_doubt if self.only_doubt is not None else False
self.max_points = self.max_points if self.max_points is not None else 50000
self.minimum_points = (
self.minimum_points if self.minimum_points is not None else 0
Expand All @@ -120,13 +102,16 @@ def default(self):
self.delay_mode = (
self.delay_mode if self.delay_mode is not None else DelayMode.FROM_END
)
self.strategy_settings = (
self.strategy_settings if self.strategy_settings is not None else {}
)

def __repr__(self):
return f"BetSettings(strategy={self.strategy}, percentage={self.percentage}, percentage_gap={self.percentage_gap}, max_points={self.max_points}, minimum_points={self.minimum_points}, stealth_mode={self.stealth_mode})"
return f"BetSettings(strategy={self.strategy}, percentage={self.percentage}, max_points={self.max_points}, minimum_points={self.minimum_points}, stealth_mode={self.stealth_mode})"


class Bet(object):
__slots__ = ["outcomes", "decision", "total_users", "total_points", "settings"]
__slots__ = ["outcomes", "decision", "total_users", "total_points", "settings", "strategy"]

def __init__(self, outcomes: list, settings: BetSettings):
self.outcomes = outcomes
Expand Down Expand Up @@ -225,91 +210,10 @@ def __clear_outcomes(self):
if key not in self.outcomes[index]:
self.outcomes[index][key] = 0

'''def __return_choice(self, key) -> str:
return "A" if self.outcomes[0][key] > self.outcomes[1][key] else "B"'''

def __return_choice(self, key) -> int:
largest=0
for index in range(0, len(self.outcomes)):
if self.outcomes[index][key] > self.outcomes[largest][key]:
largest = index
return largest

def skip(self) -> bool:
if self.settings.filter_condition is not None:
# key == by , condition == where
key = self.settings.filter_condition.by
condition = self.settings.filter_condition.where
value = self.settings.filter_condition.value

fixed_key = (
key
if key not in [OutcomeKeys.DECISION_USERS, OutcomeKeys.DECISION_POINTS]
else key.replace("decision", "total")
)
if key in [OutcomeKeys.TOTAL_USERS, OutcomeKeys.TOTAL_POINTS]:
compared_value = (
self.outcomes[0][fixed_key] + self.outcomes[1][fixed_key]
)
else:
#outcome_index = char_decision_as_index(self.decision["choice"])
outcome_index = self.decision["choice"]
compared_value = self.outcomes[outcome_index][fixed_key]

# Check if condition is satisfied
if condition == Condition.GT:
if compared_value > value:
return False, compared_value
elif condition == Condition.LT:
if compared_value < value:
return False, compared_value
elif condition == Condition.GTE:
if compared_value >= value:
return False, compared_value
elif condition == Condition.LTE:
if compared_value <= value:
return False, compared_value
return True, compared_value # Else skip the bet
else:
return False, 0 # Default don't skip the bet
return self.strategy.skip()

def calculate(self, balance: int) -> dict:
self.decision = {"choice": None, "amount": 0, "id": None}
if self.settings.strategy == Strategy.MOST_VOTED:
self.decision["choice"] = self.__return_choice(OutcomeKeys.TOTAL_USERS)
elif self.settings.strategy == Strategy.HIGH_ODDS:
self.decision["choice"] = self.__return_choice(OutcomeKeys.ODDS)
elif self.settings.strategy == Strategy.PERCENTAGE:
self.decision["choice"] = self.__return_choice(OutcomeKeys.ODDS_PERCENTAGE)
elif self.settings.strategy == Strategy.SMART_MONEY:
self.decision["choice"] = self.__return_choice(OutcomeKeys.TOP_POINTS)
elif self.settings.strategy == Strategy.SMART:
difference = abs(
self.outcomes[0][OutcomeKeys.PERCENTAGE_USERS]
- self.outcomes[1][OutcomeKeys.PERCENTAGE_USERS]
)
self.decision["choice"] = (
self.__return_choice(OutcomeKeys.ODDS)
if difference < self.settings.percentage_gap
else self.__return_choice(OutcomeKeys.TOTAL_USERS)
)

if self.decision["choice"] is not None:
#index = char_decision_as_index(self.decision["choice"])
index = self.decision["choice"]
self.decision["id"] = self.outcomes[index]["id"]
self.decision["amount"] = min(
int(balance * (self.settings.percentage / 100)),
self.settings.max_points,
)
if (
self.settings.stealth_mode is True
and self.decision["amount"]
>= self.outcomes[index][OutcomeKeys.TOP_POINTS]
):
reduce_amount = uniform(1, 5)
self.decision["amount"] = (
self.outcomes[index][OutcomeKeys.TOP_POINTS] - reduce_amount
)
self.decision["amount"] = int(self.decision["amount"])
self.strategy = Strategy(self.outcomes, self.settings).get_instance()
self.decision = self.strategy.calculate(balance)
return self.decision
155 changes: 155 additions & 0 deletions TwitchChannelPointsMiner/classes/entities/Strategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
from enum import Enum, auto
from importlib import import_module
from random import uniform


class Condition(Enum):
GT = auto()
LT = auto()
GTE = auto()
LTE = auto()

def __str__(self):
return self.name


class OutcomeKeys(object):
# Real key on Bet dict ['']
PERCENTAGE_USERS = "percentage_users"
ODDS_PERCENTAGE = "odds_percentage"
ODDS = "odds"
TOP_POINTS = "top_points"
# Real key on Bet dict [''] - Sum()
TOTAL_USERS = "total_users"
TOTAL_POINTS = "total_points"
# This key does not exist
DECISION_USERS = "decision_users"
DECISION_POINTS = "decision_points"


class Strategy(object):
MOST_VOTED = "MostVoted"
HIGH_ODDS = "HighOdds"
SMART_HIGH_ODDS = "SmartHighOdds"
PERCENTAGE = "Percentage"
SMART = "Smart"

def __init__(self, outcomes: list, settings: object):
self.outcomes = outcomes
self.decision: dict = {}
self.settings = settings

def get_instance(self):
strategy_module = import_module(
f".{self.settings.strategy}", package=f"{__package__}.strategies"
)
subclass = getattr(strategy_module, self.settings.strategy)
return subclass(self.outcomes, self.settings)

def return_choice(self, key) -> int:
largest = 0
for index in range(0, len(self.outcomes)):
if self.outcomes[index][key] > self.outcomes[largest][key]:
largest = index
return largest

def calculate_before(self):
self.decision = {"choice": None, "amount": 0, "id": None}

def calculate_middle(self):
pass

def calculate_after(self, balance: int):
if self.settings.only_doubt:
self.decision["choice"] = 1
if self.decision["choice"] is not None:
index = self.decision["choice"]
self.decision["id"] = self.outcomes[index]["id"]
amounts = [
self.decision["amount"],
int(balance * (self.settings.percentage / 100)),
self.settings.max_points,
]
self.decision["amount"] = min(x for x in amounts if x != 0)
if (
self.settings.stealth_mode is True
and self.decision["amount"]
>= self.outcomes[index][OutcomeKeys.TOP_POINTS]
):
reduce_amount = uniform(1, 5)
# check by
# grep -r --include=*.log "Bet won't be placed as the amount -[0-9] is less than the minimum required 10" .
self.decision["amount"] = (
self.outcomes[index][OutcomeKeys.TOP_POINTS] - reduce_amount
)
if self.decision["amount"] < 10: self.decision["amount"] = 10
self.decision["amount"] = int(self.decision["amount"])

def calculate(self, balance: int) -> dict:
self.calculate_before()
self.calculate_middle()
self.calculate_after(balance)
return self.decision

def skip_before(self):
pass

def skip_middle(self):
pass

def skip_after(self):
if self.settings.filter_condition is not None:
# key == by , condition == where
key = self.settings.filter_condition.by
condition = self.settings.filter_condition.where
value = self.settings.filter_condition.value

fixed_key = (
key
if key not in [OutcomeKeys.DECISION_USERS, OutcomeKeys.DECISION_POINTS]
else key.replace("decision", "total")
)
if key in [OutcomeKeys.TOTAL_USERS, OutcomeKeys.TOTAL_POINTS]:
compared_value = (
self.outcomes[0][fixed_key] + self.outcomes[1][fixed_key]
)
else:
outcome_index = self.decision["choice"]
compared_value = self.outcomes[outcome_index][fixed_key]

# Check if condition is satisfied
if condition == Condition.GT:
if compared_value > value:
return False, compared_value
elif condition == Condition.LT:
if compared_value < value:
return False, compared_value
elif condition == Condition.GTE:
if compared_value >= value:
return False, compared_value
elif condition == Condition.LTE:
if compared_value <= value:
return False, compared_value
return True, compared_value # Else skip the bet
else:
return False, 0 # Default don't skip the bet

def skip(self) -> bool:
skip_results = [self.skip_before(), self.skip_middle(), self.skip_after()]
return next(item for item in skip_results if item is not None)

def __str__(self):
return self.name


class StrategySettings(object):
def __init__(self, strategy: Strategy = None, **kwargs):
strategy_module = import_module(
f".{strategy}", package=f"{__package__}.strategies"
)
subclass = getattr(strategy_module, f"{strategy}Settings")
self.instance = subclass(**kwargs)
self.instance.default()

def get_instance(self):
return self.instance
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from TwitchChannelPointsMiner.classes.entities.Strategy import OutcomeKeys, Strategy


class HighOdds(Strategy):
def calculate_middle(self):
self.decision["choice"] = self.return_choice(OutcomeKeys.ODDS)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from TwitchChannelPointsMiner.classes.entities.Strategy import OutcomeKeys, Strategy


class MostVoted(Strategy):
def calculate_middle(self):
self.decision["choice"] = self.return_choice(OutcomeKeys.TOTAL_USERS)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from TwitchChannelPointsMiner.classes.entities.Strategy import OutcomeKeys, Strategy


class Percentage(Strategy):
def calculate_middle(self):
self.decision["choice"] = self.return_choice(OutcomeKeys.ODDS_PERCENTAGE)
Loading