Open Net Worth
Open Net Worth는 직접 운영하는 오픈소스 개인 AI 자산 비서로, 전체 재무를 하나의 원장에 기록하고 사용자가 제어하는 AI가 관리
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗python3 fetch_dividends.py # refresh dividends.json + the embedded seed
python3 fetch_dividends.py --dry-run # report what would change, write nothing
python3 fetch_dividends.py --only AVGO,D05
Needs yfinance (pip3 install yfinance). The Moomoo path is used automatically
when the OpenD gateway is running on 127.0.0.1:11111; otherwise the script
falls back to Yahoo Finance, which covers KLSE / SGX / HKEX / SWX / US.
The script only rewrites each counter's auto block — the counter list, market
and type classification, manual entries, links and estimate fallbacks are
curated by hand and preserved. Serve the folder (python3 -m http.server) so the
dashboard reads dividends.json; opening index.html directly falls back to the
embedded seed.
The dashboard's Counters tab adds and removes counters without editing JSON
by hand. Pick the portfolio (or name a new one), the market, and the type; the
Yahoo symbol is derived from the ticker per market (5285 on KLSE becomes
5285.KL, 00700 on HKEX becomes 0700.HK) and can be overridden.
Those edits live in the browser's localStorage, so they show on the board at once but the counter has no dividend data yet. To make them part of the project:
python3 fetch_dividends.pyThe fetcher folds the roster into dividends.json, fetches the new counters,
and the additions become permanent for everyone. Delete roster.json afterwards
so the same edits are not replayed on the next run.
Two scheduled jobs, split because they need different things:
.github/workflows/refresh.yml) — weekdays 01:03 UTC.
Runs the fetcher and commits dividends.json and index.html to main.
This is where the fetching happens: GitHub's runners have unrestricted
outbound network.Both refuse to write when the data looks wrong: the fetcher's --min-ok 40
aborts if fewer than 40 counters come back clean, and the routine re-checks the
same thing before publishing.
Every run of fetch_dividends.py also writes dividend-tracker.html — one
self-contained file with the data baked in. Open it straight from the Finder,
AirDrop it to a phone, or keep it in iCloud Drive; it needs no server and no
network. Ticks and Counters-tab edits are saved in whichever browser opens it.
Its data is frozen at the moment it was built, so rebuild it (python3 fetch_dividends.py) whenever you want current figures.
The dashboard runs in its own container, published to the tailnet by
tailscale serve. The container binds to loopback only, so Serve is the one
route in — reachable on the tailnet, not on the local network, never public.
https://winnies-imac.tail823d40.ts.net
Docker here is Colima, installed as plain binaries under the home directory, so it needed no admin password:
~/.local/bin/docker docker CLI 29.9.2
~/.docker/cli-plugins/docker-compose compose 5.6.1
~/.local/lima/bin/limactl lima 2.2.1
~/.local/bin/colima colima 0.10.3
It runs on Apple's Virtualization.framework (no QEMU). ~/.zshrc puts these on
PATH, and a launch agent (~/Library/LaunchAgents/com.winnie.colima.plist)
starts the VM at login, so the dashboard comes back by itself after a reboot.
docker compose -f deploy/docker-compose.yml logs -f # watch requests
docker compose -f deploy/docker-compose.yml restart # reload
docker compose -f deploy/docker-compose.yml down # stop
colima status # is the VM up?
tailscale serve status # is it published?
index.html and dividends.json are bind-mounted read-only, so a refresh
updates the live site with no rebuild, and nginx sends no-store on both so the
page's 60-second poll sees it.
"Added to calendar" is a fact about the dividend, not about the browser that
recorded it, so the ticks are held server-side and everyone who can open the
dashboard sees the same ones. A second container (dividend-checks,
deploy/checks-api.py) keeps them in a Docker volume:
GET /api/checks the whole map, plus a revision number
PUT /api/checks/<counterId> merge one counter's tick
Each tick is its own request, so two people ticking different rows cannot overwrite each other, and a tick reaches other open pages over an SSE stream in well under a second. The header says ● Ticks shared when a store answered.
The counter roster is shared the same way:
GET /api/roster the added/removed overlay, plus a revision number
PUT /api/roster replace it
So adding or removing a counter in the Counters tab changes the board for everyone, not just the browser that did it, and a removal is reversible from the Removed section on any device.
Those edits become permanent on the next refresh. The agent pulls the
overlay, lets the fetcher fold it into dividends.json, and only then clears
it — so a throttled run postpones the edit rather than losing it. In practice a
counter removed in the dashboard is gone from the project file within 15
minutes, and the Removed section empties once it is.
Where none does — the standalone file, the hosted claude.ai copy, or the API being down — the page falls back to this-browser-only ticks and says so.
여기까지가 README 앞부분입니다. 나머지는 원문에서 읽을 수 있습니다. README 전문 보기 ↗