You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
14 KiB

3 years ago
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <title>Using Ledger for YNAB-like envelope budgeting</title>
  8. <meta name="description" content="Bye bye Elbank">
  9. <link rel="shortcut icon" type="image/png" href="/favicon.png"/>
  10. <link href="https://fonts.googleapis.com/css?family=Fira+Mono|Gentium+Book+Basic|Lato" rel="stylesheet">
  11. <link rel="stylesheet" href="/assets/main.css">
  12. <link rel="stylesheet" href="/css/cafe.css">
  13. <link rel="canonical" href="https://emacs.cafe/ledger/emacs/ynab/budgeting/2018/06/12/elbank-ynab.html">
  14. <link rel="alternate" type="application/rss+xml" title="Emacs café" href="/feed.xml">
  15. </head>
  16. <body>
  17. <header class="site-header" role="banner">
  18. <div class="wrapper">
  19. <a class="site-title" href="/"><img src="/img/emacscafe.png"/>Emacs café</a>
  20. <nav class="site-nav">
  21. <input type="checkbox" id="nav-trigger" class="nav-trigger" />
  22. <label for="nav-trigger">
  23. <span class="menu-icon">
  24. <svg viewBox="0 0 18 15" width="18px" height="15px">
  25. <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"/>
  26. <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"/>
  27. <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"/>
  28. </svg>
  29. </span>
  30. </label>
  31. <div class="trigger">
  32. <a class="page-link" href="/about/">About Emacs café</a>
  33. </div>
  34. </nav>
  35. </div>
  36. </header>
  37. <main class="page-content" aria-label="Content">
  38. <div class="wrapper">
  39. <article class="post" itemscope itemtype="http://schema.org/BlogPosting">
  40. <header class="post-header">
  41. <h1 class="post-title" itemprop="name headline">Using Ledger for YNAB-like envelope budgeting</h1>
  42. <p class="post-meta">
  43. <time datetime="2018-06-12T21:20:00+02:00" itemprop="datePublished">
  44. Jun 12, 2018
  45. </time>
  46. <span itemprop="author" itemscope itemtype="http://schema.org/Person"><span itemprop="name">Nicolas Petton</span></span>
  47. </p>
  48. </header>
  49. <div class="post-content" itemprop="articleBody">
  50. <h1 id="bye-bye-elbank">Bye bye Elbank</h1>
  51. <p>I have to start this post with this: I will not be actively maintaining
  52. <a href="https://github.com/NicolasPetton/elbank">Elbank</a> anymore, simply because I
  53. switched back to <a href="https://www.ledger-cli.org/">Ledger</a>. If someone wants to
  54. take over, please contact me!</p>
  55. <p>The main reason for switching is budgeting. While Elbank was a cool experiment,
  56. it is not an accounting software, and inherently lacks support for powerful
  57. budgeting.</p>
  58. <p>When I started working on Elbank as a replacement for Ledger, I was looking for
  59. a reporting tool within Emacs that would fetch bank transactions automatically,
  60. so I wouldn’t have to enter transactions by hand (this is a seriously tedious
  61. task, and I grew tired of doing it after roughly two years, and finally gave up).</p>
  62. <p>Since then, I learned about ledger-autosync and boobank, which I use to sync my
  63. bank statements with Ledger (more about that in another post).</p>
  64. <h1 id="ynabs-way-of-budgeting">YNAB’s way of budgeting</h1>
  65. <p>I only came across <a href="https://ynab.com">YNAB</a> recently. While I won’t use their
  66. software (being a non-free web application, and, you know… there’s no <code class="highlighter-rouge">M-x
  67. ynab</code>), I think that the principles behind it are really appealing for personal
  68. budgeting. I encourage you to <a href="https://www.youneedabudget.com/method/">read more about
  69. it</a> (or grab a <a href="https://www.youneedabudget.com/book-order-now/">copy of the
  70. book</a>, it’s great), but here’s
  71. the idea.</p>
  72. <ol>
  73. <li>
  74. <p><strong>Budget every euro</strong>: Quite simple once you get it. Every single Euro you have
  75. should be in a budget envelope. You should assign a job to every Euro you
  76. earn (that’s called
  77. <a href="https://en.wikipedia.org/wiki/Zero-based_budgeting">zero-based</a>, <a href="https://en.wikipedia.org/wiki/Envelope_system">envelope
  78. system</a>).</p>
  79. </li>
  80. <li>
  81. <p><strong>Embrace your true expenses</strong>: Plan for larger and less frequent expenses, so
  82. when a yearly bill arrives, or your car breaks down, you’ll be covered.</p>
  83. </li>
  84. <li>
  85. <p><strong>Roll with the punches</strong>: Address overspending as it happens by taking money
  86. overspent from another envelope. As long as you keep budgeting, you’re
  87. succeeding.</p>
  88. </li>
  89. <li>
  90. <p><strong>Age your money</strong>: Spend less than you earn, so your money stays in the bank
  91. account longer. As you do that, the age of your money will grow, and once
  92. you reach the goal of spending money that is at least one month old, you
  93. won’t worry about that next bill.</p>
  94. </li>
  95. </ol>
  96. <h1 id="implementation-in-ledger">Implementation in Ledger</h1>
  97. <p>I assume that you are familiar with Ledger, but if not I recommend reading its
  98. great
  99. <a href="https://www.ledger-cli.org/3.0/doc/ledger3.html#Introduction-to-Ledger">introduction</a>
  100. and <a href="https://www.ledger-cli.org/3.0/doc/ledger3.html#Ledger-Tutorial">tutorial</a>.</p>
  101. <p>The implementation in Ledger uses plain double-entry accounting. I took most of
  102. it from
  103. <a href="http://sachachua.com/blog/2014/11/keeping-financial-score-ledger/">Sacha</a>, with
  104. some minor differences.</p>
  105. <h2 id="budgeting-new-money">Budgeting new money</h2>
  106. <p>After each income transaction, I budget the new money:</p>
  107. <div class="highlighter-rouge"><pre class="highlight"><code>2018-06-12 Employer
  108. Assets:Bank:Checking 1600.00 EUR
  109. Income:Salary -1600.00 EUR
  110. 2018-06-12 Budget
  111. [Assets:Budget:Food] 400.00 EUR
  112. [Assets:Budget:Rent] 600.00 EUR
  113. [Assets:Budget:Utilities] 600.00 EUR
  114. [Equity:Budget] -1600.00 EUR
  115. </code></pre>
  116. </div>
  117. <p>Did you notice the square brackets around the accounts of the budget
  118. transaction? It’s a feature Ledger calls <a href="https://www.ledger-cli.org/3.0/doc/ledger3.html#Virtual-postings">virtual
  119. postings</a>. These
  120. postings are not considered real, and won’t be present in any report that uses
  121. the <code class="highlighter-rouge">--real</code> flag. This is exactly what we want, since it’s a budget allocation
  122. and not a “real” transaction. Therefore we’ll use the <code class="highlighter-rouge">--real</code> flag for all
  123. reports except for our budget report.</p>
  124. <h2 id="automatically-crediting-budget-accounts-when-spending-money">Automatically crediting budget accounts when spending money</h2>
  125. <p>Next, we need to credit the budget accounts each time we spend money. Ledger
  126. has another neat feature called <a href="https://www.ledger-cli.org/3.0/doc/ledger3.html#Automated-Transactions">automated
  127. transactions</a>
  128. for this:</p>
  129. <div class="highlighter-rouge"><pre class="highlight"><code>= /Expenses/
  130. [Assets:Budget:Unbudgeted] -1.0
  131. [Equity:Budget] 1.0
  132. = /Expenses:Food/
  133. [Assets:Budget:Food] -1.0
  134. [Assets:Budget:Unbudgeted] 1.0
  135. = /Expenses:Rent/
  136. [Assets:Budget:Rent] -1.0
  137. [Assets:Budget:Unbudgeted] 1.0
  138. = /Expenses:Utilities/
  139. [Assets:Budget:Utilities] -1.0
  140. [Assets:Budget:Unbudgeted] 1.0
  141. </code></pre>
  142. </div>
  143. <p>Every expense is taken out of the <code class="highlighter-rouge">Assets:Budget:Unbudgeted</code> account by default.</p>
  144. <p>This forces me to budget properly, as <code class="highlighter-rouge">Assets:Budget:Unbudgeted</code> should always
  145. be 0 (if it is not the case I immediately know that there is something wrong
  146. going on).</p>
  147. <p>All other automatic transactions take money out of the
  148. <code class="highlighter-rouge">Assets:Budget:Unbudgeted</code> account instead of <code class="highlighter-rouge">Equity:Budget</code> account.</p>
  149. <h2 id="a-budget-report">A Budget report</h2>
  150. <p>This is the final piece of the puzzle. Here’s the budget report command:</p>
  151. <div class="highlighter-rouge"><pre class="highlight"><code>ledger --empty -S -T -f ledger.dat bal ^assets:budget
  152. </code></pre>
  153. </div>
  154. <p>If we have the following transactions:</p>
  155. <div class="highlighter-rouge"><pre class="highlight"><code>2018/06/12 Groceries store
  156. Expenses:Food 123.00 EUR
  157. Assets:Bank:Checking
  158. 2018/06/12 Landlord
  159. Expenses:Rent 600.00 EUR
  160. Assets:Bank:Checking
  161. 2018/06/12 Internet provider
  162. Expenses:Utilities:Internet 40.00 EUR
  163. Assets:Bank:Checking
  164. </code></pre>
  165. </div>
  166. <p>Here’s what the report looks like:</p>
  167. <div class="highlighter-rouge"><pre class="highlight"><code> 837.00 EUR Assets:Budget
  168. 560.00 EUR Utilities
  169. 277.00 EUR Food
  170. 0 Rent
  171. 0 Unbudgeted
  172. --------------------
  173. 837.00 EUR
  174. </code></pre>
  175. </div>
  176. <h1 id="conclusion">Conclusion</h1>
  177. <p>Ledger is amazingly powerful, and provides a great framework for YNAB-like
  178. budgeting. In a future post I’ll explain how I automatically import my bank
  179. transactions using a mix of <code class="highlighter-rouge">ledger-autosync</code> and <code class="highlighter-rouge">weboob</code>.</p>
  180. </div>
  181. <div id="disqus_thread"></div>
  182. <script>
  183. /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
  184. var disqus_shortname = 'emacs-cafe';
  185. /* * * DON'T EDIT BELOW THIS LINE * * */
  186. (function() {
  187. var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
  188. dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
  189. (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
  190. })();
  191. </script>
  192. <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
  193. </article>
  194. </div>
  195. </main>
  196. <footer class="site-footer">
  197. <div class="wrapper">
  198. <h2 class="footer-heading">Emacs café</h2>
  199. <div class="footer-col-wrapper">
  200. <div class="footer-col footer-col-1">
  201. <ul class="contact-list">
  202. <li>
  203. Emacs café
  204. </li>
  205. <li><a href="mailto:nicolas@petton.fr">nicolas@petton.fr</a></li>
  206. </ul>
  207. </div>
  208. <div class="footer-col footer-col-2">
  209. <ul class="social-media-list">
  210. <li>
  211. <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>
  212. </span><span class="username">NicolasPetton</span></a>
  213. </li>
  214. <li>
  215. <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>
  216. </span><span class="username">NicolasPetton</span></a>
  217. </li>
  218. </ul>
  219. </div>
  220. <div class="footer-col footer-col-3">
  221. <p>A blog about Emacs, mostly focused on JavaScript development, by Nicolas Petton.
  222. </p>
  223. </div>
  224. </div>
  225. </div>
  226. </footer>
  227. </body>
  228. </html>