A comprehensive Home Assistant custom integration that tracks stocks, cryptocurrencies, and portfolio performance in near real-time using Finnhub and CoinGecko APIs. View everything from your Lovelace dashboard with charts, statistics, and a financial news ticker.
If you find this plugin useful, please consider donating. Your support is greatly appreciated!
- Multi-Asset Support: Track both stocks and cryptocurrencies via Finnhub API in one unified portfolio
- Real-Time Updates: Automatic price updates on a configurable schedule (default: every 10 minutes)
- Efficient API Usage: Batch API calls minimize rate limits and maximize performance
- Dynamic Entity Management: Entities are automatically created and removed based on your holdings configuration
For each holding:
- Current market price
- Total position value
- Cost basis
- Gain/Loss (absolute $ and %)
- Performance tracking
For your entire portfolio:
- Total portfolio value
- Total cost basis
- Overall gain/loss
- Portfolio performance percentage
- Holdings breakdown (stocks vs. crypto)
- Live financial news feed from Yahoo Finance RSS
- Cached hourly to minimize API load
- Accessible as sensor attributes for custom dashboards
- Intelligent caching reduces API calls (5-min for prices, 60-min for news)
- Symbol normalization - automatically converts to uppercase (NVDA, BTC, etc.)
- Post-install configuration - add/remove holdings and update API keys anytime
- User-friendly Config Flow UI
- No YAML editing required (but supported!)
- Add unlimited holdings
- Modify settings through Home Assistant UI
- Open HACS in Home Assistant
- Click on "Integrations"
- Click the three dots in the top right
- Select "Custom repositories"
- Add this repository URL:
https://github.com/biofects/Biofects-Portfolio-Tracker - Select category: "Integration"
- Click "Add"
- Click "Install"
- Restart Home Assistant
- Copy the
custom_components/biofects_portfoliofolder to your Home Assistant'scustom_componentsdirectory - Restart Home Assistant
Required:
Finnhub (for stocks):
- Free tier: 60 API calls/minute
- Get your API key from the dashboard
Optional:
- No separate API key needed for crypto
- Add your holdings:
- Symbol: Stock ticker (e.g.,
AAPL) or crypto symbol (e.g.,BTC)
- Symbol: Stock ticker (e.g.,
- Find Biofects Portfolio Tracker
- Click Configure (βοΈ gear icon)
- Remove holdings
- View all holdings
sensor.portfolio_summary
- State: Total portfolio value in USD
- Attributes:
total_holdings: Number of holdingsstock_count: Number of stock positionscrypto_count: Number of crypto positionstotal_cost: Total cost basistotal_gain_loss: Total gain/loss in USDtotal_gain_loss_percent: Portfolio performance %last_updated: Last update timestamp
For each holding, two sensors are created:
sensor.holding_[symbol] - Holding details
- State: Total position value in USD
- Attributes:
symbol: Asset symbolholding_type:stockorcryptoquantity: Number of shares/coinsbuy_price: Purchase pricecurrent_price: Current market pricetotal_value: Position valuegain_loss: Gain/loss amountgain_loss_percent: Gain/loss percentage
If you want to use the advanced auto-discovery dashboard (sample-layout-auto.yml), you must install these HACS frontend cards:
- auto-entities β Dynamic entity lists
- stack-in-card β Card organization
- layout-card β Advanced layouts
Install these from HACS β Frontend before using the auto layout sample.
1. Basic Layout (examples/sample-layout.yml)
- Works immediately with no additional cards required
- Uses standard Home Assistant cards only
- Manual: You need to add entity names when you add new holdings
- Perfect for getting started quickly
2. Auto Layout (examples/sample-layout-auto.yml)
- Requires HACS cards but provides automatic discovery
- Dynamic: Automatically shows new holdings as you add them
- No manual entity configuration needed
For the auto sample dashboard layout to work, install these cards via HACS:
- auto-entities - For dynamic entity lists
- HACS β Frontend β Search "auto-entities"
- stack-in-card - For card organization
- HACS β Frontend β Search "stack-in-card"
- layout-card - For advanced layouts
- HACS β Frontend β Search "layout-card"
- Basic Setup: View or copy the sample-layout.yml β works immediately!
- Enhanced Setup: Install HACS cards, then view or copy sample-layout-auto.yml for automatic entity discovery
-
current_price: Current market price -
total_cost: Position cost basis -
gain_loss: Position gain/loss in USD -
gain_loss_percent: Position performance % -
last_updated: Last update timestamp -
State: Number of news items
-
Attributes:
news_items: Array of news objects with:title: News headlinelink: Article URLpublished: Publication datesummary: Article summary
title: πΌ My Portfolio entities:
- entity: sensor.portfolio_summary name: Total Value icon: mdi:wallet
- type: attribute entity: sensor.portfolio_summary attribute: total_gain_loss name: Gain/Loss suffix: USD attribute: total_gain_loss_percent name: Performance suffix: '%'
### Holdings List Card
- entity: sensor.holding_aapl
name: Apple (AAPL)
secondary_info: attribute
attribute: gain_loss_percent
- entity: sensor.holding_tsla
name: Tesla (TSLA)
secondary_info: attribute
attribute: gain_loss_percent
- entity: sensor.holding_btc
name: Bitcoin
secondary_info: attribute
attribute: gain_loss_percent
type: custom:apexcharts-card
header:
show: true
title: Portfolio Performance
graph_span: 7d
name: Portfolio Valuetype: vertical-stack
cards:
- type: custom:mushroom-template-card
primary: Portfolio Value
secondary: ${{ states('sensor.portfolio_summary') }}
icon: mdi:wallet
icon_color: >
{% if state_attr('sensor.portfolio_summary', 'total_gain_loss') | float > 0 %}
green
{% else %}
red
{% endif %}
- type: horizontal-stack
cards:
- type: custom:mushroom-template-card
primary: Stocks
secondary: '{{ state_attr("sensor.portfolio_summary", "stock_count") }}'
icon: mdi:chart-line
- type: custom:mushroom-template-card
primary: Crypto
secondary: '{{ state_attr("sensor.portfolio_summary", "crypto_count") }}'
icon: mdi:currency-btc
- type: custom:mushroom-template-card
primary: >
{% set gl = state_attr('sensor.portfolio_summary', 'total_gain_loss') | float %}
{% if gl > 0 %}π{% else %}π{% endif %}
{{ '%.2f' | format(gl) }} USD
secondary: >
{{ '%.2f' | format(state_attr('sensor.portfolio_summary', 'total_gain_loss_percent') | float) }}%
icon: mdi:trending-up
icon_color: >
{% if state_attr('sensor.portfolio_summary', 'total_gain_loss') | float > 0 %}
green
{% else %}
red
{% endif %}type: markdown
content: >
## π° Market News
{% for item in state_attr('sensor.portfolio_news', 'news_items')[:5] %}
**[{{ item.title }}]({{ item.link }})**
{{ item.published }}
---
{% endfor %}views:
- title: Portfolio
path: portfolio
icon: mdi:wallet
cards:
- type: vertical-stack
cards:
# Summary Section
- type: custom:mushroom-title-card
title: My Investment Portfolio
- type: horizontal-stack
cards:
- type: statistic
entity: sensor.portfolio_summary
name: Total Value
- type: custom:mushroom-template-card
primary: >
{{ '%.2f' | format(state_attr('sensor.portfolio_summary', 'total_gain_loss_percent') | float) }}%
secondary: Performance
icon: mdi:chart-line
icon_color: >
{% if state_attr('sensor.portfolio_summary', 'total_gain_loss') | float > 0 %}
green
{% else %}
red
{% endif %}
# Chart Section
- type: custom:apexcharts-card
header:
show: true
title: 7-Day Performance
graph_span: 7d
series:
- entity: sensor.portfolio_summary
name: Portfolio Value
stroke_width: 3
# Holdings Section
- type: custom:auto-entities
card:
type: entities
title: π Holdings
filter:
include:
- entity_id: sensor.holding_*
options:
type: custom:multiple-entity-row
secondary_info:
attribute: gain_loss_percent
name: false
suffix: '%'
entities:
- attribute: current_price
name: Price
- attribute: quantity
name: Qty
# News Section
- type: markdown
title: π° Latest Market News
content: >
{% for item in state_attr('sensor.portfolio_news', 'news_items')[:5] %}
**[{{ item.title }}]({{ item.link }})**
*{{ item.published }}*
---
{% endfor %}automation:
- alias: Daily Portfolio Report
trigger:
platform: time
at: "09:00:00"
action:
service: notify.mobile_app
data:
title: "π Daily Portfolio Update"
message: >
Portfolio Value: ${{ states('sensor.portfolio_summary') }}
Today's Change: ${{ state_attr('sensor.portfolio_summary', 'total_gain_loss') }}
Performance: {{ state_attr('sensor.portfolio_summary', 'total_gain_loss_percent') }}%automation:
- alias: Portfolio Alert - Big Gain
trigger:
platform: numeric_state
entity_id: sensor.portfolio_summary
attribute: total_gain_loss_percent
above: 5
action:
service: notify.mobile_app
data:
title: "π Portfolio up {{ trigger.to_state.attributes.total_gain_loss_percent }}%!"
message: "Your portfolio is performing great!"
- alias: Portfolio Alert - Big Loss
trigger:
platform: numeric_state
entity_id: sensor.portfolio_summary
attribute: total_gain_loss_percent
below: -5
action:
service: notify.mobile_app
data:
title: "β οΈ Portfolio down {{ trigger.to_state.attributes.total_gain_loss_percent }}%"
message: "Consider reviewing your positions."- Verify your API keys are correct
- Check API rate limits (Finnhub free tier: 60 calls/min)
- Ensure Home Assistant can reach external APIs
- Check the update interval setting (default: 10 minutes)
- Verify symbols are correct (use proper stock tickers)
- Check Home Assistant logs for errors
Use these common mappings:
- Bitcoin:
BTC - Ethereum:
ETH - Binance Coin:
BNB - Solana:
SOL - Cardano:
ADA
Add to configuration.yaml:
logger:
default: info
logs:
custom_components.biofects_portfolio: debugThis project is licensed under the MIT License.
Contributions are welcome! Please feel free to submit a Pull Request.
- Report bugs: GitHub Issues
- Feature requests: GitHub Discussions
This integration is for informational purposes only. It does not provide financial advice. Always do your own research before making investment decisions.
Made with β€οΈ by Biofects