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
*