diff --git a/backends/redoubt/tokens.py b/backends/redoubt/tokens.py index 94c9cb8..bb18df5 100644 --- a/backends/redoubt/tokens.py +++ b/backends/redoubt/tokens.py @@ -79,7 +79,13 @@ def _do_calculate(self, config: SeasonConfig, dry_run: bool = False): and build_time < to_timestamp({config.start_time}) - interval '14 day' -- end of the S4 season order by thd.address, build_time desc ), tvl_prior_start as ( - select symbol, sum(tvl_ton) as start_tvl from tvl_prior_start_all + select symbol, sum(tvl_ton) as start_tvl, + ( + select rate from ton_usd_rates + where build_time < to_timestamp({config.start_time}) - interval '14 day' + order by build_time desc limit 1 + ) * sum(tvl_ton) as start_tvl_usd + from tvl_prior_start_all group by 1 ), current_tvl as ( -- TVL during the season @@ -116,6 +122,7 @@ def _do_calculate(self, config: SeasonConfig, dry_run: bool = False): prizes, url, boost_link, coalesce(start_tvl, 0) as start_tvl, + coalesce(start_tvl_usd, 0) as start_tvl_usd, coalesce(last_tvl.tvl, 0) as last_tvl, coalesce(100 * coalesce(price_change, 0), 0) as price_delta, coalesce(price_before, 0) as price_before, @@ -148,6 +155,7 @@ def _do_calculate(self, config: SeasonConfig, dry_run: bool = False): results[row['symbol']].metrics[ProjectStat.TOKEN_IS_MEME] = row['is_meme'] results[row['symbol']].metrics[ProjectStat.TOKEN_HAS_BOOST] = row['has_boost'] results[row['symbol']].metrics[ProjectStat.TOKEN_START_TVL] = int(row['start_tvl']) + results[row['symbol']].metrics[ProjectStat.TOKEN_START_TVL_USD] = int(row['start_tvl_usd']) results[row['symbol']].metrics[ProjectStat.TOKEN_LAST_TVL] = int(row['last_tvl']) results[row['symbol']].metrics[ProjectStat.TOKEN_PRICE_BEFORE] = float(row['price_before']) results[row['symbol']].metrics[ProjectStat.TOKEN_PRICE_AFTER] = float(row['price_after']) diff --git a/models/results.py b/models/results.py index fbca765..205a54e 100644 --- a/models/results.py +++ b/models/results.py @@ -16,8 +16,10 @@ class ProjectStat: APP_ONCHAIN_UAW = 'onchain_uaw' APP_ONCHAIN_MEDIAN_TX = 'onchain_median_tx' + TOKEN_TVL_CATEGORY = 'token_tvl_category' TOKEN_TVL_CHANGE = 'token_tvl_change' TOKEN_START_TVL = 'token_start_tvl' + TOKEN_START_TVL_USD = 'token_start_tvl_usd' TOKEN_LAST_TVL = 'token_last_tvl' TOKEN_PRICE_BEFORE = 'token_price_before' TOKEN_PRICE_AFTER = 'token_price_after' diff --git a/seasons/tokens_models.py b/seasons/tokens_models.py index e7d7bf0..a9b611d 100644 --- a/seasons/tokens_models.py +++ b/seasons/tokens_models.py @@ -29,18 +29,38 @@ def calculate(self, metrics: List[ProjectStat]): """ -Token leaderboard score model, launched since S5. The only metrics is price change +Token leaderboard score model, launched since S5 +30% - base TVL Delta weight +40% - base New holders weight +30% - base Price change (normalised on sqrt(TVL)) weight """ class TokenLeaderboardModelV5(ScoreModel): def __init__(self): super().__init__() self.params[ScoreModel.PARAM_TOKEN_MIN_VALUE_FOR_NEW_HOLDER] = 1.0 # 1 TON + self.tvl_category = { + "10M – 20M": {"low": 10_000_000, "high": None, "coefficient": 1}, + "5M – 10M": {"low": 5_000_000, "high": 10_000_000, "coefficient": 0.8}, + "2M – 5M": {"low": 2_000_000, "high": 5_000_000, "coefficient": 0.6}, + "1M – 2M": {"low": 1_000_000, "high": 2_000_000, "coefficient": 0.5}, + "500K – 1M": {"low": 500_000, "high": 1_000_000, "coefficient": 0.4}, + "100K – 500K": {"low": None, "high": 500_000, "coefficient": 0.3}, + } + + def get_tvl_category(self, tvl_value) -> str: + for category_name, limits in self.tvl_category.items(): + if (not limits["low"] or tvl_value > limits["low"]) and (not limits["high"] or tvl_value <= limits["high"]): + return category_name def calculate(self, metrics: List[ProjectStat]): - MIN_TVL = 14106 # $100,000 nominated in TON for project in metrics: logger.info(f"Calculating score for {project}") - project.score = project.metrics[ProjectStat.TOKEN_LAST_TVL] - \ - max(MIN_TVL, project.metrics[ProjectStat.TOKEN_START_TVL]) + project.metrics[ProjectStat.TOKEN_TVL_CATEGORY] = self.get_tvl_category(project.metrics[ProjectStat.TOKEN_START_TVL_USD]) + price_change_weight = 30 * self.tvl_category[project.metrics[ProjectStat.TOKEN_TVL_CATEGORY]]["coefficient"] + tvl_change_weight = 30 + (30 - price_change_weight) * 3 / 7 + new_holders_weight = 40 + (30 - price_change_weight) * 4 / 7 + project.score = new_holders_weight * self.normalized_max(project, ProjectStat.TOKEN_NEW_USERS_WITH_MIN_AMOUNT, metrics) + \ + tvl_change_weight * self.normalized_min_max(project, ProjectStat.TOKEN_TVL_CHANGE, metrics) + \ + price_change_weight * self.normalized_min_max(project, ProjectStat.TOKEN_PRICE_CHANGE_NORMED, metrics) return sorted(metrics, key=lambda m: m.score, reverse=True)