Skip to content

Commit

Permalink
Changed coingecko API
Browse files Browse the repository at this point in the history
close #511
  • Loading branch information
StephanAkkerman committed Aug 5, 2024
1 parent 3a6018f commit 88113d5
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 51 deletions.
2 changes: 2 additions & 0 deletions data/bitcoin_data.csv
Original file line number Diff line number Diff line change
Expand Up @@ -5706,3 +5706,5 @@ Date,Value
2024-08-02,61498.33
2024-08-02,61498.33
2024-08-03,60697.99
2024-08-03,60697.99
2024-08-04,58161.0
2 changes: 0 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
yahoo-fin==0.8.9.1
numpy==1.26.4
yfinance==0.2.41
pycoingecko==3.1.0
pandas==2.2.2
requests==2.32.3
PyYAML==6.0.1
Expand All @@ -17,7 +16,6 @@ py-cord==2.6.0
python-dotenv==1.0.1
tls-client==1.0.1
uncurl==0.0.11
yahooquery==2.3.7
nltk==3.8.1
timm==1.0.8
seaborn==0.13.2
Expand Down
58 changes: 38 additions & 20 deletions src/api/coingecko.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
##> Imports
# > Standard libaries
from __future__ import annotations

import numbers
Expand All @@ -10,35 +8,54 @@
from typing import List, Optional

import pandas as pd
import tls_client
from bs4 import BeautifulSoup

# > Third party libraries
from pycoingecko import CoinGeckoAPI

import util.vars
from api.http_client import get_json_data, session
from api.tradingview import tv

# Local dependencies
from constants.logger import logger
from constants.stable_coins import stables
from util.formatting import format_change

cg = CoinGeckoAPI()
session = tls_client.Session(
client_identifier="chrome112", random_tls_extension_order=True
)

async def get_coin_by_id(id: str) -> dict:
data = await get_json_data(f"https://api.coingecko.com/api/v3/coins/{id}")
return data


async def get_coins_markets(currency: str = "usd") -> list:
data = await get_json_data(
f"https://api.coingecko.com/api/v3/coins/markets?vs_currency={currency}"
)
return data


async def get_exchange_tickers(exchange_id: str = "binance") -> dict:
data = await get_json_data(
f"https://api.coingecko.com/api/v3/exchanges/{exchange_id}/tickers"
)
return data


async def get_search_trending() -> dict:
data = await get_json_data("https://api.coingecko.com/api/v3/search/trending")
return data


async def get_coins_list() -> list:
data = await get_json_data("https://api.coingecko.com/api/v3/coins/list")
return data


def get_crypto_info(ids):
async def get_crypto_info(ids):
if len(ids) > 1:
id = None
best_vol = 0
coin_dict = None
for symbol in ids.values:
# Catch potential errors
try:
coin_info = cg.get_coin_by_id(symbol)
coin_info = await get_coin_by_id(symbol)
if "usd" in coin_info["market_data"]["total_volume"]:
volume = coin_info["market_data"]["total_volume"]["usd"]
if volume > best_vol:
Expand All @@ -53,7 +70,7 @@ def get_crypto_info(ids):
id = ids.values[0]
# Try in case the CoinGecko API does not work
try:
coin_dict = cg.get_coin_by_id(id)
coin_dict = await get_coin_by_id(id)
except Exception as e:
logger.error(f"Error getting coin info for {id}, Error: {e}")
return None, None
Expand Down Expand Up @@ -163,7 +180,7 @@ async def get_coin_info(
if ticker in util.vars.cg_db["symbol"].values:
# Check coin by symbol, i.e. "BTC"
logger.debug(f"Cg_data ticker: {ticker}")
coin_dict, id = get_crypto_info(
coin_dict, id = await get_crypto_info(
util.vars.cg_db[util.vars.cg_db["symbol"] == ticker]["id"]
)

Expand All @@ -189,13 +206,13 @@ async def get_coin_info(

# Third option is to check by id
elif ticker.lower() in util.vars.cg_db["id"].values:
coin_dict, id = get_crypto_info(
coin_dict, id = await get_crypto_info(
util.vars.cg_db[util.vars.cg_db["id"] == ticker.lower()]["id"]
)

# Fourth option is to check by name, i.e. "Bitcoin"
elif ticker in util.vars.cg_db["name"].values:
coin_dict, id = get_crypto_info(
coin_dict, id = await get_crypto_info(
util.vars.cg_db[util.vars.cg_db["name"] == ticker]["id"]
)

Expand Down Expand Up @@ -340,7 +357,7 @@ async def get_top_categories() -> pd.DataFrame | None:
return pd.DataFrame(data)


def get_top_vol_coins(length: int = 50) -> list:
async def get_top_vol_coins(length: int = 50) -> list:
CACHE_FILE = "data/top_vol_coins_cache.pkl"
CACHE_EXPIRATION = 24 * 60 * 60 # 24 hours in seconds
# List of symbols to exclude
Expand Down Expand Up @@ -370,7 +387,8 @@ def get_top_vol_coins(length: int = 50) -> list:
return cache_data["data"][:length]

# Fetch fresh data if the cache is missing or expired
df = pd.DataFrame(cg.get_coins_markets("usd"))["symbol"].str.upper() + "USDT"
data = await get_coins_markets("usd")
df = pd.DataFrame(data)["symbol"].str.upper() + "USDT"

sorted_volume = df[~df.isin(STABLE_COINS)]
top_vol_coins = sorted_volume.tolist()
Expand Down
6 changes: 6 additions & 0 deletions src/api/http_client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json

import aiohttp
import tls_client

from constants.logger import logger

Expand Down Expand Up @@ -72,3 +73,8 @@ async def post_json_data(
logger.error(f"Error with POST request for {url}.\nError: {e}")

return {}


session = tls_client.Session(
client_identifier="chrome112", random_tls_extension_order=True
)
19 changes: 8 additions & 11 deletions src/api/yahoo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
from io import StringIO
from typing import List, Optional

from yahooquery import Ticker

from api.http_client import get_json_data
from api.tradingview import tv
from constants.logger import logger
from util.afterhours import afterHours
from util.formatting import format_change

headers = {
Expand Down Expand Up @@ -66,16 +63,16 @@ async def yf_info(ticker: str, do_format_change: bool = True):
try:
# No results when asynchronous=True
logger.info(f"Getting Yahoo Finance data for {ticker}")
stock_info = Ticker(ticker, asynchronous=False).price
# stock_info = Ticker(ticker, asynchronous=False).price
stock_info = await all_info(ticker) # could also use ohlcv function
stock_info = stock_info["chart"]["result"][0]["meta"]
except Exception as e:
logger.error(f"Error in getting Yahoo Finance data for {ticker}: {e}")
return None

# Test if the ticker is valid
if not isinstance(stock_info.get(ticker), dict):
if stock_info == {}:
return None

stock_info = stock_info[ticker]
prices = []
changes = []

Expand All @@ -90,9 +87,9 @@ def append_price_data(price_key, change_key):
changes.append(change or "N/A") # Handle None or missing change

# Determine which price to report based on market hours
if afterHours():
append_price_data("preMarketPrice", "preMarketChangePercent")
append_price_data("currentPrice", "regularMarketChangePercent")
# if afterHours():
# append_price_data("preMarketPrice", "preMarketChangePercent")
append_price_data("regularMarketPrice", "regularMarketChangePercent")

# Calculate volume
volume: float = (
Expand All @@ -101,7 +98,7 @@ def append_price_data(price_key, change_key):

# Prepare return values
url: str = f"https://finance.yahoo.com/quote/{ticker}"
exchange: str = stock_info.get("exchange", [])
# exchange: str = stock_info.get("fullExchangeName", [])

return volume, url, [], prices, changes if changes else ["N/A"], ticker

Expand Down
2 changes: 1 addition & 1 deletion src/cogs/loops/funding_heatmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ async def post_heatmap(self):
async def get_all_funding_rates(NUM_COINS: int = 30):
# TODO: Check if there is new data and save it
b = BinanceClient()
symbols = get_top_vol_coins(NUM_COINS)
symbols = await get_top_vol_coins(NUM_COINS)

os.makedirs("data/funding_rate", exist_ok=True)

Expand Down
5 changes: 3 additions & 2 deletions src/cogs/loops/nfts.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from discord.ext.tasks import loop

from api.cmc import top_cmc, upcoming_cmc
from api.coingecko import cg
from api.coingecko import get_search_trending
from api.opensea import get_opensea
from api.play2earn import p2e_games
from constants.config import config
Expand Down Expand Up @@ -159,7 +159,8 @@ async def opensea_trending(self):
await self.trending_channel.send(embed=e)

async def gc_trending(self):
df = pd.DataFrame(cg.get_search_trending()["nfts"])
search_trending = await get_search_trending()
df = pd.DataFrame(search_trending["nfts"])

# Add URL
df["url"] = "https://www.coingecko.com/en/nft/" + df["id"]
Expand Down
16 changes: 12 additions & 4 deletions src/cogs/loops/reddit.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,17 @@ async def wsb_scraper(self):
self.wsb_channel = await get_channel(
self.bot, config["LOOPS"]["REDDIT"]["WALLSTREETBETS"]["CHANNEL"]
)
posts = await reddit_scraper(subreddit_name="WallStreetBets")
posts = await reddit_scraper(
subreddit_name="WallStreetBets", reddit_client=self.reddit
)
self.send_posts(posts, "WallStreetBets")
self.first_time = False

# To prevent it from going to quick
if not self.first_time:
posts = await reddit_scraper(subreddit_name="WallStreetBets")
posts = await reddit_scraper(
subreddit_name="WallStreetBets", reddit_client=self.reddit
)
self.send_posts(posts, "WallStreetBets")

@loop(hours=12)
Expand All @@ -61,12 +65,16 @@ async def cms_scraper(self):
self.cmc_channel = await get_channel(
self.bot, config["LOOPS"]["REDDIT"]["CRYPTOMOONSHOTS"]["CHANNEL"]
)
posts = await reddit_scraper(subreddit_name="CryptoMoonShots")
posts = await reddit_scraper(
subreddit_name="CryptoMoonShots", reddit_client=self.reddit
)
self.send_posts(posts, "CryptoMoonShots")
self.first_time = False

if not self.first_time:
posts = await reddit_scraper(subreddit_name="CryptoMoonShots")
posts = await reddit_scraper(
subreddit_name="CryptoMoonShots", reddit_client=self.reddit
)
self.send_posts(posts, "CryptoMoonShots")

async def send_posts(self, posts: list, subreddit_name: str):
Expand Down
6 changes: 3 additions & 3 deletions src/cogs/loops/rsi_heatmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ async def post_rsi_heatmap(self) -> None:
self.bot, config["LOOPS"]["RSI_HEATMAP"]["CHANNEL"]
)

plot_rsi_heatmap()
await plot_rsi_heatmap()

e = discord.Embed(
title="Crypto Market RSI Heatmap",
Expand Down Expand Up @@ -92,8 +92,8 @@ def get_color_for_rsi(rsi_value: float) -> dict:
return None


def plot_rsi_heatmap(num_coins: int = 100, time_frame: str = "1d") -> None:
top_vol = get_top_vol_coins(num_coins)
async def plot_rsi_heatmap(num_coins: int = 100, time_frame: str = "1d") -> None:
top_vol = await get_top_vol_coins(num_coins)
rsi_data = get_RSI(top_vol, time_frame=time_frame)
old_rsi_data = get_closest_to_24h(time_frame=time_frame)

Expand Down
11 changes: 3 additions & 8 deletions src/util/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,13 @@
from collections import defaultdict

import numpy as np

# > 3rd party dependencies
import pandas as pd

# > Discord dependencies
from discord.ext import commands
from discord.ext.tasks import loop
from pycoingecko import CoinGeckoAPI
from yahoo_fin.stock_info import tickers_nasdaq

# > Local dependencies
import util.vars
from api.coingecko import get_coins_list
from api.tradingview import get_tv_ticker_data
from constants.logger import logger
from constants.tradingview import all_forex_indices, crypto_indices, stock_indices
Expand Down Expand Up @@ -89,8 +84,8 @@ async def set_nasdaq_tickers(self):
@loop(hours=24)
async def set_cg_db(self):
# Saves all CoinGecko coins, maybe refresh this daily
cg = CoinGeckoAPI()
cg_coins = pd.DataFrame(cg.get_coins_list())
coin_list = await get_coins_list()
cg_coins = pd.DataFrame(coin_list)
cg_coins["symbol"] = cg_coins["symbol"].str.upper()

# Save cg_coins to database
Expand Down

0 comments on commit 88113d5

Please sign in to comment.