elbank-ynab.html (13988B)
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset="utf-8"> 6 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 7 <meta name="viewport" content="width=device-width, initial-scale=1"> 8 9 <title>Using Ledger for YNAB-like envelope budgeting</title> 10 <meta name="description" content="Bye bye Elbank"> 11 12 <link rel="shortcut icon" type="image/png" href="/favicon.png"/> 13 <link href="https://fonts.googleapis.com/css?family=Fira+Mono|Gentium+Book+Basic|Lato" rel="stylesheet"> 14 <link rel="stylesheet" href="/assets/main.css"> 15 <link rel="stylesheet" href="/css/cafe.css"> 16 <link rel="canonical" href="https://emacs.cafe/ledger/emacs/ynab/budgeting/2018/06/12/elbank-ynab.html"> 17 <link rel="alternate" type="application/rss+xml" title="Emacs café" href="/feed.xml"> 18 19 20 </head> 21 22 23 <body> 24 25 <header class="site-header" role="banner"> 26 27 <div class="wrapper"> 28 29 30 <a class="site-title" href="/"><img src="/img/emacscafe.png"/>Emacs café</a> 31 32 33 <nav class="site-nav"> 34 <input type="checkbox" id="nav-trigger" class="nav-trigger" /> 35 <label for="nav-trigger"> 36 <span class="menu-icon"> 37 <svg viewBox="0 0 18 15" width="18px" height="15px"> 38 <path fill="#424242" d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.031C17.335,0,18,0.665,18,1.484L18,1.484z"/> 39 <path fill="#424242" d="M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0c0-0.82,0.665-1.484,1.484-1.484 h15.031C17.335,6.031,18,6.696,18,7.516L18,7.516z"/> 40 <path fill="#424242" d="M18,13.516C18,14.335,17.335,15,16.516,15H1.484C0.665,15,0,14.335,0,13.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.031C17.335,12.031,18,12.696,18,13.516L18,13.516z"/> 41 </svg> 42 </span> 43 </label> 44 45 <div class="trigger"> 46 47 48 49 <a class="page-link" href="/about/">About Emacs café</a> 50 51 52 53 54 55 56 57 58 59 60 61 </div> 62 </nav> 63 64 </div> 65 </header> 66 67 68 <main class="page-content" aria-label="Content"> 69 <div class="wrapper"> 70 <article class="post" itemscope itemtype="http://schema.org/BlogPosting"> 71 72 <header class="post-header"> 73 <h1 class="post-title" itemprop="name headline">Using Ledger for YNAB-like envelope budgeting</h1> 74 <p class="post-meta"> 75 <time datetime="2018-06-12T21:20:00+02:00" itemprop="datePublished"> 76 77 Jun 12, 2018 78 </time> 79 80 • <span itemprop="author" itemscope itemtype="http://schema.org/Person"><span itemprop="name">Nicolas Petton</span></span> 81 </p> 82 </header> 83 84 <div class="post-content" itemprop="articleBody"> 85 <h1 id="bye-bye-elbank">Bye bye Elbank</h1> 86 87 <p>I have to start this post with this: I will not be actively maintaining 88 <a href="https://github.com/NicolasPetton/elbank">Elbank</a> anymore, simply because I 89 switched back to <a href="https://www.ledger-cli.org/">Ledger</a>. If someone wants to 90 take over, please contact me!</p> 91 92 <p>The main reason for switching is budgeting. While Elbank was a cool experiment, 93 it is not an accounting software, and inherently lacks support for powerful 94 budgeting.</p> 95 96 <p>When I started working on Elbank as a replacement for Ledger, I was looking for 97 a reporting tool within Emacs that would fetch bank transactions automatically, 98 so I wouldn’t have to enter transactions by hand (this is a seriously tedious 99 task, and I grew tired of doing it after roughly two years, and finally gave up).</p> 100 101 <p>Since then, I learned about ledger-autosync and boobank, which I use to sync my 102 bank statements with Ledger (more about that in another post).</p> 103 104 <h1 id="ynabs-way-of-budgeting">YNAB’s way of budgeting</h1> 105 106 <p>I only came across <a href="https://ynab.com">YNAB</a> recently. While I won’t use their 107 software (being a non-free web application, and, you know… there’s no <code class="highlighter-rouge">M-x 108 ynab</code>), I think that the principles behind it are really appealing for personal 109 budgeting. I encourage you to <a href="https://www.youneedabudget.com/method/">read more about 110 it</a> (or grab a <a href="https://www.youneedabudget.com/book-order-now/">copy of the 111 book</a>, it’s great), but here’s 112 the idea.</p> 113 114 <ol> 115 <li> 116 <p><strong>Budget every euro</strong>: Quite simple once you get it. Every single Euro you have 117 should be in a budget envelope. You should assign a job to every Euro you 118 earn (that’s called 119 <a href="https://en.wikipedia.org/wiki/Zero-based_budgeting">zero-based</a>, <a href="https://en.wikipedia.org/wiki/Envelope_system">envelope 120 system</a>).</p> 121 </li> 122 <li> 123 <p><strong>Embrace your true expenses</strong>: Plan for larger and less frequent expenses, so 124 when a yearly bill arrives, or your car breaks down, you’ll be covered.</p> 125 </li> 126 <li> 127 <p><strong>Roll with the punches</strong>: Address overspending as it happens by taking money 128 overspent from another envelope. As long as you keep budgeting, you’re 129 succeeding.</p> 130 </li> 131 <li> 132 <p><strong>Age your money</strong>: Spend less than you earn, so your money stays in the bank 133 account longer. As you do that, the age of your money will grow, and once 134 you reach the goal of spending money that is at least one month old, you 135 won’t worry about that next bill.</p> 136 </li> 137 </ol> 138 139 <h1 id="implementation-in-ledger">Implementation in Ledger</h1> 140 141 <p>I assume that you are familiar with Ledger, but if not I recommend reading its 142 great 143 <a href="https://www.ledger-cli.org/3.0/doc/ledger3.html#Introduction-to-Ledger">introduction</a> 144 and <a href="https://www.ledger-cli.org/3.0/doc/ledger3.html#Ledger-Tutorial">tutorial</a>.</p> 145 146 <p>The implementation in Ledger uses plain double-entry accounting. I took most of 147 it from 148 <a href="http://sachachua.com/blog/2014/11/keeping-financial-score-ledger/">Sacha</a>, with 149 some minor differences.</p> 150 151 <h2 id="budgeting-new-money">Budgeting new money</h2> 152 153 <p>After each income transaction, I budget the new money:</p> 154 155 <div class="highlighter-rouge"><pre class="highlight"><code>2018-06-12 Employer 156 Assets:Bank:Checking 1600.00 EUR 157 Income:Salary -1600.00 EUR 158 159 2018-06-12 Budget 160 [Assets:Budget:Food] 400.00 EUR 161 [Assets:Budget:Rent] 600.00 EUR 162 [Assets:Budget:Utilities] 600.00 EUR 163 [Equity:Budget] -1600.00 EUR 164 </code></pre> 165 </div> 166 167 <p>Did you notice the square brackets around the accounts of the budget 168 transaction? It’s a feature Ledger calls <a href="https://www.ledger-cli.org/3.0/doc/ledger3.html#Virtual-postings">virtual 169 postings</a>. These 170 postings are not considered real, and won’t be present in any report that uses 171 the <code class="highlighter-rouge">--real</code> flag. This is exactly what we want, since it’s a budget allocation 172 and not a “real” transaction. Therefore we’ll use the <code class="highlighter-rouge">--real</code> flag for all 173 reports except for our budget report.</p> 174 175 <h2 id="automatically-crediting-budget-accounts-when-spending-money">Automatically crediting budget accounts when spending money</h2> 176 177 <p>Next, we need to credit the budget accounts each time we spend money. Ledger 178 has another neat feature called <a href="https://www.ledger-cli.org/3.0/doc/ledger3.html#Automated-Transactions">automated 179 transactions</a> 180 for this:</p> 181 182 <div class="highlighter-rouge"><pre class="highlight"><code>= /Expenses/ 183 [Assets:Budget:Unbudgeted] -1.0 184 [Equity:Budget] 1.0 185 186 = /Expenses:Food/ 187 [Assets:Budget:Food] -1.0 188 [Assets:Budget:Unbudgeted] 1.0 189 190 = /Expenses:Rent/ 191 [Assets:Budget:Rent] -1.0 192 [Assets:Budget:Unbudgeted] 1.0 193 194 = /Expenses:Utilities/ 195 [Assets:Budget:Utilities] -1.0 196 [Assets:Budget:Unbudgeted] 1.0 197 </code></pre> 198 </div> 199 200 <p>Every expense is taken out of the <code class="highlighter-rouge">Assets:Budget:Unbudgeted</code> account by default.</p> 201 202 <p>This forces me to budget properly, as <code class="highlighter-rouge">Assets:Budget:Unbudgeted</code> should always 203 be 0 (if it is not the case I immediately know that there is something wrong 204 going on).</p> 205 206 <p>All other automatic transactions take money out of the 207 <code class="highlighter-rouge">Assets:Budget:Unbudgeted</code> account instead of <code class="highlighter-rouge">Equity:Budget</code> account.</p> 208 209 <h2 id="a-budget-report">A Budget report</h2> 210 211 <p>This is the final piece of the puzzle. Here’s the budget report command:</p> 212 213 <div class="highlighter-rouge"><pre class="highlight"><code>ledger --empty -S -T -f ledger.dat bal ^assets:budget 214 </code></pre> 215 </div> 216 217 <p>If we have the following transactions:</p> 218 219 <div class="highlighter-rouge"><pre class="highlight"><code>2018/06/12 Groceries store 220 Expenses:Food 123.00 EUR 221 Assets:Bank:Checking 222 223 2018/06/12 Landlord 224 Expenses:Rent 600.00 EUR 225 Assets:Bank:Checking 226 227 2018/06/12 Internet provider 228 Expenses:Utilities:Internet 40.00 EUR 229 Assets:Bank:Checking 230 </code></pre> 231 </div> 232 233 <p>Here’s what the report looks like:</p> 234 235 <div class="highlighter-rouge"><pre class="highlight"><code> 837.00 EUR Assets:Budget 236 560.00 EUR Utilities 237 277.00 EUR Food 238 0 Rent 239 0 Unbudgeted 240 -------------------- 241 837.00 EUR 242 </code></pre> 243 </div> 244 245 <h1 id="conclusion">Conclusion</h1> 246 247 <p>Ledger is amazingly powerful, and provides a great framework for YNAB-like 248 budgeting. In a future post I’ll explain how I automatically import my bank 249 transactions using a mix of <code class="highlighter-rouge">ledger-autosync</code> and <code class="highlighter-rouge">weboob</code>.</p> 250 251 </div> 252 253 254 255 256 <div id="disqus_thread"></div> 257 <script> 258 /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ 259 var disqus_shortname = 'emacs-cafe'; 260 261 /* * * DON'T EDIT BELOW THIS LINE * * */ 262 (function() { 263 var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; 264 dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js'; 265 (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); 266 })(); 267 </script> 268 <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript> 269 270 271 272 </article> 273 274 </div> 275 </main> 276 277 <footer class="site-footer"> 278 279 <div class="wrapper"> 280 281 <h2 class="footer-heading">Emacs café</h2> 282 283 <div class="footer-col-wrapper"> 284 <div class="footer-col footer-col-1"> 285 <ul class="contact-list"> 286 <li> 287 288 Emacs café 289 290 </li> 291 292 <li><a href="mailto:nicolas@petton.fr">nicolas@petton.fr</a></li> 293 294 </ul> 295 </div> 296 297 <div class="footer-col footer-col-2"> 298 <ul class="social-media-list"> 299 300 <li> 301 <a href="https://github.com/NicolasPetton"><span class="icon icon--github"><svg viewBox="0 0 16 16" width="16px" height="16px"><path fill="#828282" d="M7.999,0.431c-4.285,0-7.76,3.474-7.76,7.761 c0,3.428,2.223,6.337,5.307,7.363c0.388,0.071,0.53-0.168,0.53-0.374c0-0.184-0.007-0.672-0.01-1.32 c-2.159,0.469-2.614-1.04-2.614-1.04c-0.353-0.896-0.862-1.135-0.862-1.135c-0.705-0.481,0.053-0.472,0.053-0.472 c0.779,0.055,1.189,0.8,1.189,0.8c0.692,1.186,1.816,0.843,2.258,0.645c0.071-0.502,0.271-0.843,0.493-1.037 C4.86,11.425,3.049,10.76,3.049,7.786c0-0.847,0.302-1.54,0.799-2.082C3.768,5.507,3.501,4.718,3.924,3.65 c0,0,0.652-0.209,2.134,0.796C6.677,4.273,7.34,4.187,8,4.184c0.659,0.003,1.323,0.089,1.943,0.261 c1.482-1.004,2.132-0.796,2.132-0.796c0.423,1.068,0.157,1.857,0.077,2.054c0.497,0.542,0.798,1.235,0.798,2.082 c0,2.981-1.814,3.637-3.543,3.829c0.279,0.24,0.527,0.713,0.527,1.437c0,1.037-0.01,1.874-0.01,2.129 c0,0.208,0.14,0.449,0.534,0.373c3.081-1.028,5.302-3.935,5.302-7.362C15.76,3.906,12.285,0.431,7.999,0.431z"/></svg> 302 </span><span class="username">NicolasPetton</span></a> 303 304 </li> 305 306 307 308 <li> 309 <a href="https://twitter.com/NicolasPetton"><span class="icon icon--twitter"><svg viewBox="0 0 16 16" width="16px" height="16px"><path fill="#828282" d="M15.969,3.058c-0.586,0.26-1.217,0.436-1.878,0.515c0.675-0.405,1.194-1.045,1.438-1.809c-0.632,0.375-1.332,0.647-2.076,0.793c-0.596-0.636-1.446-1.033-2.387-1.033c-1.806,0-3.27,1.464-3.27,3.27 c0,0.256,0.029,0.506,0.085,0.745C5.163,5.404,2.753,4.102,1.14,2.124C0.859,2.607,0.698,3.168,0.698,3.767 c0,1.134,0.577,2.135,1.455,2.722C1.616,6.472,1.112,6.325,0.671,6.08c0,0.014,0,0.027,0,0.041c0,1.584,1.127,2.906,2.623,3.206 C3.02,9.402,2.731,9.442,2.433,9.442c-0.211,0-0.416-0.021-0.615-0.059c0.416,1.299,1.624,2.245,3.055,2.271 c-1.119,0.877-2.529,1.4-4.061,1.4c-0.264,0-0.524-0.015-0.78-0.046c1.447,0.928,3.166,1.469,5.013,1.469 c6.015,0,9.304-4.983,9.304-9.304c0-0.142-0.003-0.283-0.009-0.423C14.976,4.29,15.531,3.714,15.969,3.058z"/></svg> 310 </span><span class="username">NicolasPetton</span></a> 311 312 </li> 313 314 </ul> 315 </div> 316 317 <div class="footer-col footer-col-3"> 318 <p>A blog about Emacs, mostly focused on JavaScript development, by Nicolas Petton. 319 </p> 320 </div> 321 </div> 322 323 </div> 324 325 </footer> 326 327 328 </body> 329 330 </html>