Stock Portfolio
Build a wider market-data table with grouped headers, editable tickers, sparklines, and currency columns.
Stock Portfolio
Build a wider market-data table with grouped headers, editable tickers, sparklines, and currency columns.
Source: usage.py::build_stock_portfolio_code().
def load_stock_portfolio_record(symbol, row_id):
ticker = yf.Ticker(symbol)
history = ticker.history(period="3mo")["Close"].dropna().tolist()
return {
"id": row_id,
"ticker": ticker.info["displayName"],
"_queryTicker": symbol,
"Exchange": ticker.fast_info["exchange"],
"sector": ticker.info["sector"],
"lastValue": ticker.analyst_price_targets["current"],
"marketCap": ticker.fast_info["marketCap"],
"priceTargetLow": ticker.analyst_price_targets["low"],
"priceTargetMedian": ticker.analyst_price_targets["median"],
"priceTargetHigh": ticker.analyst_price_targets["high"],
"sparkline": history,
"sparklineLabel": history,
"sparklineColor": "blue",
}
stock_records = [
load_stock_portfolio_record(symbol, row_id)
for row_id, symbol in enumerate(STOCK_PORTFOLIO_DEFAULT_TICKERS, start=1)
]
portfolio_table = (
dmdt.DataTable(
id="stock-portfolio-table",
data=stock_records,
columns=STOCK_PORTFOLIO_COLUMNS,
idAccessor="id",
paginationMode="none",
)
.update_layout(
radius="lg",
withTableBorder=True,
withColumnBorders=True,
striped=True,
pinFirstColumn=True,
textSelectionDisabled=True,
)
.update_columns(
selector="ticker",
title="Stock ticker",
width=140,
editable=True,
editor=dmc.TextInput(label="Stock ticker", placeholder="e.g. NVDA"),
cellsStyle={"fontWeight": 700, "letterSpacing": "0.04em", "textTransform": "uppercase"},
)
.update_columns(selector="Exchange", title="Exchange", width=120)
.update_columns(selector="sector", title="Sector", width=190)
.update_columns(
selector="lastValue",
title="Last value",
presentation="currency",
currency="USD",
textAlign="right",
width=130,
cellsStyle={"fontVariantNumeric": "tabular-nums"},
)
.update_columns(
selector="marketCap",
title="Market cap",
presentation="currency",
currency="USD",
textAlign="right",
width=150,
cellsStyle={"fontVariantNumeric": "tabular-nums"},
)
.update_columns(
selector=["priceTargetLow", "priceTargetMedian", "priceTargetHigh"],
presentation="currency",
currency="USD",
textAlign="right",
width=120,
cellsStyle={"fontVariantNumeric": "tabular-nums"},
)
.update_columns(selector="priceTargetLow", title="Low")
.update_columns(selector="priceTargetMedian", title="Median", cellsStyle={"fontWeight": 700})
.update_columns(selector="priceTargetHigh", title="High")
.update_columns(
selector="sparkline",
title="3M history",
width=160,
render=dmc.Sparkline(data="{sparkline}", color="{sparklineColor}", w=140, h=34),
)
.group_columns(
dmdt.ColumnGroup(
"snapshot",
title="Snapshot",
columns=["ticker", "Exchange", "sector", "lastValue", "marketCap"],
),
dmdt.ColumnGroup(
"price-target",
title="Price target",
textAlign="center",
columns=["priceTargetLow", "priceTargetMedian", "priceTargetHigh"],
),
dmdt.ColumnGroup(
"history",
title="History",
columns=["sparkline"],
)
)
.group_columns(
selector="snapshot",
style={"backgroundColor": "var(--mantine-color-gray-0)"},
)
.group_columns(
selector="price-target",
style={"backgroundColor": "var(--mantine-color-blue-0)"},
)
.group_columns(
selector="history",
style={"backgroundColor": "var(--mantine-color-green-0)"},
)
)
# In the docs app, a callback reloads the live rows on page load and
# re-hydrates the table after ticker edits.