Track your securities in YNAB for account types and update your balance automatically.
Go to file
Steven Polley 54417bf436
All checks were successful
continuous-integration/drone/push Build is passing
don't export BearerToken
2024-03-23 19:45:28 -06:00
data initial commit 2023-11-12 12:04:22 -07:00
providers Do not export when not required 2024-03-23 14:06:38 -06:00
templates add css for loader h3 2024-02-17 16:41:50 -07:00
ynab don't export BearerToken 2024-03-23 19:45:28 -06:00
.drone.yml copy timezone database from build environment 2023-11-13 16:18:48 -07:00
.gitignore abstract providers behind a common interface 2023-11-12 21:40:00 -07:00
accountProviders.go move providers into providers subdirectory 2023-11-13 17:39:22 -07:00
Dockerfile Did I really not call it a directory in the previous commit. I am tainted 2024-02-24 16:22:02 +00:00
example-image.png add example image 2023-11-12 13:20:53 -07:00
go.mod Update go.mod to 1.22 2024-02-17 09:51:20 -07:00
main.go initialize refreshRunning mutex 2023-11-13 18:12:13 -07:00
README.md Architecture Goal 2023-11-14 16:59:09 -07:00
webServer.go Removed public directory as all front end assets are embedded in the HTML directly 2024-02-24 09:09:05 -07:00

ynab-portfolio-monitor

Build Status

Track your securities in YNAB for account types and update your balance automatically. For each configured account, it will update the balance from your broker in YNAB every 6 hours by creating / editing a transaction named "Capital Gains or Losses". On days that exchanges are closed, it will not do anything. The end result is that there will be transaction each day with payee "Capital Gains or Losses" in YNAB for each account you configure, which allows tracking your account balance over time.

It syncs your balance like magic!

alt text

Architecture

No bloat, uses only the standard library, separate all integrations into their own package.

Main Package

Each account provider / integration is defined in its own package and adheres to the interface specified in accountProviders.go. When the program starts, init() inside main.go attempts to configure all providers, and uses providers where configuration succeeds and ignores providers if configuration fails (eg: missing environment variable or config file). init() will run again if SIGHUP is received to reload configuration.

The main() program loop refreshes data every 6 hours by looping through each configured provider and calling AccountProvider.GetBalances(). This returns a slice of balances, and a slice of YNAB account IDs. The index position of the balance slice maps with the index of the YNAB account ID slice. This allows a single provider to provide multiple balances for different YNAB accounts depending on the provider's configuration (eg: if you have multiple accounts at your broker). We loop through the balance slice and update each YNAB account balance with the value. Finally, sleep for 6 hours before doing it again.

Provider Packages

Provider packages are used for any integration and are found in their own sub directories. Providers must adhere to the interface speficied in accountProviders.go.

// AccountProvider is the base set of requirements to be implemented for any integration
type AccountProvider interface {
	Name() string                          // Returns the name of the provider
	Configure() error                      // Configures the provider for first use - if an error is returned the provider is not used
	GetBalances() ([]int, []string, error) // A slice of balances, and an index mapped slice of ynab account IDs this provider handles is returned
}

By convention, these methods are implemented in a file called providerImpl.go in each of the provider packages.

The following providers are currently available:

  • bitcoin
  • questrade
  • staticjsonFinnhub
  • staticjsonYahooFinance

YNAB Package

This is a special package used for messaging to and from YNAB, instead of adhering to the AccountProvider interface, it exposes multiple public methods for use in the Main package's business logic.

Example docker-compose.yml

The values below are examples only, and show how to configure the Questrade and Bitcoin providers. With these providers, you can configure as many account pairings as you want using environment variables in a continuous series starting from 0 as shown below. Two example Questrade accounts are configured ending in _0 and _1 but a third can be added by adding account numbers/ID with _2. See the respective README.md files inside the provider directories for more details.

version: '3.8'

services:    

  ynab-portfolio-monitor:
    image: registry.deadbeef.codes/ynab-portfolio-monitor:latest
    restart: always
    environment:
      - TZ=America/Edmonton
      - questrade_refresh_token=4dsO6652dS3cxtcctscd3ds4Df2E0
      - questrade_account_0=51000001 # TFSA
      - questrade_account_1=51000002 # RRSP
      - questrade_ynab_account_0=731af51e-cb40-4d4a-8094-8654e59e11fc # TFSA
      - questrade_ynab_account_1=78e76e45-2fbe-4ab1-84e9-64ba0996d015 # RRSP
      - ynab_budget_id=76566452-67ff-4642-99d1-47d752216fb3
      - ynab_secret=98Q_J655F_TAyGnhCCDS4uqRe4R5654DT2d-ZXdssZ
      - bitcoin_address_0=bc1qg0edu4tr7pza8qsxf576r0eulr2ygt3mhldswg
      - bitcoin_address_1=bc1qeh0dkdqvjyt646657lge0nxqj67z5xa8zxl8q3
      - bitcoin_address_2=bc1qsfsdqvj4443t64dfssfgexsaqj67z44dsjkfkj
      - bitcoin_ynab_account=1f5bec0d-f852-2fbe-bbee-02fa98ded566 # Bitcoin addresses map to single YNAB account
    volumes:
      - /data/ynab-portfolio-monitor-data:/data

Static JSON Providers

If your broker doesn't have a provider available, or if you don't want to connect this application to your brokerage account, there is an offline solution available where you can configure your holdings in local static JSON files - and these only need to be updated if your holdings change such as after a trade has been made, or a stock split.

For more details, see the README.md files located in the provider directories prefixed with "staticjson".