diff --git a/pages/data/__init__.py b/pages/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/data/download_candles/README.md b/pages/data/download_candles/README.md new file mode 100644 index 0000000..1d08d65 --- /dev/null +++ b/pages/data/download_candles/README.md @@ -0,0 +1 @@ +Download historical exchange data as OHLVC candles. Supports multiple trading pairs and custom time ranges/intervals. \ No newline at end of file diff --git a/pages/data/download_candles/__init__.py b/pages/data/download_candles/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/data/download_candles/app.py b/pages/data/download_candles/app.py new file mode 100644 index 0000000..d03aca0 --- /dev/null +++ b/pages/data/download_candles/app.py @@ -0,0 +1,69 @@ +import streamlit as st +from datetime import datetime, time +import pandas as pd +import plotly.graph_objects as go + +from frontend.st_utils import initialize_st_page, get_backend_api_client + +# Initialize Streamlit page +initialize_st_page(title="Download Candles", icon="💾") +backend_api_client = get_backend_api_client() + +c1, c2, c3, c4 = st.columns([2, 2, 2, 0.5]) +with c1: + connector = st.selectbox("Exchange", ["binance_perpetual", "binance", "gate_io", "gate_io_perpetual", "kucoin", "ascend_ex"], index=0) + trading_pair = st.text_input("Trading Pair", value="BTC-USDT") +with c2: + interval = st.selectbox("Interval", options=["1m", "3m", "5m", "15m", "1h", "4h", "1d", "1s"]) +with c3: + start_date = st.date_input("Start Date", value=datetime(2023, 1, 1)) + end_date = st.date_input("End Date", value=datetime(2023, 1, 2)) +with c4: + get_data_button = st.button("Get Candles!") + +if get_data_button: + start_datetime = datetime.combine(start_date, time.min) + end_datetime = datetime.combine(end_date, time.max) + + candles = backend_api_client.get_historical_candles( + connector=connector, + trading_pair=trading_pair, + interval=interval, + start_time=int(start_datetime.timestamp()) * 1000, + end_time=int(end_datetime.timestamp()) * 1000 + ) + + candles_df = pd.DataFrame(candles) + candles_df.index = pd.to_datetime(candles_df["timestamp"], unit='s') + + # Plotting the candlestick chart + fig = go.Figure(data=[go.Candlestick( + x=candles_df.index, + open=candles_df['open'], + high=candles_df['high'], + low=candles_df['low'], + close=candles_df['close'], + increasing_line_color='#2ECC71', + decreasing_line_color='#E74C3C' + )]) + fig.update_layout( + height=1000, + title="Candlesticks", + xaxis_title="Time", + yaxis_title="Price", + template="plotly_dark", + showlegend=False + ) + fig.update_xaxes(rangeslider_visible=False) + fig.update_yaxes(title_text="Price") + st.plotly_chart(fig, use_container_width=True) + + # Generating CSV and download button + csv = candles_df.to_csv(index=False) + filename = f"{connector}_{trading_pair}_{start_date.strftime('%Y%m%d')}_{end_date.strftime('%Y%m%d')}.csv" + st.download_button( + label="Download Candles as CSV", + data=csv, + file_name=filename, + mime='text/csv', + ) diff --git a/pages/data/token_spreads/README.md b/pages/data/token_spreads/README.md new file mode 100644 index 0000000..4225df8 --- /dev/null +++ b/pages/data/token_spreads/README.md @@ -0,0 +1 @@ +Identify cross-exchange trading opportunities by analyzing differences in token spreads across venues \ No newline at end of file diff --git a/pages/data/token_spreads/__init__.py b/pages/data/token_spreads/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/data/token_spreads/app.py b/pages/data/token_spreads/app.py new file mode 100644 index 0000000..56a30f6 --- /dev/null +++ b/pages/data/token_spreads/app.py @@ -0,0 +1,77 @@ +import streamlit as st +import plotly.express as px +import CONFIG +from backend.services.coingecko_client import CoinGeckoClient +from backend.services.miner_client import MinerClient +from frontend.st_utils import initialize_st_page + +initialize_st_page(title="Token Spreads", icon="🧙") + +# Start content here +cg_utils = CoinGeckoClient() +miner_utils = MinerClient() + +@st.cache_data +def get_all_coins_df(): + return cg_utils.get_all_coins_df() + +@st.cache_data +def get_all_exchanges_df(): + return cg_utils.get_all_exchanges_df() + +@st.cache_data +def get_miner_stats_df(): + return miner_utils.get_miner_stats_df() + +@st.cache_data +def get_coin_tickers_by_id_list(coins_id: list): + return cg_utils.get_coin_tickers_by_id_list(coins_id) + +with st.spinner(text='In progress'): + exchanges_df = get_all_exchanges_df() + coins_df = get_all_coins_df() + miner_stats_df = get_miner_stats_df() + +miner_coins = coins_df.loc[coins_df["symbol"].isin(miner_stats_df["base"].str.lower().unique()), "name"] + +tokens = st.multiselect( + "Select the tokens to analyze:", + options=coins_df["name"], + default=CONFIG.DEFAULT_MINER_COINS +) + +coins_id = coins_df.loc[coins_df["name"].isin(tokens), "id"].tolist() + +coin_tickers_df = get_coin_tickers_by_id_list(coins_id) +coin_tickers_df["coin_name"] = coin_tickers_df.apply(lambda x: coins_df.loc[coins_df["id"] == x.token_id, "name"].item(), axis=1) + +exchanges = st.multiselect( + "Select the exchanges to analyze:", + options=exchanges_df["name"], + default=[exchange for exchange in CONFIG.MINER_EXCHANGES if exchange in exchanges_df["name"].unique()] +) + +height = len(coin_tickers_df["coin_name"].unique()) * 500 + +fig = px.scatter( + data_frame=coin_tickers_df[coin_tickers_df["exchange"].isin(exchanges)], + x="volume", + y="bid_ask_spread_percentage", + color="exchange", + log_x=True, + log_y=True, + facet_col="coin_name", + hover_data=["trading_pair"], + facet_col_wrap=1, + height=height, + template="plotly_dark", + title="Spread and Volume Chart", + labels={ + "volume": 'Volume (USD)', + 'bid_ask_spread_percentage': 'Bid Ask Spread (%)' + } +) + +# st.write("# Data filters 🏷") +# st.code("🧳 New filters coming. \nReach us on discord \nif you want to propose one!") +st.plotly_chart(fig, use_container_width=True) diff --git a/pages/data/tvl_vs_mcap/README.md b/pages/data/tvl_vs_mcap/README.md new file mode 100644 index 0000000..251fc88 --- /dev/null +++ b/pages/data/tvl_vs_mcap/README.md @@ -0,0 +1,3 @@ +Easily compare various DeFi protocols based on their market capitalization and total value locked, using DeFiLlama data. + +Data Source: [DefiLlama](https://defillama.com/) diff --git a/pages/data/tvl_vs_mcap/__init__.py b/pages/data/tvl_vs_mcap/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/data/tvl_vs_mcap/app.py b/pages/data/tvl_vs_mcap/app.py new file mode 100644 index 0000000..48e276f --- /dev/null +++ b/pages/data/tvl_vs_mcap/app.py @@ -0,0 +1,70 @@ +import numpy as np +import streamlit as st +import pandas as pd +import plotly.express as px +from defillama import DefiLlama + +from frontend.st_utils import initialize_st_page + +initialize_st_page(title="TVL vs Market Cap", icon="🦉") + +# Start content here +MIN_TVL = 1000000. +MIN_MCAP = 1000000. + +@st.cache_data +def get_tvl_mcap_data(): + llama = DefiLlama() + df = pd.DataFrame(llama.get_all_protocols()) + tvl_mcap_df = df.loc[(df["tvl"]>0) & (df["mcap"]>0), ["name", "tvl", "mcap", "chain", "category", "slug"]].sort_values(by=["mcap"], ascending=False) + return tvl_mcap_df[(tvl_mcap_df["tvl"] > MIN_TVL) & (tvl_mcap_df["mcap"]> MIN_MCAP)] + +def get_protocols_by_chain_category(protocols: pd.DataFrame, group_by: list, nth: list): + return protocols.sort_values('tvl', ascending=False).groupby(group_by).nth(nth).reset_index() + +with st.spinner(text='In progress'): + tvl_mcap_df = get_tvl_mcap_data() + +default_chains = ["Ethereum", "Solana", "Binance", "Polygon", "Multi-Chain", "Avalanche"] + +st.write("### Chains 🔗") +chains = st.multiselect( + "Select the chains to analyze:", + options=tvl_mcap_df["chain"].unique(), + default=default_chains) + +scatter = px.scatter( + data_frame=tvl_mcap_df[tvl_mcap_df["chain"].isin(chains)], + x="tvl", + y="mcap", + color="chain", + trendline="ols", + log_x=True, + log_y=True, + height=800, + hover_data=["name"], + template="plotly_dark", + title="TVL vs MCAP", + labels={ + "tvl": 'TVL (USD)', + 'mcap': 'Market Cap (USD)' + }) + +st.plotly_chart(scatter, use_container_width=True) + +st.write("---") +st.write("### SunBurst 🌞") +groupby = st.selectbox('Group by:', [['chain', 'category'], ['category', 'chain']]) +nth = st.slider('Top protocols by Category', min_value=1, max_value=5) + +proto_agg = get_protocols_by_chain_category(tvl_mcap_df[tvl_mcap_df["chain"].isin(chains)], groupby, np.arange(0, nth, 1).tolist()) +groupby.append("slug") +sunburst = px.sunburst( + proto_agg, + path=groupby, + values='tvl', + height=800, + title="SunBurst", + template="plotly_dark",) + +st.plotly_chart(sunburst, use_container_width=True) \ No newline at end of file