diff --git a/dashboard/About.py b/dashboard/About.py new file mode 100644 index 00000000..57a71bd8 --- /dev/null +++ b/dashboard/About.py @@ -0,0 +1,56 @@ +import streamlit as st +from st_pages import Page, show_pages, add_page_title + +st.set_page_config(page_title="Synthetix Dashboards", layout="wide") + +hide_footer = """ + +""" +st.markdown(hide_footer, unsafe_allow_html=True) + +st.markdown( + """ + +# Synthetix V3 Analytics + +Discover the latest insights into the Synthetix V3 ecosystem. + +## Base Andromeda Release + +Andromeda, the latest Synthetix V3 deployment on the Base network, allows liquidity provision with USDC and seamless trading of perps using USDC collateral. For details, explore our [blog post](https://blog.synthetix.io/what-is-the-andromeda-release/). + +### Dashboards: +- **Perps Stats**: Insights on volume, fees, and more across all markets. +- **Perps Markets**: Insights for each perps market. +- **Perps Monitor**: A consolidated view of all perps markets. +- **Core Stats**: Key metrics of the Core system, including debt, collateral, and LP performance. +- **Spot Markets**: Analysis of the USDC wrapper contracts. +- **Perps Integrators**: Activity overview by integrator. +- **Perps Accounts**: View recent activity by specific accounts. +- **Perps Keepers**: Track community keepers' settlement transactions. + +## Additional Resources +- V3 details: [documentation](https://docs.synthetix.io/v/v3/) +- Updates: [blog](https://blog.synthetix.io/) +- Community: [discord](https://discord.com/invite/AEdUHzt) +""" +) + +# page setup +PAGE_PREFIX = "dashboard/" if st.secrets.settings.IS_CLOUD == "true" else "" +SHOW_OP = True if st.secrets.settings.SHOW_OP == "true" else False + +home_page = [Page(f"{PAGE_PREFIX}About.py", "About")] +op_pages = [ + Page(f"{PAGE_PREFIX}pages/OP_Mainnet.py", "OP Mainnet"), +] +base_pages = [ + Page(f"{PAGE_PREFIX}pages/Base_Mainnet.py", "Base Mainnet"), + Page(f"{PAGE_PREFIX}pages/Base_Sepolia.py", "Base Sepolia"), +] + +# pages to show +pages_to_show = home_page + (op_pages if SHOW_OP else []) + base_pages +show_pages(pages_to_show) diff --git a/dashboard/Dockerfile b/dashboard/Dockerfile index 46b2837a..e32867f4 100644 --- a/dashboard/Dockerfile +++ b/dashboard/Dockerfile @@ -15,4 +15,4 @@ RUN pip install --no-cache-dir -r requirements.txt COPY . . # Command to run the service -CMD ["streamlit", "run", "Home.py"] +CMD ["streamlit", "run", "About.py"] diff --git a/dashboard/Home.py b/dashboard/Home.py deleted file mode 100644 index 81b3bbab..00000000 --- a/dashboard/Home.py +++ /dev/null @@ -1,36 +0,0 @@ -import streamlit as st -from st_pages import Page, show_pages, add_page_title - -st.set_page_config(page_title="Synthetix Dashboards", layout="wide") - -hide_footer = """ - -""" -st.markdown(hide_footer, unsafe_allow_html=True) - -st.write("# Synthetix Dashboards") - -st.markdown( - """ -Use the sidebar to select a chain. The dashboard selector will appear below. -""" -) - -# page setup -PAGE_PREFIX = "dashboard/" if st.secrets.settings.IS_CLOUD == "true" else "" -SHOW_OP = True if st.secrets.settings.SHOW_OP == "true" else False - -home_page = [Page(f"{PAGE_PREFIX}network_pages/Home.py", "Home")] -op_pages = [ - Page(f"{PAGE_PREFIX}network_pages/OP_Mainnet.py", "OP Mainnet"), -] -base_pages = [ - Page(f"{PAGE_PREFIX}network_pages/Base_Mainnet.py", "Base Mainnet"), - Page(f"{PAGE_PREFIX}network_pages/Base_Sepolia.py", "Base Sepolia"), -] - -# pages to show -pages_to_show = home_page + (op_pages if SHOW_OP else []) + base_pages -show_pages(pages_to_show) diff --git a/dashboard/modules/base_mainnet/core_stats.py b/dashboard/modules/base_mainnet/core_stats.py index f85fbf76..ef165588 100644 --- a/dashboard/modules/base_mainnet/core_stats.py +++ b/dashboard/modules/base_mainnet/core_stats.py @@ -66,6 +66,16 @@ def fetch_data(filters): db, ) + df_apr = pd.read_sql_query( + f""" + SELECT * FROM base_mainnet.fct_core_apr + WHERE ts >= '{start_date}' and ts <= '{end_date}' + and market_id != 1 + ORDER BY ts + """, + db, + ) + db.close() return { @@ -74,6 +84,7 @@ def fetch_data(filters): "account_delegation": df_account_delegation, "market_updated": df_market_updated, "pnl": df_pnl, + "apr": df_apr, } @@ -122,6 +133,19 @@ def make_charts(data): "Pnl", "market_id", ), + "hourly_pnl": chart_bars( + data["apr"], + "ts", + ["hourly_pnl"], + "Hourly Pnl", + ), + "apr": chart_lines( + data["apr"], + "ts", + ["pnl_pct_24_hr", "pnl_pct_7_day", "apr"], + "APR", + smooth=True, + ), } @@ -149,11 +173,13 @@ def main(): st.plotly_chart(charts["collateral"], use_container_width=True) st.plotly_chart(charts["reported_debt"], use_container_width=True) st.plotly_chart(charts["net_issuance"], use_container_width=True) + st.plotly_chart(charts["hourly_pnl"], use_container_width=True) with col2: st.plotly_chart(charts["delegation"], use_container_width=True) st.plotly_chart(charts["credit_capacity"], use_container_width=True) st.plotly_chart(charts["pnl"], use_container_width=True) + # st.plotly_chart(charts["apr"], use_container_width=True) st.markdown("## Top Delegators") st.dataframe( diff --git a/dashboard/modules/base_mainnet/perp_account.py b/dashboard/modules/base_mainnet/perp_account.py index 27960340..7fa4ef1c 100644 --- a/dashboard/modules/base_mainnet/perp_account.py +++ b/dashboard/modules/base_mainnet/perp_account.py @@ -138,7 +138,7 @@ def make_charts(data): def main(): - st.markdown("## Perps Account Lookup") + st.markdown("## V3 Perps Accounts") data = fetch_data(filters) ## date filter diff --git a/dashboard/modules/base_mainnet/perp_integrators.py b/dashboard/modules/base_mainnet/perp_integrators.py index 359b7cce..7f5281ea 100644 --- a/dashboard/modules/base_mainnet/perp_integrators.py +++ b/dashboard/modules/base_mainnet/perp_integrators.py @@ -80,7 +80,7 @@ def make_charts(data): def main(): ## title - st.markdown("## Perps V3 Integrators") + st.markdown("## V3 Perps Integrators") ## inputs with st.expander("Filters") as expander: diff --git a/dashboard/modules/base_mainnet/perp_keepers.py b/dashboard/modules/base_mainnet/perp_keepers.py index f4e20449..d75f927c 100644 --- a/dashboard/modules/base_mainnet/perp_keepers.py +++ b/dashboard/modules/base_mainnet/perp_keepers.py @@ -92,7 +92,7 @@ def make_charts(data): def main(): ## title - st.markdown("## Perps V3 Keepers") + st.markdown("## V3 Perps Keepers") ## inputs with st.expander("Filters") as expander: diff --git a/dashboard/modules/base_mainnet/perp_markets.py b/dashboard/modules/base_mainnet/perp_markets.py index ce1e5062..05f43b55 100644 --- a/dashboard/modules/base_mainnet/perp_markets.py +++ b/dashboard/modules/base_mainnet/perp_markets.py @@ -2,7 +2,7 @@ import pandas as pd import plotly.express as px from datetime import datetime, timedelta -from utils import chart_lines, chart_market_oi, export_data +from utils import chart_lines, chart_oi, export_data from utils import get_connection ## set default filters @@ -54,22 +54,17 @@ def make_charts(data, asset): df = data["market_history"][data["market_history"]["market_symbol"] == asset] return { - "funding": chart_lines( - df, - "ts", - ["funding_rate"], - "Funding Rate", - ), - "price": chart_lines(df, "ts", ["price"], "Price"), + "funding": chart_lines(df, "ts", ["funding_rate"], "Funding Rate", smooth=True), + "price": chart_lines(df, "ts", ["price"], "Price", smooth=True), "skew": chart_lines(df, "ts", ["skew"], "Market Skew"), "oi": chart_lines(df, "ts", ["size_usd"], "Open Interest $"), - "oi_pct": chart_market_oi(data["market_history"], asset), + "oi_pct": chart_oi(data["market_history"], "ts", "Open Interest %"), } def main(): ## title - st.markdown("## Perps V3 Markets") + st.markdown("## V3 Perps Markets") ## inputs with st.expander("Filters") as expander: diff --git a/dashboard/modules/base_mainnet/perp_monitor.py b/dashboard/modules/base_mainnet/perp_monitor.py index 89a29c3c..c234e176 100644 --- a/dashboard/modules/base_mainnet/perp_monitor.py +++ b/dashboard/modules/base_mainnet/perp_monitor.py @@ -143,7 +143,7 @@ def make_charts(data): def main(): ## title - st.markdown("## Perps V3 Market Monitor") + st.markdown("## V3 Perps Monitor") ## inputs with st.expander("Filters") as expander: diff --git a/dashboard/modules/base_mainnet/perp_stats.py b/dashboard/modules/base_mainnet/perp_stats.py new file mode 100644 index 00000000..8475562c --- /dev/null +++ b/dashboard/modules/base_mainnet/perp_stats.py @@ -0,0 +1,117 @@ +import streamlit as st +import pandas as pd +import sqlite3 +import plotly.express as px +from datetime import datetime, timedelta +from utils import get_connection +from utils import chart_bars, chart_lines, export_data + +## set default filters +filters = { + "start_date": datetime.today().date() - timedelta(days=14), + "end_date": datetime.today().date() + timedelta(days=1), + "resolution": "daily", +} + + +## data +@st.cache_data(ttl=1) +def fetch_data(filters): + # get filters + start_date = filters["start_date"] + end_date = filters["end_date"] + resolution = filters["resolution"] + + # initialize connection + db = get_connection() + + # read data + df_stats = pd.read_sql_query( + f""" + SELECT + ts, + volume, + trades, + fees, + liquidated_accounts, + liquidation_rewards, + cumulative_fees, + cumulative_volume + FROM base_mainnet.fct_perp_stats_{resolution} + WHERE ts >= '{start_date}' and ts <= '{end_date}' + """, + db, + ) + + db.close() + + return { + "stats": df_stats, + } + + +@st.cache_data(ttl=1) +def make_charts(data): + return { + "volume": chart_bars(data["stats"], "ts", ["volume"], "Volume"), + "cumulative_volume": chart_lines( + data["stats"], "ts", ["cumulative_volume"], "Cumulative Volume", smooth=True + ), + "cumulative_fees": chart_lines( + data["stats"], "ts", ["cumulative_fees"], "Cumulative Fees", smooth=True + ), + "fees": chart_bars(data["stats"], "ts", ["fees"], "Exchange Fees"), + "trades": chart_bars(data["stats"], "ts", ["trades"], "Trades"), + "account_liquidations": chart_bars( + data["stats"], "ts", ["liquidated_accounts"], "Account Liquidations" + ), + "liquidation_rewards": chart_bars( + data["stats"], "ts", ["liquidation_rewards"], "Liquidation Rewards" + ), + } + + +def main(): + ## title + st.markdown("## V3 Perps Stats") + + ## inputs + with st.expander("Filters") as expander: + # resolution + filters["resolution"] = st.radio("Resolution", ["daily", "hourly"]) + + # date filter + filt_col1, filt_col2 = st.columns(2) + with filt_col1: + filters["start_date"] = st.date_input("Start", filters["start_date"]) + + with filt_col2: + filters["end_date"] = st.date_input("End", filters["end_date"]) + + ## fetch data + data = fetch_data(filters) + + ## make the charts + charts = make_charts(data) + + ## display + col1, col2 = st.columns(2) + + with col1: + st.plotly_chart(charts["cumulative_volume"], use_container_width=True) + st.plotly_chart(charts["cumulative_fees"], use_container_width=True) + st.plotly_chart(charts["account_liquidations"], use_container_width=True) + st.plotly_chart(charts["liquidation_rewards"], use_container_width=True) + pass + + with col2: + st.plotly_chart(charts["volume"], use_container_width=True) + st.plotly_chart(charts["fees"], use_container_width=True) + st.plotly_chart(charts["trades"], use_container_width=True) + pass + + ## export + exports = [{"title": export, "df": data[export]} for export in data.keys()] + with st.expander("Exports"): + for export in exports: + export_data(export["title"], export["df"]) diff --git a/dashboard/modules/base_sepolia/perp_account.py b/dashboard/modules/base_sepolia/perp_account.py index 0c8871da..d9fe6132 100644 --- a/dashboard/modules/base_sepolia/perp_account.py +++ b/dashboard/modules/base_sepolia/perp_account.py @@ -138,7 +138,7 @@ def make_charts(data): def main(): - st.markdown("## Perps Account Lookup") + st.markdown("## V3 Perps Accounts") data = fetch_data(filters) ## date filter diff --git a/dashboard/modules/base_sepolia/perp_integrators.py b/dashboard/modules/base_sepolia/perp_integrators.py index f78a4cd0..d7189fc3 100644 --- a/dashboard/modules/base_sepolia/perp_integrators.py +++ b/dashboard/modules/base_sepolia/perp_integrators.py @@ -80,7 +80,7 @@ def make_charts(data): def main(): ## title - st.markdown("## Perps V3 Integrators") + st.markdown("## V3 Perps Integrators") ## inputs with st.expander("Filters") as expander: diff --git a/dashboard/modules/base_sepolia/perp_keepers.py b/dashboard/modules/base_sepolia/perp_keepers.py index b0980354..fd833323 100644 --- a/dashboard/modules/base_sepolia/perp_keepers.py +++ b/dashboard/modules/base_sepolia/perp_keepers.py @@ -92,7 +92,7 @@ def make_charts(data): def main(): ## title - st.markdown("## Perps V3 Keepers") + st.markdown("## V3 Perps Keepers") ## inputs with st.expander("Filters") as expander: diff --git a/dashboard/modules/base_sepolia/perp_markets.py b/dashboard/modules/base_sepolia/perp_markets.py index eba29617..8d432bb9 100644 --- a/dashboard/modules/base_sepolia/perp_markets.py +++ b/dashboard/modules/base_sepolia/perp_markets.py @@ -2,7 +2,7 @@ import pandas as pd import plotly.express as px from datetime import datetime, timedelta -from utils import chart_lines, chart_market_oi, export_data +from utils import chart_lines, chart_oi, export_data from utils import get_connection ## set default filters @@ -54,22 +54,17 @@ def make_charts(data, asset): df = data["market_history"][data["market_history"]["market_symbol"] == asset] return { - "funding": chart_lines( - df, - "ts", - ["funding_rate"], - "Funding Rate", - ), - "price": chart_lines(df, "ts", ["price"], "Price"), + "funding": chart_lines(df, "ts", ["funding_rate"], "Funding Rate", smooth=True), + "price": chart_lines(df, "ts", ["price"], "Price", smooth=True), "skew": chart_lines(df, "ts", ["skew"], "Market Skew"), "oi": chart_lines(df, "ts", ["size_usd"], "Open Interest $"), - "oi_pct": chart_market_oi(data["market_history"], asset), + "oi_pct": chart_oi(data["market_history"], "ts", "Open Interest %"), } def main(): ## title - st.markdown("## Perps V3 Markets") + st.markdown("## V3 Perps Markets") ## inputs with st.expander("Filters") as expander: diff --git a/dashboard/modules/base_sepolia/perp_monitor.py b/dashboard/modules/base_sepolia/perp_monitor.py index d789a778..0a5c4775 100644 --- a/dashboard/modules/base_sepolia/perp_monitor.py +++ b/dashboard/modules/base_sepolia/perp_monitor.py @@ -143,7 +143,7 @@ def make_charts(data): def main(): ## title - st.markdown("## Perps V3 Market Monitor") + st.markdown("## V3 Perps Monitor") ## inputs with st.expander("Filters") as expander: diff --git a/dashboard/modules/base_sepolia/perp_stats.py b/dashboard/modules/base_sepolia/perp_stats.py new file mode 100644 index 00000000..8ea0461e --- /dev/null +++ b/dashboard/modules/base_sepolia/perp_stats.py @@ -0,0 +1,117 @@ +import streamlit as st +import pandas as pd +import sqlite3 +import plotly.express as px +from datetime import datetime, timedelta +from utils import get_connection +from utils import chart_bars, chart_lines, export_data + +## set default filters +filters = { + "start_date": datetime.today().date() - timedelta(days=14), + "end_date": datetime.today().date() + timedelta(days=1), + "resolution": "daily", +} + + +## data +@st.cache_data(ttl=1) +def fetch_data(filters): + # get filters + start_date = filters["start_date"] + end_date = filters["end_date"] + resolution = filters["resolution"] + + # initialize connection + db = get_connection() + + # read data + df_stats = pd.read_sql_query( + f""" + SELECT + ts, + volume, + trades, + fees, + liquidated_accounts, + liquidation_rewards, + cumulative_fees, + cumulative_volume + FROM base_sepolia.fct_perp_stats_{resolution} + WHERE ts >= '{start_date}' and ts <= '{end_date}' + """, + db, + ) + + db.close() + + return { + "stats": df_stats, + } + + +@st.cache_data(ttl=1) +def make_charts(data): + return { + "volume": chart_bars(data["stats"], "ts", ["volume"], "Volume"), + "cumulative_volume": chart_lines( + data["stats"], "ts", ["cumulative_volume"], "Cumulative Volume", smooth=True + ), + "cumulative_fees": chart_lines( + data["stats"], "ts", ["cumulative_fees"], "Cumulative Fees", smooth=True + ), + "fees": chart_bars(data["stats"], "ts", ["fees"], "Exchange Fees"), + "trades": chart_bars(data["stats"], "ts", ["trades"], "Trades"), + "account_liquidations": chart_bars( + data["stats"], "ts", ["liquidated_accounts"], "Account Liquidations" + ), + "liquidation_rewards": chart_bars( + data["stats"], "ts", ["liquidation_rewards"], "Liquidation Rewards" + ), + } + + +def main(): + ## title + st.markdown("## V3 Perps Stats") + + ## inputs + with st.expander("Filters") as expander: + # resolution + filters["resolution"] = st.radio("Resolution", ["daily", "hourly"]) + + # date filter + filt_col1, filt_col2 = st.columns(2) + with filt_col1: + filters["start_date"] = st.date_input("Start", filters["start_date"]) + + with filt_col2: + filters["end_date"] = st.date_input("End", filters["end_date"]) + + ## fetch data + data = fetch_data(filters) + + ## make the charts + charts = make_charts(data) + + ## display + col1, col2 = st.columns(2) + + with col1: + st.plotly_chart(charts["cumulative_volume"], use_container_width=True) + st.plotly_chart(charts["cumulative_fees"], use_container_width=True) + st.plotly_chart(charts["account_liquidations"], use_container_width=True) + st.plotly_chart(charts["liquidation_rewards"], use_container_width=True) + pass + + with col2: + st.plotly_chart(charts["volume"], use_container_width=True) + st.plotly_chart(charts["fees"], use_container_width=True) + st.plotly_chart(charts["trades"], use_container_width=True) + pass + + ## export + exports = [{"title": export, "df": data[export]} for export in data.keys()] + with st.expander("Exports"): + for export in exports: + export_data(export["title"], export["df"]) diff --git a/dashboard/modules/op_mainnet/perp_integrators.py b/dashboard/modules/op_mainnet/perp_integrators.py index dc9ddd75..ee352896 100644 --- a/dashboard/modules/op_mainnet/perp_integrators.py +++ b/dashboard/modules/op_mainnet/perp_integrators.py @@ -143,6 +143,7 @@ def make_charts(df, df_daily): ["fees_cumulative"], "Cumulative Fees Paid", color="tracking_code", + smooth=True, ), "volume": chart_bars( df_daily, "day", ["volume"], "Volume", color="tracking_code" @@ -156,6 +157,7 @@ def make_charts(df, df_daily): ["volume_cumulative"], "Cumulative Volume", color="tracking_code", + smooth=True, ), "traders": chart_bars( df_daily, "day", ["traders"], "Traders", color="tracking_code" @@ -166,6 +168,7 @@ def make_charts(df, df_daily): ["traders_cumulative"], "Cumulative Traders", color="tracking_code", + smooth=True, ), "trades": chart_bars( df_daily, "day", ["trades"], "Trades", color="tracking_code" @@ -179,6 +182,7 @@ def make_charts(df, df_daily): ["trades_cumulative"], "Cumulative Trades", color="tracking_code", + smooth=True, ), } diff --git a/dashboard/modules/op_mainnet/perp_markets.py b/dashboard/modules/op_mainnet/perp_markets.py index d10c80f0..9aeb5b4a 100644 --- a/dashboard/modules/op_mainnet/perp_markets.py +++ b/dashboard/modules/op_mainnet/perp_markets.py @@ -3,7 +3,7 @@ import sqlite3 import plotly.express as px from datetime import datetime, timedelta -from utils import chart_asset_bars, chart_asset_lines, chart_asset_oi, export_data +from utils import chart_bars, chart_lines, chart_oi, export_data ## data @@ -73,34 +73,32 @@ def filter_data(df, df_trade, df_funding, start_date, end_date): ## charts @st.cache_data(ttl=1) def make_charts(df, df_daily, df_trade, df_funding, asset): + df = df[df["asset"] == asset] + df_daily = df_daily[df_daily["asset"] == asset] + df_trade = df_trade[df_trade["asset"] == asset] + df_funding = df_funding[df_funding["asset"] == asset] + return { - "cumulative_volume": chart_asset_lines( - df, asset, "date", ["cumulative_volume"], "Cumulative Volume" - ), - "daily_volume": chart_asset_bars( - df_daily, asset, "day", ["daily_volume"], "Daily Volume" + "cumulative_volume": chart_lines( + df, "date", ["cumulative_volume"], "Cumulative Volume" ), - "fees": chart_asset_lines( - df, asset, "date", ["liq_fees", "exchange_fees"], "Cumulative Fees" + "daily_volume": chart_bars(df_daily, "day", ["daily_volume"], "Daily Volume"), + "fees": chart_lines( + df, "date", ["liq_fees", "exchange_fees"], "Cumulative Fees" ), - "daily_fees": chart_asset_bars( + "daily_fees": chart_bars( df_daily, - asset, "day", ["daily_exchange_fees", "daily_liq_fees"], "Daily Fees", ), - "pnl": chart_asset_lines( - df, asset, "date", ["staker_pnl"], "Cumulative Staker Pnl" - ), - "daily_pnl": chart_asset_bars( - df_daily, asset, "day", ["daily_staker_pnl"], "Daily Staker Pnl" - ), - "skew": chart_asset_lines(df_trade, asset, "date", ["net_skew"], "Net Skew"), - "funding": chart_asset_lines( - df_funding, asset, "date", ["fundingRate"], "Funding Rate" + "pnl": chart_lines(df, "date", ["staker_pnl"], "Cumulative Staker Pnl"), + "daily_pnl": chart_bars( + df_daily, "day", ["daily_staker_pnl"], "Daily Staker Pnl" ), - "oi": chart_asset_oi(df_trade, asset), + "skew": chart_lines(df_trade, "date", ["net_skew"], "Net Skew"), + "funding": chart_lines(df_funding, "date", ["fundingRate"], "Funding Rate"), + "oi": chart_oi(df_trade, "date", f"Open Interest %"), } diff --git a/dashboard/modules/op_mainnet/perp_stats.py b/dashboard/modules/op_mainnet/perp_stats.py index 681f9eb8..fdff35ed 100644 --- a/dashboard/modules/op_mainnet/perp_stats.py +++ b/dashboard/modules/op_mainnet/perp_stats.py @@ -126,16 +126,22 @@ def filter_data(df, df_trade, start_date, end_date, assets): @st.cache_data(ttl=600) def make_charts(df, df_daily, df_trade, df_oi): return { - "pnl": chart_lines(df_daily, "date", ["staker_pnl"], "Cumulative Staker Pnl"), + "pnl": chart_lines( + df_daily, "date", ["staker_pnl"], "Cumulative Staker Pnl", smooth=True + ), "daily_pnl": chart_bars( df_daily, "day", ["daily_staker_pnl"], "Daily Staker Pnl" ), "cumulative_volume": chart_lines( - df_daily, "date", ["cumulative_volume"], "Cumulative Volume" + df_daily, "date", ["cumulative_volume"], "Cumulative Volume", smooth=True ), "daily_volume": chart_bars(df_daily, "day", ["daily_volume"], "Daily Volume"), "fees": chart_lines( - df_daily, "date", ["liq_fees", "exchange_fees"], "Cumulative Fees" + df_daily, + "date", + ["liq_fees", "exchange_fees"], + "Cumulative Fees", + smooth=True, ), "daily_fees": chart_bars( df_daily, "day", ["daily_liq_fees", "daily_exchange_fees"], "Daily Fees" diff --git a/dashboard/network_pages/Home.py b/dashboard/network_pages/Home.py deleted file mode 100644 index 148e8157..00000000 --- a/dashboard/network_pages/Home.py +++ /dev/null @@ -1,18 +0,0 @@ -import streamlit as st - -st.set_page_config(page_title="Synthetix Dashboards", layout="wide") - -hide_footer = """ - -""" -st.markdown(hide_footer, unsafe_allow_html=True) - -st.write("# Synthetix Dashboards") - -st.markdown( - """ -Use the sidebar to select a chain. The dashboard selector will appear below. -""" -) diff --git a/dashboard/network_pages/Base_Mainnet.py b/dashboard/pages/Base_Mainnet.py similarity index 93% rename from dashboard/network_pages/Base_Mainnet.py rename to dashboard/pages/Base_Mainnet.py index 2c40b11f..c37a1009 100644 --- a/dashboard/network_pages/Base_Mainnet.py +++ b/dashboard/pages/Base_Mainnet.py @@ -1,6 +1,7 @@ import streamlit as st from modules.base_mainnet import ( perp_integrators, + perp_stats, perp_monitor, perp_markets, spot_markets, @@ -13,6 +14,7 @@ pages = { + "Perps Stats": perp_stats.main, "Perps Markets": perp_markets.main, "Perps Monitor": perp_monitor.main, "Core Stats": core_stats.main, diff --git a/dashboard/network_pages/Base_Sepolia.py b/dashboard/pages/Base_Sepolia.py similarity index 93% rename from dashboard/network_pages/Base_Sepolia.py rename to dashboard/pages/Base_Sepolia.py index ab8f743e..0fb9d7df 100644 --- a/dashboard/network_pages/Base_Sepolia.py +++ b/dashboard/pages/Base_Sepolia.py @@ -1,6 +1,7 @@ import streamlit as st from modules.base_sepolia import ( perp_integrators, + perp_stats, perp_monitor, perp_markets, spot_markets, @@ -13,6 +14,7 @@ pages = { + "Perps Stats": perp_stats.main, "Perps Markets": perp_markets.main, "Perps Monitor": perp_monitor.main, "Core Stats": core_stats.main, diff --git a/dashboard/network_pages/OP_Mainnet.py b/dashboard/pages/OP_Mainnet.py similarity index 100% rename from dashboard/network_pages/OP_Mainnet.py rename to dashboard/pages/OP_Mainnet.py diff --git a/dashboard/utils/charts.py b/dashboard/utils/charts.py index f332402d..39a1ccaf 100644 --- a/dashboard/utils/charts.py +++ b/dashboard/utils/charts.py @@ -48,7 +48,7 @@ def chart_bars(df, x_col, y_cols, title, color=None): return fig -def chart_lines(df, x_col, y_cols, title, color=None): +def chart_lines(df, x_col, y_cols, title, color=None, smooth=False): fig = px.line( df, x=x_col, @@ -56,71 +56,28 @@ def chart_lines(df, x_col, y_cols, title, color=None): title=title, color=color, color_discrete_sequence=categorical, - line_shape="hv", ) - fig.update_traces(hovertemplate=None) - fig.update_layout( - hovermode="x unified", + fig.update_traces( + hovertemplate=None, + line_shape=None if smooth else "hv", ) - fig.update_layout( - legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), - ) - return fig - - -# with asset filter -def chart_asset_bars(df, asset, x_col, y_cols, title): - fig = px.bar(df[df["asset"] == asset], x=x_col, y=y_cols, title=f"{title}: {asset}") - fig.update_traces(hovertemplate=None) fig.update_layout( hovermode="x unified", - legend=(dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1)), - ) - return fig - - -def chart_asset_lines(df, asset, x_col, y_cols, title): - fig = px.line( - df[df["asset"] == asset], - x=x_col, - y=y_cols, - line_shape="hv", - title=f"{title}: {asset}", ) - fig.update_traces(hovertemplate=None) - fig.update_layout( - hovermode="x unified", - legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), - ) - return fig - - -def chart_asset_oi(df, asset): - fig = px.area( - df[df["asset"] == asset], - x="date", - y=["short_oi_pct", "long_oi_pct"], - line_shape="hv", - color_discrete_sequence=["red", "green"], - title=f"Open Interest %: {asset}", - ) - fig.update_traces(hovertemplate=None) fig.update_layout( - hovermode="x unified", legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), ) return fig -# with market filter -def chart_market_oi(df, asset): +def chart_oi(df, x_col, title): fig = px.area( - df[df["market_symbol"] == asset], - x="ts", + df, + x=x_col, y=["short_oi_pct", "long_oi_pct"], line_shape="hv", color_discrete_sequence=["red", "green"], - title=f"Open Interest %: {asset}", + title=title, ) fig.update_traces(hovertemplate=None) fig.update_layout( diff --git a/docker-compose.yml b/docker-compose.yml index 54095e6b..82d18b7d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -93,8 +93,6 @@ services: dashboard: build: context: ./dashboard - depends_on: - - db restart: always networks: - data @@ -102,7 +100,7 @@ services: - "${DASHBOARD_PORT}:8501" volumes: - ${LEGACY_DB_LOCATION}:/app/data/perps.db - # - .streamlit:/app/.streamlit # uncomment to pass local secrets + - .streamlit:/app/.streamlit # pass local secrets # - ./dashboard:/app # uncomment to enable dashboard development deploy: resources: diff --git a/transformers/synthetix/models/marts/core_stat/fct_core_apr.sql b/transformers/synthetix/models/marts/core_stat/fct_core_apr.sql new file mode 100644 index 00000000..289f6608 --- /dev/null +++ b/transformers/synthetix/models/marts/core_stat/fct_core_apr.sql @@ -0,0 +1,192 @@ +WITH dim AS ( + SELECT + generate_series(DATE_TRUNC('hour', MIN(t.ts)), DATE_TRUNC('hour', MAX(t.ts)), '1 hour' :: INTERVAL) AS ts, + m.market_id + FROM + ( + SELECT + ts + FROM + {{ ref('fct_core_market_updated') }} + ) AS t + CROSS JOIN ( + SELECT + DISTINCT market_id + FROM + {{ ref('fct_core_market_updated') }} + ) AS m + GROUP BY + m.market_id +), +pnls AS ( + SELECT + DISTINCT DATE_TRUNC( + 'hour', + ts + ) AS ts, + market_id, + LAST_VALUE(market_pnl) over (PARTITION BY DATE_TRUNC('hour', ts), market_id + ORDER BY + ts rows BETWEEN unbounded preceding + AND unbounded following) AS pnl + FROM + {{ ref('fct_perp_pnl') }} +), +debt AS ( + SELECT + DISTINCT DATE_TRUNC( + 'hour', + ts + ) AS ts, + market_id, + LAST_VALUE(reported_debt) over (PARTITION BY DATE_TRUNC('hour', ts), market_id + ORDER BY + ts rows BETWEEN unbounded preceding + AND unbounded following) AS debt + FROM + {{ ref('fct_core_market_updated') }} + WHERE + collateral_type != 'USD' +), +ffill AS ( + SELECT + dim.ts, + dim.market_id, + pnls.pnl, + debt.debt, + SUM( + CASE + WHEN pnls.pnl IS NOT NULL THEN 1 + ELSE 0 + END + ) over ( + ORDER BY + dim.ts + ) AS pnl_id, + SUM( + CASE + WHEN debt.debt IS NOT NULL THEN 1 + ELSE 0 + END + ) over ( + ORDER BY + dim.ts + ) AS debt_id + FROM + dim + LEFT JOIN pnls + ON dim.ts = pnls.ts + AND dim.market_id = pnls.market_id + LEFT JOIN debt + ON dim.ts = debt.ts + AND dim.market_id = debt.market_id +), +hourly_pnl AS ( + SELECT + ts, + market_id, + FIRST_VALUE(COALESCE(pnl, 0)) over ( + PARTITION BY pnl_id, + market_id + ORDER BY + ts + ) AS pnl, + FIRST_VALUE(COALESCE(debt, 0)) over ( + PARTITION BY debt_id + ORDER BY + ts + ) AS debt + FROM + ffill +), +ranked_pnl AS ( + SELECT + ts, + market_id, + pnl, + debt, + LAG(pnl) over ( + PARTITION BY market_id + ORDER BY + ts + ) AS prev_pnl + FROM + hourly_pnl +), +hourly_calculations AS ( + SELECT + ts, + market_id, + COALESCE( + pnl - prev_pnl, + 0 + ) AS hourly_pnl, + debt, + (COALESCE(pnl - prev_pnl, 0) / NULLIF(debt, 0)) AS hourly_pnl_pct + FROM + ranked_pnl +) +SELECT + ts, + market_id, + hourly_pnl, + debt, + hourly_pnl_pct, + ( + COALESCE( + EXP( + SUM( + LN( + 1 + hourly_pnl_pct + ) + ) over ( + PARTITION BY market_id + ORDER BY + ts rows BETWEEN 23 preceding + AND CURRENT ROW + ) + ) - 1, + 0 + ) + ) AS pnl_pct_24_hr, + ( + COALESCE( + ( + EXP( + SUM( + LN( + 1 + hourly_pnl_pct + ) + ) over ( + PARTITION BY market_id + ORDER BY + ts rows BETWEEN 168 preceding + AND CURRENT ROW + ) + ) - 1 + ) / 7, + 0 + ) + ) AS pnl_pct_7_day, + ( + COALESCE( + EXP( + SUM( + LN( + 1 + hourly_pnl_pct + ) + ) over ( + PARTITION BY market_id + ORDER BY + ts rows BETWEEN 23 preceding + AND CURRENT ROW + ) + ) - 1, + 0 + ) + ) * 365 AS apr +FROM + hourly_calculations +ORDER BY + market_id, + ts diff --git a/transformers/synthetix/models/marts/perp_stats/fct_perp_market_stats_daily.sql b/transformers/synthetix/models/marts/perp_stats/fct_perp_market_stats_daily.sql index 0247ff59..4310f688 100644 --- a/transformers/synthetix/models/marts/perp_stats/fct_perp_market_stats_daily.sql +++ b/transformers/synthetix/models/marts/perp_stats/fct_perp_market_stats_daily.sql @@ -48,10 +48,30 @@ inc_liq AS ( 1, 2 ), +dim AS ( + SELECT + generate_series(DATE_TRUNC('day', MIN(t.ts)), DATE_TRUNC('day', MAX(t.ts)), '1 day' :: INTERVAL) AS ts, + m.market_symbol + FROM + ( + SELECT + ts + FROM + trades + ) AS t + CROSS JOIN ( + SELECT + DISTINCT market_symbol + FROM + trades + ) AS m + GROUP BY + m.market_symbol +), inc AS ( SELECT - h.ts, - h.market_symbol, + dim.ts, + dim.market_symbol, COALESCE( h.trades, 0 @@ -75,20 +95,25 @@ inc AS ( SUM( h.fees ) over ( + PARTITION BY dim.market_symbol ORDER BY - h.ts + dim.ts ) AS cumulative_fees, SUM( h.volume ) over ( + PARTITION BY dim.market_symbol ORDER BY - h.ts + dim.ts ) AS cumulative_volume FROM - inc_trades h + dim + LEFT JOIN inc_trades h + ON dim.ts = h.ts + AND dim.market_symbol = h.market_symbol LEFT JOIN inc_liq l - ON h.ts = l.ts - AND h.market_symbol = l.market_symbol + ON dim.ts = l.ts + AND dim.market_symbol = l.market_symbol ) SELECT * diff --git a/transformers/synthetix/models/marts/perp_stats/fct_perp_market_stats_hourly.sql b/transformers/synthetix/models/marts/perp_stats/fct_perp_market_stats_hourly.sql index cb33a1d6..2b08066e 100644 --- a/transformers/synthetix/models/marts/perp_stats/fct_perp_market_stats_hourly.sql +++ b/transformers/synthetix/models/marts/perp_stats/fct_perp_market_stats_hourly.sql @@ -48,16 +48,30 @@ inc_liq AS ( 1, 2 ), +dim AS ( + SELECT + generate_series(DATE_TRUNC('hour', MIN(t.ts)), DATE_TRUNC('hour', MAX(t.ts)), '1 hour' :: INTERVAL) AS ts, + m.market_symbol + FROM + ( + SELECT + ts + FROM + trades + ) AS t + CROSS JOIN ( + SELECT + DISTINCT market_symbol + FROM + trades + ) AS m + GROUP BY + m.market_symbol +), inc AS ( SELECT - COALESCE( - h.ts, - l.ts - ) AS ts, - COALESCE( - h.market_symbol, - l.market_symbol - ) AS market_symbol, + dim.ts, + dim.market_symbol, COALESCE( h.trades, 0 @@ -81,20 +95,25 @@ inc AS ( SUM( h.fees ) over ( + PARTITION BY dim.market_symbol ORDER BY - h.ts + dim.ts ) AS cumulative_fees, SUM( h.volume ) over ( + PARTITION BY dim.market_symbol ORDER BY - h.ts + dim.ts ) AS cumulative_volume FROM - inc_trades h full - OUTER JOIN inc_liq l - ON h.ts = l.ts - AND h.market_symbol = l.market_symbol + dim + LEFT JOIN inc_trades h + ON dim.ts = h.ts + AND dim.market_symbol = h.market_symbol + LEFT JOIN inc_liq l + ON dim.ts = l.ts + AND dim.market_symbol = l.market_symbol ) SELECT *