Track Your Stock Portfolio in Home Assistant Using Yahoo Finance and custom python script

I know that there is a couple of similar How-Tos.
But they all use templates and input numbers to track stock and I guess that is fine for a couple of sensors. I decided to go down different route.
I use Yahoo Finance HACS integration - so make sure you have that configured. Follow the github documentation for that integration how to install it and set it up.

Next to track current value for the shares I hold, gain/loss % gain/loss and trend vs buy price (up/down/break_even) and total portfolio value I use a home assistant script

In your config folder, go to /config/python_scripts
Create the folder if it doesn’t exist

Save the following file as:
portfolio_tracker.py

portfolio = {
    "apple": {
        "sensor": "sensor.yahoofinance_aapl",
        "shares": 5,
        "buy_price": 150.00,
        "price_in_pence": False
    },
    "barclays": {
        "sensor": "sensor.yahoofinance_barc_l",
        "shares": 100,
        "buy_price": 1.50,
        "price_in_pence": True
    }
    # Add more stocks here...
}

total_value = 0.0
total_gain = 0.0

for key, data in portfolio.items():
    sensor = data["sensor"]
    shares = float(data["shares"])
    buy_price = float(data["buy_price"])
    entity = hass.states.get(sensor)

    if entity is None or "regularMarketPrice" not in entity.attributes:
        continue

    raw_price = float(entity.attributes["regularMarketPrice"])
    current_price = raw_price / 100 if data.get("price_in_pence", False) else raw_price

    value = round(current_price * shares, 2)
    gain = round((current_price - buy_price) * shares, 2)
    gain_pct = round(((current_price - buy_price) / buy_price) * 100, 2)

    if abs(current_price - buy_price) < 0.01:
        trend_vs_buy = "break_even"
    elif current_price > buy_price:
        trend_vs_buy = "up"
    else:
        trend_vs_buy = "down"

    total_value += value
    total_gain += gain

    hass.states.set(f"sensor.{key}_portfolio", value, {
        "friendly_name": f"{key.replace('_', ' ').title()} Value",
        "current_price": current_price,
        "shares": shares,
        "buy_price": buy_price,
        "gain": gain,
        "gain_pct": gain_pct,
        "trend_vs_buy": trend_vs_buy,
        "unit_of_measurement": "GBP"
    })

# Total Portfolio Sensor
total_value = round(total_value, 2)
total_gain = round(total_gain, 2)
total_gain_pct = round((total_gain / (total_value - total_gain) * 100), 2) if total_value - total_gain > 0 else 0

hass.states.set("sensor.portfolio_total", total_value, {
    "friendly_name": "Total Portfolio Value",
    "gain": total_gain,
    "gain_pct": total_gain_pct,
    "unit_of_measurement": "GBP"
})

At the top of the script in the portfolio section populate your stock holdings
sensor → from the yahoo finance integration
shares → this is where you enter how many shares you have
buy_price → this is the value average price per share that you have paid for your shares
price_in_pence → is needed for UK stocks (Yahoo Finance returns prices in pennies).

Save the script and restart HA. Once the script is saved you won’t have to restart HA in case of modifications - just go to dev tools and click reload Python Scripts.

Next step is to create Automation to run that script:

alias: Update Stock Portfolio
trigger:
  - platform: time
    at: "08:00:00"
action:
  - service: python_script.portfolio_tracker
mode: single

I run mine every couple of minutes

With that you should have 2 sensors for each stock i.e. for Rolls Royce:
sensor.yahoofinance_rr_l (from Yahoo Finance integration)
sensor.rolls_royce_portfolio (from the python script)

As for the dashboard - you can do whatever you like with the data - I keep mine simple:
image

I’m using Mushroom Template cards:

type: custom:mushroom-template-card
primary: >
  ÂŁ{{ (state_attr(entity, 'regularMarketPrice') / 100) | round(2) }} ({{
  state_attr(entity, 'regularMarketChangePercent') | round(2) }}%)
secondary: >
  52W Range: ÂŁ{{ (state_attr(entity, 'fiftyTwoWeekLow') / 100) | round(2) }} -
  ÂŁ{{ (state_attr(entity, 'fiftyTwoWeekHigh') / 100) | round(2) }}
icon: |
  {{ state_attr(entity, 'icon') }}
icon_color: |
  {% if state_attr(entity, 'trending') == 'up' %}
    green
  {% elif state_attr(entity, 'trending') == 'down' %}
    red
  {% else %}
    grey
  {% endif %}
multiline_secondary: false
fill_container: false
grid_options:
  columns: 6
  rows: 1
entity: sensor.yahoofinance_rr_l
tap_action:
  action: more-info

and for the other tile:

type: custom:mushroom-template-card
primary: "Total: ÂŁ{{ states(entity) }}"
icon: mdi:cash-multiple
multiline_secondary: false
fill_container: false
grid_options:
  columns: 6
  rows: 1
entity: sensor.rolls_royce_portfolio
icon_color: |2-
    {% set trend = state_attr(entity, 'trend_vs_buy') %}
    {% if trend == 'up' %}
      green
    {% elif trend == 'down' %}
      red
    {% else %}
      grey
    {% endif %}
secondary: |2-
    {% if state_attr(entity, 'trend_vs_buy') == 'break_even' %}
      Break-even — no gain or loss
    {% elif state_attr(entity, 'trend_vs_buy') == 'up' %}
      Profit: ÂŁ{{ state_attr(entity, 'gain') }} ({{ state_attr(entity, 'gain_pct') }}%)
    {% else %}
      Loss: ÂŁ{{ state_attr(entity, 'gain') }} ({{ state_attr(entity, 'gain_pct') }}%)
    {% endif %}
tap_action:
  action: more-info

Also from the python script you get one more sensor called:
sensor.portfolio_total
it has the following attributes:


(No, those are not real values :smile: )

I’m pleased to say that using home assistant/yahoo finance integration and my script I get better quality and more up-to-date values than using my Freetrade app

So here it is. Of course, feel free to modify the script to suit your own needs.

And just to be crystal clear:
You use this at your own risk. I accept no liability for any decisions or losses resulting from the use of this script or the data it generates.

In other words – do your own homework and make sure to double-check everything.

3 Likes

How do you add/delete/change stock you own? Fiddle with the script code/yaml?
You appear to be using your code as a database as well in portfolio_tracker.py

Yes, you have to add/remove/amend the portfolio json part of the script:
“apple”: {
“sensor”: “sensor.yahoofinance_aapl”,
“shares”: 5,
“buy_price”: 150.00,
“price_in_pence”: False
},

I wanted to have that in a separate file but it would appear that importing files is not supported in home assistant python scripts.
I believe that might be possible in HACS pyscript.

Are you saying the instant the share prices move, your code containimg hard coded proces is obsolete?

Your money, your editor, your code, your time…

In these days of strong focus on Artificial Intelligence, why not get AI to self modify your code for fun and profit? It is excellent at repetetive tasks, especially if your commands are precise and clear.

I think you are completely missing the point here.

Nevermind. Storing data in executable code is a big no-no in my part of the universe. You do your thing, and go make lots of money…

How can I create this automation?

alias: Update Stock Portfolio
trigger:

  • platform: time
    at: “08:00:00”
    action:
  • service: python_script.portfolio_tracker
    mode: single

I’ve implemented your code and got it working, but I am puzzling over the 52week range data.
Is it the api or hacs integration not delivering the info or am I missing something?