Stock / equities ticker widget for led-ticker (Finnhub).
Project description
led-ticker-stocks
A stock / equities ticker plugin for led-ticker, backed by the Finnhub API. It contributes a stocks.ticker Container widget that cycles one scrolling price line per configured symbol: SYM price ▲/▼ change change%, trend-colored green/red and dimmed by market state (full brightness while the market is open, dimmed while pre/post-market, dimmest while closed).
Phase 1 scope: US equities only, one layout (crawl, sized for the smallsign). FX/forex, the bigsign card layout, and the longboi dashboard layout are not implemented yet — see Roadmap.
Prerequisites
- A working led-ticker install.
- Internet access on the Pi (the widget calls the Finnhub REST API).
- A free Finnhub account and API token — or run in
demo = truemode with no token at all (see Demo mode).
Install
The widget auto-registers via the led_ticker.plugins entry point — once the package is installed, no [plugins] config change is needed.
Into a containerized led-ticker (recommended): add this package to config/requirements-plugins.txt (copy it from config/requirements-plugins.example.txt), then restart:
# in your led-ticker checkout
cp config/requirements-plugins.example.txt config/requirements-plugins.txt
# add the line below to config/requirements-plugins.txt, then:
docker compose restart
led-ticker-stocks
Standalone (a venv that already has led-ticker):
pip install led-ticker-stocks
See the led-ticker Plugins docs for the constraint-based install the Docker image uses, and pin production signs to an exact version (led-ticker-stocks==0.1.0) so a restart doesn't silently pick up a new release.
Configuration
Reference the widget in a playlist section by type = "stocks.ticker":
[[playlist.section]]
mode = "ticker"
[[playlist.section.widget]]
type = "stocks.ticker"
symbols = ["AAPL", "MSFT", "NVDA", "TSLA"]
mode = "ticker" (continuous side-by-side crawl) is the recommended section mode for this widget — the crawl layout is a single scrolling line per symbol, the same shape as the built-in crypto.coingecko / rss.feed tickers. slideshow also works (one symbol held per visit) but the crawl text is designed to keep moving.
New to led-ticker configs? The first-config tutorial walks through the overall structure — the block above shows just the stocks-specific keys.
Options
| Option | Type | Default | Description |
|---|---|---|---|
symbols |
list of strings | — | Required. Ticker symbols (e.g. ["AAPL", "MSFT"]). US equities only — a symbol containing / (e.g. "EUR/USD") fails validation with a message pointing at the FX limitation below. |
layout |
string | auto | Force a specific render layout. Phase 1 registers only "crawl" — omit this field and let the widget auto-select (it currently always resolves to crawl on a ≤160px-wide canvas and raises NotImplementedError on anything wider, since card/dashboard aren't shipped yet). |
demo |
bool | false |
Run against a seeded, offline random-walk feed instead of Finnhub — no token, no network call. See Demo mode. |
update_interval |
int | 60 |
Seconds between Finnhub polls. The widget silently raises this to len(symbols) + 1 if you set it lower — see Rate limits below. |
padding |
int | 6 |
Horizontal spacing (logical px) after each symbol's segment, before the next symbol. |
green_up |
bool | true |
Set false to flip the up/down colors (green-down/red-up) for non-US market conventions. |
At least symbols must be a non-empty list — the widget fails at config validation otherwise (led-ticker validate catches this before boot).
Demo mode (no token required)
Set demo = true (or simply omit FINNHUB_API_TOKEN from the environment — an unset token silently routes to the same demo feed, it is not an error) to drive the widget from a deterministic, seeded random-walk price generator instead of live Finnhub data. Useful for previewing the widget, render-demo GIFs, or a sign that doesn't have a Finnhub token yet. See docs/demo.toml for a runnable example.
Smoke-test configs (per sign)
Ready-to-run hardware smoke configs live in examples/, one per sign form factor — each with a token-free demo section plus a live section, and a "what to look for" header:
| File | Sign | Notes |
|---|---|---|
config.stocks-smoke.smallsign.toml |
160×16 | crawl auto-selected (native Phase-1 target) |
config.stocks-smoke.bigsign.toml |
256×64 | layout = "crawl" forced (card is Phase 2) |
config.stocks-smoke.longboi.toml |
512×64 | layout = "crawl" forced (dashboard is Phase 2) |
Copy one to config/config.toml on the sign, led-ticker validate it, then make restart.
Rate limits & API token
Get a free API token at finnhub.io/register and supply it via the FINNHUB_API_TOKEN environment variable — never put it in config.toml; secrets are env-only in led-ticker (see the Plugins docs):
export FINNHUB_API_TOKEN="your-token-here"
Finnhub's free tier allows 60 requests per minute, per API key — not per widget. Every poll cycle costs len(symbols) + 1 requests (one market-status call plus one quote call per symbol; the widget skips the quote calls entirely while the market is closed, holding last prices instead). The widget enforces effective_interval = max(update_interval, len(symbols) + 1) automatically, so a single stocks.ticker on its own can't blow the budget — but the 60/min ceiling is shared across everything using that token: two signs pointed at the same Finnhub key, or another Finnhub-backed widget/script on the same key, split the same 60 requests. Give each sign (or each concurrent consumer) its own free Finnhub account/token if you're running more than one.
Equities only — FX requires a paid tier
Finnhub's free tier returns HTTP 403 on forex (/forex/*) endpoints. This plugin's v1 only implements the equities /quote + /stock/market-status endpoints — FX pairs are out of scope until a paid-tier client ships (not planned for Phase 1/2). validate_config rejects any symbol containing / (the conventional FX pair separator, e.g. "EUR/USD") at config-load time with a message explaining why, rather than letting it fail opaquely at runtime.
layout override
Phase 1 ships exactly one registered layout, "crawl" (built for the smallsign, 160px-wide canvas). resolve_layout auto-selects crawl whenever the canvas is ≤160px wide; on a wider canvas (bigsign/longboi) it raises NotImplementedError naming the missing card/dashboard layouts rather than silently rendering wrong. Setting layout = "crawl" explicitly is accepted but has no effect beyond skipping the geometry check — there's nothing else to choose from yet.
Roadmap
- Phase 2:
card(bigsign) +dashboard(longboi) hi-res layouts; sparkline + day-range rendering; paging dots; watch column; geometry auto-select across scale-4 widths. - Phase 3: price-flash on update, sparkline/state pulses, global state dim on the held layouts, abstract per-symbol brand chips,
font_color/borderstyling knobs. - Phase 4: docs-site page, catalog
providesentry, demo GIFs,stocks-v0.1.0release.
Development
Install dev deps and run the checks:
uv sync --extra dev # resolves led-ticker-core from PyPI
uv run pytest -q
uv run ruff check src tests
Note: tests that need a headless canvas obtain one via
HeadlessBackend(...).create_canvas()fromled_ticker.plugin— the software backend shipped in led-ticker-core. No rgbmatrix test stub orPYTHONPATHplumbing is required.
The plugin imports only the public led_ticker.plugin surface — tests/test_import_purity.py enforces it.
Links
- led-ticker — the core project
- Docs site · Plugin system
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file led_ticker_stocks-0.1.0.tar.gz.
File metadata
- Download URL: led_ticker_stocks-0.1.0.tar.gz
- Upload date:
- Size: 28.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c08643ed096d5fbebd7bb202d57c55a74ea5f574b353a32dd3212039f2fd54c
|
|
| MD5 |
f46c8940f5a81dc479831d873053f473
|
|
| BLAKE2b-256 |
074b16bdeb5edbf8df704a1c0f2a9c3a4004222b5d4a2d768b3f52d4be7a5b11
|
Provenance
The following attestation bundles were made for led_ticker_stocks-0.1.0.tar.gz:
Publisher:
publish.yml on JamesAwesome/led-ticker-plugins
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
led_ticker_stocks-0.1.0.tar.gz -
Subject digest:
5c08643ed096d5fbebd7bb202d57c55a74ea5f574b353a32dd3212039f2fd54c - Sigstore transparency entry: 2168916591
- Sigstore integration time:
-
Permalink:
JamesAwesome/led-ticker-plugins@fb4eda5358c869dafcde0951d222f5c0997b708d -
Branch / Tag:
refs/tags/stocks-v0.1.0 - Owner: https://github.com/JamesAwesome
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fb4eda5358c869dafcde0951d222f5c0997b708d -
Trigger Event:
release
-
Statement type:
File details
Details for the file led_ticker_stocks-0.1.0-py3-none-any.whl.
File metadata
- Download URL: led_ticker_stocks-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
648050920ac6610605860be9448854cf0a5b97baf27471068de1c57cd335a0a4
|
|
| MD5 |
711d57c3b34f8567d33578610d848b45
|
|
| BLAKE2b-256 |
01624d04462c26844a78714284b0fcfab638cc7821734c68e7ba3fd7218a3e3c
|
Provenance
The following attestation bundles were made for led_ticker_stocks-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on JamesAwesome/led-ticker-plugins
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
led_ticker_stocks-0.1.0-py3-none-any.whl -
Subject digest:
648050920ac6610605860be9448854cf0a5b97baf27471068de1c57cd335a0a4 - Sigstore transparency entry: 2168916602
- Sigstore integration time:
-
Permalink:
JamesAwesome/led-ticker-plugins@fb4eda5358c869dafcde0951d222f5c0997b708d -
Branch / Tag:
refs/tags/stocks-v0.1.0 - Owner: https://github.com/JamesAwesome
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fb4eda5358c869dafcde0951d222f5c0997b708d -
Trigger Event:
release
-
Statement type: