Skip to content

Commit

Permalink
Improved User Leaderboard Ranking + bugfix
Browse files Browse the repository at this point in the history
The changes optimize fetching of current cryptocurrency prices by preloading all necessary values from Redis in a single operation. Additionally, the refactored code ensures accurate mapping of user balances to their corresponding users by using a dictionary, and streamlines the calculation of total asset values by filtering out non-asset columns only once, leading to more efficient and accurate ranking of users based on their total asset value. (There were some bugs calculating the estimated asset values incorrectly)
  • Loading branch information
KnightChaser committed Jun 8, 2024
1 parent d4899c8 commit 24bb025
Showing 1 changed file with 19 additions and 29 deletions.
48 changes: 19 additions & 29 deletions tasks/ranking_user_leaderboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
import json
from sqlalchemy.orm import Session
from rich.console import Console
from typing import List
from typing import List, Dict

# Note that these packages are in the parent directory
import sys
sys.path.append("..")
from database_session import get_sqlite3_db, get_redis_db
Expand All @@ -29,39 +28,30 @@ def rank_user_leaderboard(update_interval_in_seconds: int) -> None:
sqlite3_db: Session = next(get_sqlite3_db())
redis_db = get_redis_db()

# Get the user's balances from the SQLite3 database
# Get the users and their balances from the SQLite3 database
users: List[User] = sqlite3_db.query(User).all()
user_balances: List[Balance] = sqlite3_db.query(Balance).all()
user_balances: Dict[int, Balance] = {balance.user_id: balance for balance in sqlite3_db.query(Balance).all()}

user_total_assets = {user.id: user_balance.KRW for user, user_balance in zip(users, user_balances)}
user_total_assets = {}

# Calculate the user's total asset value by considering the current market price(Redis)
# (user's total asset value) = (user's KRW balance) + (user's BTC balance) * (current BTC price) + ... (for all currencies)
for user in users:
for user_balance_data_row in user_balances:
# Get all available cryptocurrency types
availble_crypto_asset_type: List[str] = user_balance_data_row.__table__.columns.keys()
availble_crypto_asset_type.remove("id")
availble_crypto_asset_type.remove("user_id")
availble_crypto_asset_type.remove("created_at")
availble_crypto_asset_type.remove("KRW")
for column in user_balance_data_row.__table__.columns.keys():
if column.endswith("_average_unit_price"):
availble_crypto_asset_type.remove(column)
# Fetch all available cryptocurrency types and current prices
all_crypto_assets = [col for col in Balance.__table__.columns.keys() if col not in {"id", "user_id", "created_at", "KRW"} and not col.endswith("_average_unit_price")]
crypto_prices = {crypto: json.loads(redis_db.get(f"KRW-{crypto}"))["trade_price"] for crypto in all_crypto_assets}

# Calculate the user's total asset value
for crypto_asset_type in availble_crypto_asset_type:
current_crypto_price = redis_db.get(f"KRW-{crypto_asset_type}")
current_crypto_price = json.loads(current_crypto_price)["trade_price"]
user_total_assets[user.id] += user_balance_data_row.__getattribute__(crypto_asset_type) * current_crypto_price
# Calculate the user's total asset value
for user in users:
balance = user_balances.get(user.id)
if balance:
total_asset_value = balance.KRW # Start with KRW balance
for crypto in all_crypto_assets:
crypto_balance = getattr(balance, crypto, 0)
current_price = crypto_prices.get(crypto, 0)
total_asset_value += crypto_balance * current_price

# Now we have the user's total asset value in the user_total_assets dictionary
# i.e. {1: 1000000, 2: 2000000, ...}
user_total_assets[user.id] = total_asset_value

# Associate the user's name with the sorted_user_total_assets's key(user ID)
user_total_assets_with_name = {}
for user in users:
user_total_assets_with_name[user.username] = user_total_assets[user.id]
# Associate the user's name with their total asset value
user_total_assets_with_name = {user.username: user_total_assets[user.id] for user in users if user.id in user_total_assets}

# Sort the user's total asset value in descending order
sorted_user_total_assets = dict(sorted(user_total_assets_with_name.items(), key=lambda item: item[1], reverse=True))
Expand Down

0 comments on commit 24bb025

Please sign in to comment.