Track your securities in YNAB for account types and update your balance automatically.
Go to file
Steven Polley 7ce58c03d7
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
comments and formatting
2024-03-30 19:42:58 -06:00
data initial commit 2023-11-12 12:04:22 -07:00
providers comments and formatting 2024-03-30 19:42:58 -06:00
templates comments and formatting 2024-03-30 19:42:58 -06:00
ynab comments and formatting 2024-03-30 19:42:58 -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 Architecture Goal 2023-11-14 16:59:09 -07:00
webServer.go comments and formatting 2024-03-30 19:42:58 -06:00


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


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 files inside the provider directories for more details.

version: '3.8'


    restart: always
      - 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
      - /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 files located in the provider directories prefixed with "staticjson".