hledger-forecast 2.0.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/{test.yml → ci.yml} +18 -10
  3. data/.github/workflows/publish_ruby_gem.yml +24 -0
  4. data/.github/workflows/release.yml +12 -13
  5. data/.mise.toml +2 -0
  6. data/CHANGELOG.md +17 -0
  7. data/Gemfile +1 -0
  8. data/README.md +149 -119
  9. data/example.csv +15 -15
  10. data/example.journal +17 -18
  11. data/hledger-forecast.gemspec +20 -18
  12. data/lib/hledger_forecast/calculator.rb +7 -15
  13. data/lib/hledger_forecast/cli.rb +98 -71
  14. data/lib/hledger_forecast/comparator.rb +12 -11
  15. data/lib/hledger_forecast/forecast.rb +29 -0
  16. data/lib/hledger_forecast/formatter.rb +13 -15
  17. data/lib/hledger_forecast/generator.rb +32 -72
  18. data/lib/hledger_forecast/settings.rb +34 -47
  19. data/lib/hledger_forecast/summarizer.rb +34 -55
  20. data/lib/hledger_forecast/summarizer_formatter.rb +75 -78
  21. data/lib/hledger_forecast/transaction.rb +63 -0
  22. data/lib/hledger_forecast/transactions/default.rb +45 -72
  23. data/lib/hledger_forecast/version.rb +1 -1
  24. data/lib/hledger_forecast.rb +21 -22
  25. data/spec/calculator_spec.rb +45 -0
  26. data/spec/cli_spec.rb +19 -17
  27. data/spec/compare_spec.rb +16 -14
  28. data/spec/computed_amounts_spec.rb +7 -7
  29. data/spec/custom_spec.rb +9 -9
  30. data/spec/formatter_spec.rb +51 -0
  31. data/spec/half-yearly_spec.rb +5 -5
  32. data/spec/monthly_end_date_spec.rb +6 -6
  33. data/spec/monthly_end_date_transaction_spec.rb +10 -10
  34. data/spec/monthly_spec.rb +7 -7
  35. data/spec/once_spec.rb +5 -5
  36. data/spec/quarterly_spec.rb +5 -5
  37. data/spec/settings_spec.rb +101 -0
  38. data/spec/stubs/forecast.csv +4 -4
  39. data/spec/summarizer_spec.rb +28 -33
  40. data/spec/tags_spec.rb +92 -0
  41. data/spec/verbose_output_spec.rb +8 -8
  42. data/spec/yearly_spec.rb +5 -5
  43. metadata +49 -13
  44. data/lib/hledger_forecast/transactions/modifiers.rb +0 -90
  45. data/lib/hledger_forecast/transactions/trackers.rb +0 -88
  46. data/lib/hledger_forecast/utilities.rb +0 -14
  47. data/spec/track_spec.rb +0 -105
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c025630ee2a5d379fcf9e27509c1c5cc5438e5b0a38fcc73c3277fab8e1a6e2e
4
- data.tar.gz: 6d50f7774dbf3331328b9126392bad45aba281b00b4e93eb9060671b982560f6
3
+ metadata.gz: 33ae1c8b9a296f2420b87963e12ccc77a6a4b18cb5e9e977ed6e17f3d83b3c03
4
+ data.tar.gz: f4a4e1fa8df7a5d982036349903ce6a38b68edc59f2734be1ebc12a071ebf27f
5
5
  SHA512:
6
- metadata.gz: 7a21eca09d0f5145a54e4acff809090179cc48e9aa060ed6117c5ef2d17f578aab93b6779396254c3ff0437ff29ecffecf92546622f0dc2f9d12ee61e2794dbd
7
- data.tar.gz: 43509f84789f5dc0700924e22d3137eb4f07a11ee4cbbecef291770c4bdb2bbf83ef63c4aaecc7a87c0a4b77bc5ff29d578dc0e231cf68db85e76fc00f187ec7
6
+ metadata.gz: 1942ba18912517ceb70a6f2e4639632f5bccb6c98945d88509405c046e41c59631bebb099f15c89cc630ebca270360d5efd2c9eaea9fe7449eeb9be2fc5d9dee
7
+ data.tar.gz: d717115be6e73cf7277f29e01d4f465a63f1e03c88271a16ecd9df20600430b0d7483dc5f9a4c1831796a71413fb8bb2df9adb9f9dd5b3fd4c583c7e3e79a5fa
@@ -1,29 +1,37 @@
1
- name: Test
1
+ name: Continuous Integration
2
2
 
3
3
  on:
4
- pull_request:
5
- branches: [main]
6
4
  push:
7
- branches: [main]
5
+ branches:
6
+ - main
7
+ pull_request: ~
8
8
 
9
9
  jobs:
10
- test:
10
+ tests:
11
11
  runs-on: ubuntu-latest
12
12
  strategy:
13
13
  matrix:
14
- ruby-version: ['3.0', '3.1', '3.2']
14
+ ruby-version: ['3.3', '3.4']
15
15
 
16
16
  steps:
17
17
  - uses: actions/checkout@v4
18
- - name: Update packages
18
+
19
+ - name: Update packages 📦️
19
20
  run: sudo apt-get update
20
- - name: Install packages
21
+
22
+ - name: Install packages 📦️
21
23
  run: sudo apt-get -y install hledger
22
- - name: Set up Ruby
24
+
25
+ - name: Set up Ruby env 💎️
23
26
  uses: ruby/setup-ruby@v1
24
27
  with:
25
28
  bundler-cache: true
26
29
  ruby-version: ${{ matrix.ruby-version }}
27
- - name: Run tests
30
+
31
+ - name: Run tests 🧪
28
32
  run: |
29
33
  bundle exec rspec
34
+
35
+ - name: Build gem 💎️
36
+ run: gem build *.gemspec
37
+
@@ -0,0 +1,24 @@
1
+ name: Publish Ruby Gem
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ release:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - name: Publish Gem 💎️
16
+ run: |
17
+ mkdir -p $HOME/.gem
18
+ touch $HOME/.gem/credentials
19
+ chmod 0600 $HOME/.gem/credentials
20
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
21
+ gem build *.gemspec
22
+ gem push *.gem
23
+ env:
24
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
@@ -1,22 +1,21 @@
1
1
  name: Release
2
2
 
3
3
  on:
4
- release:
5
- types: [published]
4
+ push:
5
+ branches:
6
+ - main
6
7
 
7
8
  jobs:
8
9
  release:
9
10
  runs-on: ubuntu-latest
10
11
 
12
+ permissions:
13
+ contents: write
14
+ pull-requests: write
15
+
11
16
  steps:
12
- - uses: actions/checkout@v4
13
- - name: publish gem
14
- run: |
15
- mkdir -p $HOME/.gem
16
- touch $HOME/.gem/credentials
17
- chmod 0600 $HOME/.gem/credentials
18
- printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
19
- gem build *.gemspec
20
- gem push *.gem
21
- env:
22
- GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
17
+ - name: Release 📦
18
+ uses: googleapis/release-please-action@v4
19
+ with:
20
+ release-type: ruby
21
+
data/.mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = '3.4'
data/CHANGELOG.md ADDED
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## [3.0.0](https://github.com/olimorris/hledger-forecast/compare/v2.0.1...v3.0.0) (2026-03-27)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * plugin rewrite and removal of tracking ([#9](https://github.com/olimorris/hledger-forecast/issues/9))
9
+
10
+ ### Features
11
+
12
+ * add tag support ([#12](https://github.com/olimorris/hledger-forecast/issues/12)) ([2c341aa](https://github.com/olimorris/hledger-forecast/commit/2c341aa1270699d4bdd13431d5a1a7301169b7a0))
13
+
14
+
15
+ ### Code Refactoring
16
+
17
+ * plugin rewrite and removal of tracking ([#9](https://github.com/olimorris/hledger-forecast/issues/9)) ([1fadce6](https://github.com/olimorris/hledger-forecast/commit/1fadce6c1db34a93f5700997fb39800e4716c967))
data/Gemfile CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem 'bigdecimal'
5
6
  gem 'colorize'
6
7
  gem 'money'
7
8
  gem 'terminal-table'
data/README.md CHANGED
@@ -5,25 +5,48 @@
5
5
  <h1 align="center">hledger-forecast</h1>
6
6
 
7
7
  <p align="center">
8
- <a href="https://github.com/olimorris/hledger-forecast/stargazers"><img src="https://img.shields.io/github/stars/olimorris/hledger-forecast?color=c678dd&logoColor=e06c75&style=for-the-badge"></a>
9
- <a href="https://github.com/olimorris/hledger-forecast/issues"><img src="https://img.shields.io/github/issues/olimorris/hledger-forecast?color=%23d19a66&style=for-the-badge"></a>
10
- <a href="https://github.com/olimorris/hledger-forecast/blob/main/LICENSE"><img src="https://img.shields.io/github/license/olimorris/hledger-forecast?color=%2361afef&style=for-the-badge"></a>
11
- <a href="https://github.com/olimorris/hledger-forecast/actions/workflows/test.yml"><img src="https://img.shields.io/github/actions/workflow/status/olimorris/hledger-forecast/test.yml?branch=main&label=tests&style=for-the-badge"></a>
8
+ <a href="https://github.com/olimorris/hledger-forecast/stargazers"><img src="https://img.shields.io/github/stars/olimorris/hledger-forecast?style=for-the-badge"></a>
9
+ <a href="https://github.com/olimorris/hledger-forecast/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/olimorris/hledger-forecast/ci.yml?branch=main&label=tests&style=for-the-badge"></a>
10
+ <a href="https://github.com/olimorris/hledger-forecast/releases"><img src="https://img.shields.io/github/v/release/olimorris/hledger-forecast?style=for-the-badge"</a>
12
11
  </p>
13
-
14
12
  **"Improved", you say?** Using a _CSV_ file, forecasts can be quickly generated into a _journal_ file ready to be fed into [hledger](https://github.com/simonmichael/hledger). **A 16 line [CSV file](https://github.com/olimorris/hledger-forecast/blob/main/example.csv) can generate a 46 line hledger [forecast file](https://github.com/olimorris/hledger-forecast/blob/main/example.journal)!**
15
13
 
16
- Forecasts can also be constrained between dates, inflated by modifiers, tracked until they appear in your bank statements and summarized into your own daily/weekly/monthly/yearly personal forecast income and expenditure statement.
17
-
18
14
  ## :sparkles: Features
19
15
 
20
- - :rocket: Uses a simple CSV file to generate forecasts which can be used with hledger
21
- - :calendar: Can smartly track forecasts against your bank statement
22
- - :dollar: Can automatically apply modifiers such as inflation/deflation to forecasts
23
- - :mag: Enables the use of maths in your forecasts (for amounts and dates)
24
- - :bar_chart: Display your forecasts as income and expenditure reports (e.g. daily, weekly, monthly)
25
- - :twisted_rightwards_arrows: Compare and display the difference between hledger outputs
26
- - :computer: Simple and easy to use CLI
16
+ - :rocket: Simple CSV file drives the whole forecast
17
+ - :mag: Supports maths in your amounts _and_ dates
18
+ - :label: Apply tags to your transactions​
19
+ - :bar_chart: Summarize forecasts as daily/weekly/monthly/yearly income and expenditure reports
20
+ - :twisted_rightwards_arrows: Compare and highlight the difference between two hledger CSV outputs
21
+ - :computer: Straightforward CLI
22
+
23
+ ## :brain: The problem statement
24
+
25
+ Forecasting is essential to how I plan and budget with hledger. It enables me to know my financial position in 1 month, 10 months or even 100 months from now.
26
+
27
+ But forecasting in hledger is verbose and unintelligent. Consider this scenario: you purchase a new $3,000 laptop on a 0% finance deal and spread it over 20 months. In hledger, this would be accounted for with:
28
+
29
+ ```ledger
30
+ ~ monthly from 2026-01-01 to 2027-08-31 * New Laptop
31
+ Expenses:General Expenses $150.00
32
+ Assets:Checking
33
+ ```
34
+
35
+ Except, you'd need to work out what 20 months from `2026-01-01` is and do $3000 \div 20$.
36
+
37
+ In `hledger-forecast`, you add a single line to your CSV:
38
+
39
+ ```csv
40
+ monthly,,Assets:Checking,01/01/2026,=20,New Laptop,Expenses:General Expenses,=3000/20,,,
41
+ ```
42
+
43
+ The tool calculates the amount and the end date for you.
44
+
45
+ Now the natural next question: _what does that $150/month do to your monthly surplus_? With `hledger-forecast`, that's one command:
46
+
47
+ hledger-forecast summarize -f forecast.csv -r monthly
48
+
49
+ You get an [income statement](https://en.wikipedia.org/wiki/Income_statement) in your terminal - income, expenses, totals, and savings rate.
27
50
 
28
51
  ## :camera_flash: Screenshots
29
52
 
@@ -31,194 +54,201 @@ Forecasts can also be constrained between dates, inflated by modifiers, tracked
31
54
 
32
55
  <img src="https://github.com/olimorris/hledger-forecast/assets/9512444/430503b5-f447-4972-b122-b48f8628aff9" alt="hledger-Forecast" />
33
56
 
34
- **The ouput from the `summarize` command**
57
+ **The output from the `summarize` command**
35
58
 
36
59
  <img src="https://github.com/olimorris/hledger-forecast/assets/9512444/f5017ea2-9606-46ec-8b38-8840dc175e7b" alt="Summarize command" />
37
60
 
38
61
  ## :package: Installation
39
62
 
40
- Assuming you have Ruby and [Rubygems](http://rubygems.org/pages/download) installed on your system, simply run:
63
+ Assuming you have Ruby and [RubyGems](http://rubygems.org/pages/download) installed:
41
64
 
42
- gem install --user hledger-forecast
65
+ gem install hledger-forecast
43
66
 
44
67
  ## :rocket: Usage
45
68
 
46
- Run:
47
-
48
69
  hledger-forecast
49
-
50
- The available options are:
51
-
70
+
52
71
  Usage: hledger-forecast [command] [options]
53
-
72
+
54
73
  Commands:
55
- generate Generate a forecast from a file
74
+ generate Generate a forecast from a CSV file
56
75
  summarize Summarize the forecast file and output to the terminal
57
76
  compare Compare and highlight the differences between two CSV files
58
-
77
+
59
78
  Options:
60
79
  -h, --help Show this help message
61
80
  -v, --version Show version
62
81
 
63
- ### Generate command
82
+ ### Generate
64
83
 
65
- The `hledger-forecast generate` command will generate a forecast _from_ a `CSV` file _to_ a journal file. You can see the output of this command in the [example.journal](https://github.com/olimorris/hledger-forecast/blob/main/example.journal) file.
66
-
67
- The available options are:
84
+ Reads your CSV file and creates a journal file ready to use with hledger. See [example.journal](https://github.com/olimorris/hledger-forecast/blob/main/example.journal) for an example of the output.
68
85
 
86
+ hledger-forecast generate -f my_forecast.csv -o forecast.journal
87
+
69
88
  Usage: hledger-forecast generate [options]
70
-
89
+
71
90
  -f, --forecast FILE The path to the FORECAST CSV file to generate from
72
91
  -o, --output-file FILE The path to the OUTPUT file to create
73
- -t, --transaction FILE The path to the TRANSACTION journal file
92
+ -t, --tags TAGS Only include transactions with given tags (comma-separated)
74
93
  -v, --verbose Don't group transactions by type in the output file
75
94
  --force Force an overwrite of the output file
76
- --no-track Don't track any transactions
77
95
  -h, --help Show this help message
78
96
 
79
- > **Note**: For the tracking of transactions you need to include the `-t` flag
80
-
81
- Running the command with no options will assume a `forecast.csv` file exists.
97
+ Running with no options assumes a `forecast.csv` file exists in the current directory.
82
98
 
83
99
  ### Using with hledger
84
100
 
85
- To work with hledger, include the forecast file and use the `--forecast` flag:
101
+ Include the generated journal file and use hledger's `--forecast` flag:
86
102
 
87
- hledger -f bank_transactions.journal -f forecast.journal --forecast bal assets -e 2024-02
103
+ hledger -f bank_transactions.journal -f forecast.journal --forecast bal assets -e 2027-02
88
104
 
89
- The command will generate a forecast up to the end of Feb 2024, showing the balance for any asset accounts, overlaying some bank transactions with the forecast journal file. Forecasting in hledger can be complicated so be sure to refer to the [documentation](https://hledger.org/dev/hledger.html) or start a [discussion](https://github.com/olimorris/hledger-forecast/discussions/new?category=q-a).
105
+ This will generate a forecast up to the end of Feb 2027, showing asset balances with your bank transactions overlaid. Forecasting in hledger has some nuance, so please refer to the [hledger docs](https://hledger.org/dev/hledger.html) or open a [discussion](https://github.com/olimorris/hledger-forecast/discussions/new?category=q-a) if you get stuck.
90
106
 
91
- If you use the `hledger-ui` tool, it may be helpful to use the `--verbose` flag. This ensures that transactions are not grouped together in the forecast journal file, making descriptions much easier to read.
107
+ > **Tip:** If you use `hledger-ui`, the `--verbose` flag is worth using. It keeps each transaction as its own entry in the journal, making descriptions much easier to read in the UI.
92
108
 
93
- ### Summarize command
109
+ ### Summarize
94
110
 
95
- As your forecast file grows, it can be helpful to sum up the total amounts and output them to the CLI. Think of this command as your own _profit and loss_ summarizer, generating a statement over a period you specify.
111
+ As your forecast grows, it's useful to see the totals at a glance. Think of this as your income statement, rolled up to whatever period makes sense.
96
112
 
97
113
  hledger-forecast summarize -f my_forecast.csv
98
-
99
- The available options are:
100
-
114
+
101
115
  Usage: hledger-forecast summarize [options]
116
+
117
+ -f, --forecast FILE The path to the FORECAST CSV file to summarize
118
+ -r, --roll-up PERIOD The period to roll-up your forecasts into. One of:
119
+ [yearly], [half-yearly], [quarterly], [monthly], [weekly], [daily]
120
+ -t, --tags TAGS Only include transactions with given tags (comma-separated)
121
+ -v, --verbose Show additional information in the summary
122
+ -h, --help Show this help message
102
123
 
103
- -f, --forecast FILE The path to the FORECAST CSV file to summarize
104
- -r, --roll-up PERIOD The period to roll-up your forecasts into. One of:
105
- [yearly], [half-yearly], [quarterly], [monthly], [weekly], [daily]
106
- -v, --verbose Show additional information in the summary
107
- -h, --help Show this help message
124
+ ### Compare
108
125
 
109
- ### Compare command
126
+ A core part of managing personal finances is comparing what you _expected_ to happen with what _actually_ happened. The `compare` command makes this easy:
110
127
 
111
- A core part of managing your personal finances is the comparison of what you _expected_ to happen versus what _actually_ happened. This can be challenging to accomplish with hledger so to make this easier, the app has a useful `compare` command:
128
+ hledger-forecast compare path/to/expected.csv path/to/actual.csv
112
129
 
113
- hledger-forecast compare [path/to/file1.csv] [path/to/file2.csv]
130
+ To generate CSV output from hledger, append `-O csv > output.csv` to any hledger command.
114
131
 
115
- To generate CSV output with hledger, append `-O csv > output.csv` to your desired command.
132
+ For wide output, pipe through a pager like [most](https://en.wikipedia.org/wiki/Most_(Unix)):
116
133
 
117
- To make it easier to read horizontal output in the terminal, consider the use of a terminal pager like [most](https://en.wikipedia.org/wiki/Most_(Unix)) by appending `| most` to the compare command.
134
+ hledger-forecast compare file1.csv file2.csv | most
118
135
 
119
- > **Note:** The two CSV files being compared must have the same structure
136
+ > **Note:** The two CSV files must have the same structure.
120
137
 
121
138
  ## :gear: Creating your forecast
122
139
 
123
- The app makes it easy to generate a comprehensive _journal_ file with very few lines of code, making it much easier to stay on top of your forecasting from month to month.
124
-
125
140
  ### Columns
126
141
 
127
- The _CSV_ file _should_ contain a header row with the following columns:
128
-
129
- - `type` - (string) - The type of forecast entry. One of `monthly`, `quarterly`, `half-yearly`, `yearly`, `once` or `custom`
130
- - `frequency` - (string) - The frequency that the type repeats with (only if `custom`). As per hledger's [periodic rule syntax](https://hledger.org/dev/hledger.html#periodic-transactions)
131
- - `account` - (string) - The account the transaction applies to e.g. _Expenses:Food_
132
- - `from` - (date) - The date the transaction should start from e.g. _2023-06-01_
133
- - `to` - (date) _(optional)_ - The date the transaction should end on e.g. _2023-12-31_
134
- - `description` - (string) - A description of the transaction
135
- - `category` - (string) - The classification or category of the transaction
136
- - `amount` - (integer/float) - The amount of the transaction
137
- - `roll-up` - (integer/float) _(optional)_ - For use with the summarizer, the value you need to multiply the amount by to get it into a yearly amount
138
- - `summary_exclude` - (boolean) _(optional)_ - Exclude the transaction from the summarizer?
139
- - `track` - (boolean) _(optional)_ - Track the transaction against your confirmed transactions?
142
+ The CSV file should have a header row with these columns:
140
143
 
141
- ### Example forecast
144
+ | Column | Type | Required | Description |
145
+ |---|---|---|---|
146
+ | `type` | string | yes | One of: `monthly`, `quarterly`, `half-yearly`, `yearly`, `once`, `custom` |
147
+ | `frequency` | string | `custom` only | Repeating frequency, using hledger's [periodic rule syntax](https://hledger.org/dev/hledger.html#periodic-transactions) |
148
+ | `account` | string | yes | The account the transaction applies to, e.g. `Assets:Bank` |
149
+ | `from` | date | yes | Start date, e.g. `01/03/2023` |
150
+ | `to` | date | no | End date, e.g. `01/01/2025` |
151
+ | `description` | string | yes | A description of the transaction |
152
+ | `category` | string | yes | The category account, e.g. `Expenses:Food` |
153
+ | `amount` | number | yes | The transaction amount. Supports `=` prefix for calculated values |
154
+ | `roll-up` | number | no | Multiplier for the summarizer — use this for `custom` types to annualise them |
155
+ | `summary_exclude` | boolean | no | Set to `TRUE` to exclude from the summarizer |
156
+ | `tag` | string | no | Pipe-separated tags, e.g. `fixed|essential`. Outputs as native hledger tags |
142
157
 
143
- Putting it together, we end up with a CSV file like:
158
+ ### Example
144
159
 
145
160
  ```csv
146
- type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
147
- monthly,,Assets:Bank,01/03/2023,,Salary,Income:Salary,-3500,,,
148
- monthly,,Assets:Bank,01/03/2023,01/01/2025,Mortgage,Expenses:Mortgage,2000,,,
149
- monthly,,Assets:Bank,01/03/2023,,Bills,Expenses:Bills,175,,,
150
- monthly,,Assets:Bank,01/03/2023,,Food,Expenses:Food,500,,,
151
- monthly,,Assets:Bank,01/03/2023,,New Kitchen,Expenses:House,=5000/24,,,
152
- monthly,,Assets:Bank,01/03/2023,=12,Holiday,Expenses:Holiday,125,,,
153
- monthly,,Assets:Bank,01/03/2023,01/03/2025,Rainy day fund,Assets:Savings,300,,,
154
- monthly,,Assets:Pension,01/01/2024,,Pension draw down,Income:Pension,-500,,,
155
- quarterly,,Assets:Bank,01/04/2023,,Quarterly bonus,Income:Bonus,-1000,,,
156
- half-yearly,,Assets:Bank,01/04/2023,,Top up holiday funds,Expenses:Holiday,500,,,
157
- yearly,,Assets:Bank,01/04/2023,,Annual bonus,Income:Bonus,-2000,,,
158
- once,,Assets:Bank,05/03/2023,,Refund for that damn laptop,Expenses:Shopping,-3000,,TRUE,TRUE
159
- custom,every 2 weeks,Assets:Bank,01/03/2023,,Hair and beauty,Expenses:Personal Care,80,26,,
160
- custom,every 5 weeks,Assets:Bank,01/03/2023,,Misc expenses,Expenses:General Expenses,30,10.4,,
161
+ type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,tag
162
+ monthly,,Assets:Bank,01/03/2023,,Salary,Income:Salary,-3500,,,fixed|essential
163
+ monthly,,Assets:Bank,01/03/2023,01/01/2025,Mortgage,Expenses:Mortgage,2000,,,fixed|essential
164
+ monthly,,Assets:Bank,01/03/2023,,Bills,Expenses:Bills,175,,,fixed|essential
165
+ monthly,,Assets:Bank,01/03/2023,,Food,Expenses:Food,500,,,living|essential
166
+ monthly,,Assets:Bank,01/03/2023,,New Kitchen,Expenses:House,=5000/24,,,living
167
+ monthly,,Assets:Bank,01/03/2023,=12,Holiday,Expenses:Holiday,125,,,living
168
+ monthly,,Assets:Bank,01/03/2023,01/03/2025,Rainy day fund,Assets:Savings,300,,,saving
169
+ monthly,,Assets:Pension,01/01/2024,,Pension draw down,Income:Pension,-500,,,fixed|essential
170
+ quarterly,,Assets:Bank,01/04/2023,,Quarterly bonus,Income:Bonus,-1000,,,fixed
171
+ half-yearly,,Assets:Bank,01/04/2023,,Top up holiday funds,Expenses:Holiday,500,,,living
172
+ yearly,,Assets:Bank,01/04/2023,,Annual bonus,Income:Bonus,-2000,,,fixed
173
+ once,,Assets:Bank,05/03/2023,,Refund for that damn laptop,Expenses:Shopping,-3000,TRUE,
174
+ custom,every 2 weeks,Assets:Bank,01/03/2023,,Hair and beauty,Expenses:Personal Care,80,26,,living
175
+ custom,every 5 weeks,Assets:Bank,01/03/2023,,Misc expenses,Expenses:General Expenses,30,10.4,,living
161
176
  settings,currency,USD,,,,,,,,
162
177
  ```
163
178
 
164
- ### Additional features
179
+ ### Calculated amounts
180
+
181
+ Prefix any `amount` with `=` and write it as a standard formula — the app will evaluate it for you. Great for spreading a lump sum across months:
165
182
 
166
- From the example above, there are a few additional features that may be useful.
183
+ ```csv
184
+ monthly,,Assets:Bank,01/03/2023,,New Kitchen,Expenses:House,=5000/24,,
185
+ ```
167
186
 
168
- #### Calculated amounts
187
+ > Calculations are evaluated to two decimal places.
169
188
 
170
- > **Note**: Calculations will be determined up to two decimal places
189
+ ### Calculated dates
171
190
 
172
- It may be helpful to let the app calculate the forecasted amount in your transactions on your behalf. This can be especially useful if you're spreading a payment out over a number of months:
191
+ The `to` column also supports calculated values. Use `=` followed by a number to mean "N months from the `from` date":
173
192
 
174
193
  ```csv
175
- type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
176
- monthly,,Assets:Bank,01/03/2023,,New Kitchen,Expenses:House,=5000/24,,,
194
+ monthly,,Assets:Bank,01/03/2023,=12,Holiday,Expenses:Holiday,125,,
177
195
  ```
178
196
 
179
- Simply start the `amount` column with a `=` sign and use standard Excel based math formatting.
197
+ That sets the end date to 12 months after `01/03/2023`.
180
198
 
181
- #### Calculated dates
199
+ ### Tags
182
200
 
183
- It may also be helpful for `to` dates to be calculated:
201
+ Add a `tag` column to your CSV to tag transactions. Tags are output as native [hledger tags](https://hledger.org/tags-tutorial.html), making them queryable in hledger itself. Multiple tags are separated by pipes (`|`):
184
202
 
185
203
  ```csv
186
- type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
187
- monthly,,Assets:Bank,01/03/2023,=12,Holiday,Expenses:Holiday,125,,,
204
+ type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,tag
205
+ monthly,,Assets:Bank,01/03/2023,,Salary,Income:Salary,-3500,,,fixed|essential
206
+ monthly,,Assets:Bank,01/03/2023,,Food,Expenses:Food,500,,,living|essential
207
+ monthly,,Assets:Bank,01/03/2023,,Netflix,Expenses:Subscriptions,15,,,living
188
208
  ```
189
209
 
190
- ### Settings
191
-
192
- There are also additional settings that can be applied in the forecast. The defaults are:
210
+ This generates journal entries with proper hledger tags on each posting:
193
211
 
194
- ```csv
195
- type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
196
- settings,currency,USD,,,,,,,,
197
- settings,show_symbol,true,,,,,,,,
198
- settings,thousands_separator,true,,,,,,,,
212
+ ```
213
+ ~ monthly from 2023-03-01 * Salary, Food, Netflix
214
+ Income:Salary £-3,500.00; fixed:, essential:
215
+ Expenses:Food £500.00 ; living:, essential:
216
+ Expenses:Subscriptions £15.00 ; living:
217
+ Assets:Bank
199
218
  ```
200
219
 
201
- ### Tracking
220
+ **Filtering by tags** - both `generate` and `summarize` accept a `--tags` flag to include only transactions matching any of the given tags:
202
221
 
203
- > **Note**: Marking a transaction for tracking will ensure that it is only written into the forecast if it isn't found within a specified transaction file
222
+ ```bash
223
+ # Generate a journal with only your fixed costs
224
+ hledger-forecast generate -f forecast.csv -o fixed.journal --tags=fixed
204
225
 
205
- Sometimes it can be useful to track and monitor forecasted transactions to ensure that they are accounted for in any financial projections. If they are present, then these should be discarded from your forecast as this will create a double count against your actuals. However, if they can't be found then they should be carried forward into a future period to ensure accurate recording.
226
+ # Summarize only essential spending
227
+ hledger-forecast summarize -f forecast.csv --tags=essential
206
228
 
207
- To mark transactions as available for tracking you may use the `track` option in your config file:
229
+ # Multiple tags use OR logic matches any
230
+ hledger-forecast summarize -f forecast.csv --tags=fixed,living
231
+ ```
208
232
 
209
- ```csv
210
- type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
211
- once,,Assets:Bank,2023-03-05,,Refund for that damn laptop,Expenses:Shopping,-3000,,,TRUE
233
+ **Querying in hledger** - because the tags are native hledger format, you can query them directly:
234
+
235
+ ```bash
236
+ hledger bal tag:fixed -f forecast.journal
237
+ hledger bal tag:essential not:tag:living -f forecast.journal
212
238
  ```
213
239
 
214
- > **Note**: This feature has been designed to work with `once` transaction types only
240
+ ### Settings
215
241
 
216
- To use this feature, ensure you pass a filepath to the `-t` flag, such as:
242
+ Settings rows live in the same CSV file. The defaults are:
217
243
 
218
- hledger-forecast generate -t [journal_file_to_search] -f [path_to_yaml_file] -o [path_to_output_journal]
244
+ ```csv
245
+ settings,currency,USD,,,,,,,,
246
+ settings,show_symbol,true,,,,,,,,
247
+ settings,thousands_separator,true,,,,,,,,
248
+ ```
219
249
 
220
- The app will use a hledger query to determine if the combination of category and amount is present in the periods between the `from` key and the current date in the journal file you've specified. If not, then the app will include it as a forecast transaction in the output file.
250
+ Override any of them by adding a `settings` row. Multiple settings rows are fine they won't clobber each other.
221
251
 
222
252
  ## :pencil2: Contributing
223
253
 
224
- I am open to any pull requests that fix bugs but would ask that any new functionality is discussed before it could be accepted.
254
+ I'm open to pull requests that fix bugs. For new functionality, please open a discussion first so we can figure out whether it's the right direction before any code is written.
data/example.csv CHANGED
@@ -1,16 +1,16 @@
1
- type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,track
2
- monthly,,Assets:Bank,01/03/2023,,Salary,Income:Salary,-3500,,,
3
- monthly,,Assets:Bank,01/03/2023,01/01/2025,Mortgage,Expenses:Mortgage,2000,,,
4
- monthly,,Assets:Bank,01/03/2023,,Bills,Expenses:Bills,175,,,
5
- monthly,,Assets:Bank,01/03/2023,,Food,Expenses:Food,500,,,
6
- monthly,,Assets:Bank,01/03/2023,,New Kitchen,Expenses:House,=5000/24,,,
7
- monthly,,Assets:Bank,01/03/2023,=12,Holiday,Expenses:Holiday,125,,,
8
- monthly,,Assets:Bank,01/03/2023,01/03/2025,Rainy day fund,Assets:Savings,300,,,
9
- monthly,,Assets:Pension,01/01/2024,,Pension draw down,Income:Pension,-500,,,
10
- quarterly,,Assets:Bank,01/04/2023,,Quarterly bonus,Income:Bonus,-1000,,,
11
- half-yearly,,Assets:Bank,01/04/2023,,Top up holiday funds,Expenses:Holiday,500,,,
12
- yearly,,Assets:Bank,01/04/2023,,Annual bonus,Income:Bonus,-2000,,,
13
- once,,Assets:Bank,05/03/2023,,Refund for that damn laptop,Expenses:Shopping,-3000,,TRUE,TRUE
14
- custom,every 2 weeks,Assets:Bank,01/03/2023,,Hair and beauty,Expenses:Personal Care,80,26,,
15
- custom,every 5 weeks,Assets:Bank,01/03/2023,,Misc expenses,Expenses:General Expenses,30,10.4,,
1
+ type,frequency,account,from,to,description,category,amount,roll-up,summary_exclude,tag
2
+ monthly,,Assets:Bank,01/03/2023,,Salary,Income:Salary,-3500,,,fixed|essential
3
+ monthly,,Assets:Bank,01/03/2023,01/01/2025,Mortgage,Expenses:Mortgage,2000,,,fixed|essential
4
+ monthly,,Assets:Bank,01/03/2023,,Bills,Expenses:Bills,175,,,fixed|essential
5
+ monthly,,Assets:Bank,01/03/2023,,Food,Expenses:Food,500,,,living|essential
6
+ monthly,,Assets:Bank,01/03/2023,,New Kitchen,Expenses:House,=5000/24,,,living
7
+ monthly,,Assets:Bank,01/03/2023,=12,Holiday,Expenses:Holiday,125,,,living
8
+ monthly,,Assets:Bank,01/03/2023,01/03/2025,Rainy day fund,Assets:Savings,300,,,saving
9
+ monthly,,Assets:Pension,01/01/2024,,Pension draw down,Income:Pension,-500,,,fixed|essential
10
+ quarterly,,Assets:Bank,01/04/2023,,Quarterly bonus,Income:Bonus,-1000,,,fixed
11
+ half-yearly,,Assets:Bank,01/04/2023,,Top up holiday funds,Expenses:Holiday,500,,,living
12
+ yearly,,Assets:Bank,01/04/2023,,Annual bonus,Income:Bonus,-2000,,,fixed
13
+ once,,Assets:Bank,05/03/2023,,Refund for that damn laptop,Expenses:Shopping,-3000,TRUE,
14
+ custom,every 2 weeks,Assets:Bank,01/03/2023,,Hair and beauty,Expenses:Personal Care,80,26,,living
15
+ custom,every 5 weeks,Assets:Bank,01/03/2023,,Misc expenses,Expenses:General Expenses,30,10.4,,living
16
16
  settings,currency,USD,,,,,,,,
data/example.journal CHANGED
@@ -1,47 +1,46 @@
1
1
  ~ monthly from 2023-03-01 * Salary, Bills, Food, New Kitchen
2
- Income:Salary $-3,500.00 ; Salary
3
- Expenses:Bills $175.00 ; Bills
4
- Expenses:Food $500.00 ; Food
5
- Expenses:House $208.33 ; New Kitchen
2
+ Income:Salary $-3,500.00; fixed:, essential:
3
+ Expenses:Bills $175.00 ; fixed:, essential:
4
+ Expenses:Food $500.00 ; living:, essential:
5
+ Expenses:House $208.33 ; living:
6
6
  Assets:Bank
7
7
 
8
8
  ~ monthly from 2023-03-01 to 2025-01-01 * Mortgage
9
- Expenses:Mortgage $2,000.00 ; Mortgage
9
+ Expenses:Mortgage $2,000.00 ; fixed:, essential:
10
10
  Assets:Bank
11
11
 
12
12
  ~ monthly from 2023-03-01 to 2024-02-29 * Holiday
13
- Expenses:Holiday $125.00 ; Holiday
13
+ Expenses:Holiday $125.00 ; living:
14
14
  Assets:Bank
15
15
 
16
16
  ~ monthly from 2023-03-01 to 2025-03-01 * Rainy day fund
17
- Assets:Savings $300.00 ; Rainy day fund
17
+ Assets:Savings $300.00 ; saving:
18
18
  Assets:Bank
19
19
 
20
20
  ~ monthly from 2024-01-01 * Pension draw down
21
- Income:Pension $-500.00 ; Pension draw down
21
+ Income:Pension $-500.00 ; fixed:, essential:
22
22
  Assets:Pension
23
23
 
24
24
  ~ every 3 months from 2023-04-01 * Quarterly bonus
25
- Income:Bonus $-1,000.00 ; Quarterly bonus
25
+ Income:Bonus $-1,000.00; fixed:
26
26
  Assets:Bank
27
27
 
28
28
  ~ every 6 months from 2023-04-01 * Top up holiday funds
29
- Expenses:Holiday $500.00 ; Top up holiday funds
29
+ Expenses:Holiday $500.00 ; living:
30
30
  Assets:Bank
31
31
 
32
32
  ~ yearly from 2023-04-01 * Annual bonus
33
- Income:Bonus $-2,000.00 ; Annual bonus
33
+ Income:Bonus $-2,000.00; fixed:
34
34
  Assets:Bank
35
35
 
36
- ~ every 2 weeks from 2023-03-01 * Hair and beauty
37
- Expenses:Personal Care $80.00 ; Hair and beauty
36
+ ~ 2023-03-05 * Refund for that damn laptop
37
+ Expenses:Shopping $-3,000.00
38
38
  Assets:Bank
39
39
 
40
- ~ every 5 weeks from 2023-03-01 * Misc expenses
41
- Expenses:General Expenses $30.00 ; Misc expenses
40
+ ~ every 2 weeks from 2023-03-01 * Hair and beauty
41
+ Expenses:Personal Care $80.00 ; living:
42
42
  Assets:Bank
43
43
 
44
- ~ 2024-01-01 * [TRACKED] Refund for that damn laptop
45
- Expenses:Shopping $-3,000.00; Refund for that damn laptop
44
+ ~ every 5 weeks from 2023-03-01 * Misc expenses
45
+ Expenses:General Expenses $30.00 ; living:
46
46
  Assets:Bank
47
-