;update manuals

This commit is contained in:
Simon Michael 2020-11-19 09:19:20 -08:00
parent 0295be5553
commit b6c667c388
3 changed files with 826 additions and 93 deletions

View File

@ -4469,14 +4469,295 @@ At a minimum, you need to supply a query (which could be just an account
name) to select your investments with \f[C]--inv\f[R], and another query
to identify your profit and loss transactions with \f[C]--pnl\f[R].
.PP
It will compute and display the internalized rate of return (IRR) and
time-weighted rate of return (TWR) for your investments for the time
period requested.
This command will compute and display the internalized rate of return
(IRR) and time-weighted rate of return (TWR) for your investments for
the time period requested.
Both rates of return are annualized before display, regardless of the
length of reporting interval.
.PP
An example:
Note, in some cases this report can fail, for these reasons:
.IP \[bu] 2
Error (NotBracketed): No solution for Internal Rate of Return (IRR).
Possible causes: IRR is huge (>1000000%), balance of investment becomes
negative at some point in time.
.IP \[bu] 2
Error (SearchFailed): Failed to find solution for Internal Rate of
Return (IRR).
Either search does not converge to a solution, or converges too slowly.
.PP
Examples:
.IP \[bu] 2
Using roi to report unrealised gains:
https://github.com/simonmichael/hledger/blob/master/examples/roi-unrealised.ledger
.PP
More background:
.PP
\[dq]ROI\[dq] stands for \[dq]return on investment\[dq].
Traditionally this was computed as a difference between current value of
investment and its initial value, expressed in percentage of the initial
value.
.PP
However, this approach is only practical in simple cases, where
investments receives no in-flows or out-flows of money, and where rate
of growth is fixed over time.
For more complex scenarios you need different ways to compute rate of
return, and this command implements two of them: IRR and TWR.
.PP
Internal rate of return, or \[dq]IRR\[dq] (also called
\[dq]money-weighted rate of return\[dq]) takes into account effects of
in-flows and out-flows.
Naively, if you are withdrawing from your investment, your future gains
would be smaller (in absolute numbers), and will be a smaller percentage
of your initial investment, and if you are adding to your investment,
you will receive bigger absolute gains (but probably at the same rate of
return).
IRR is a way to compute rate of return for each period between in-flow
or out-flow of money, and then combine them in a way that gives you an
annual rate of return that investment is expected to generate.
.PP
As mentioned before, in-flows and out-flows would be any cash that you
personally put in or withdraw, and for the \[dq]roi\[dq] command, these
are transactions that involve account(s) matching \f[C]--inv\f[R]
argument and NOT involve account(s) matching \f[C]--pnl\f[R] argument.
.PP
Presumably, you will also record changes in the value of your
investment, and balance them against \[dq]profit and loss\[dq] (or
\[dq]unrealized gains\[dq]) account.
Note that in order for IRR to compute the precise effect of your
in-flows and out-flows on the rate of return, you will need to record
the value of your investement on or close to the days when in- or
out-flows occur.
.PP
Implementation of IRR in hledger should match the \f[C]XIRR\f[R] formula
in Excel.
.PP
Second way to compute rate of return that \f[C]roi\f[R] command
implements is called \[dq]time-weighted rate of return\[dq] or
\[dq]TWR\[dq].
Like IRR, it will also break the history of your investment into periods
between in-flows and out-flows to compute rate of return per each period
and then a compound rate of return.
However, internal workings of TWR are quite different.
.PP
In technical terms, IRR uses the same approach as computation of net
present value, and tries to find a discount rate that makes net present
value of all the cash flows of your investment to add up to zero.
This could be hard to wrap your head around, especially if you
haven\[aq]t done discounted cash flow analysis before.
.PP
TWR represents your investment as an imaginary \[dq]unit fund\[dq] where
in-flows/ out-flows lead to buying or selling \[dq]units\[dq] of your
investment and changes in its value change the value of \[dq]investment
unit\[dq].
Change in \[dq]unit price\[dq] over the reporting period gives you rate
of return of your investment.
.PP
References: * Explanation of rate of return * Explanation of IRR *
Explanation of TWR * Examples of computing IRR and TWR and discussion of
the limitations of both metrics
.PP
More examples:
.PP
Lets say that we found an investment in Snake Oil that is proising to
give us 10% annually:
.IP
.nf
\f[C]
2019-01-01 Investing in Snake Oil
assets:cash -$100
investment:snake oil
2019-12-24 Recording the growth of Snake Oil
investment:snake oil = $110
equity:unrealized gains
\f[R]
.fi
.PP
For now, basic computation of the rate of return, as well as IRR and
TWR, gives us the expected 10%:
.IP
.nf
\f[C]
$ hledger roi -Y --inv investment --pnl \[dq]unrealized\[dq]
+---++------------+------------++---------------+----------+-------------+-----++--------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+=====++========+========+
| 1 || 2019-01-01 | 2019-12-31 || 0 | 100 | 110 | 10 || 10.00% | 10.00% |
+---++------------+------------++---------------+----------+-------------+-----++--------+--------+
\f[R]
.fi
.PP
However, lets say that shorty after investing in the Snake Oil we
started to have second thoughs, so we prompty withdrew $90, leaving only
$10 in.
Before Christmas, though, we started to get the \[dq]fear of mission
out\[dq], so we put the $90 back in.
So for most of the year, our investment was just $10 dollars, and it
gave us just $1 in growth:
.IP
.nf
\f[C]
2019-01-01 Investing in Snake Oil
assets:cash -$100
investment:snake oil
2019-01-02 Buyers remorse
assets:cash $90
investment:snake oil
2019-12-30 Fear of missing out
assets:cash -$90
investment:snake oil
2019-12-31 Recording the growth of Snake Oil
investment:snake oil = $101
equity:unrealized gains
\f[R]
.fi
.PP
Now IRR and TWR are drastically different:
.IP
.nf
\f[C]
$ hledger roi -Y --inv investment --pnl \[dq]unrealized\[dq]
+---++------------+------------++---------------+----------+-------------+-----++-------+-------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+=====++=======+=======+
| 1 || 2019-01-01 | 2019-12-31 || 0 | 100 | 101 | 1 || 9.32% | 1.00% |
+---++------------+------------++---------------+----------+-------------+-----++-------+-------+
\f[R]
.fi
.PP
Here, IRR tells us that we made close to 10% on the $10 dollars that we
had in the account most of the time.
And TWR is ...
just 1%?
Why?
.PP
Based on the transactions in our journal, TWR \[dq]think\[dq] that we
are buying back $90 worst of Snake Oil at the same price that it had at
the beginning of they year, and then after that our $100 investment gets
$1 increase in value, or 1% of $100.
Let\[aq]s take a closer look at what is happening here by asking for
quarterly reports instead of annual:
.IP
.nf
\f[C]
$ hledger roi -Q --inv investment --pnl \[dq]unrealized\[dq]
+---++------------+------------++---------------+----------+-------------+-----++--------+-------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+=====++========+=======+
| 1 || 2019-01-01 | 2019-03-31 || 0 | 10 | 10 | 0 || 0.00% | 0.00% |
| 2 || 2019-04-01 | 2019-06-30 || 10 | 0 | 10 | 0 || 0.00% | 0.00% |
| 3 || 2019-07-01 | 2019-09-30 || 10 | 0 | 10 | 0 || 0.00% | 0.00% |
| 4 || 2019-10-01 | 2019-12-31 || 10 | 90 | 101 | 1 || 37.80% | 4.03% |
+---++------------+------------++---------------+----------+-------------+-----++--------+-------+
\f[R]
.fi
.PP
Now both IRR and TWR are thrown off by the fact that all of the growth
for our investment happens in Q4 2019.
This happes because IRR computation is still yielding 9.32% and TWR is
still 1%, but this time these are rates for three month period instead
of twelve, so in order to get an annual rate they should be multiplied
by four!
.PP
Let\[aq]s try to keep a better record of how Snake Oil grew in value:
.IP
.nf
\f[C]
2019-01-01 Investing in Snake Oil
assets:cash -$100
investment:snake oil
2019-01-02 Buyers remorse
assets:cash $90
investment:snake oil
2019-02-28 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
2019-06-30 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
2019-09-30 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
2019-12-30 Fear of missing out
assets:cash -$90
investment:snake oil
2019-12-31 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
\f[R]
.fi
.PP
Would our quartery report look better now?
Almost:
.IP
.nf
\f[C]
$ hledger roi -Q --inv investment --pnl \[dq]unrealized\[dq]
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+======++========+========+
| 1 || 2019-01-01 | 2019-03-31 || 0 | 10 | 10.25 | 0.25 || 9.53% | 10.53% |
| 2 || 2019-04-01 | 2019-06-30 || 10.25 | 0 | 10.50 | 0.25 || 10.15% | 10.15% |
| 3 || 2019-07-01 | 2019-09-30 || 10.50 | 0 | 10.75 | 0.25 || 9.79% | 9.78% |
| 4 || 2019-10-01 | 2019-12-31 || 10.75 | 90 | 101.00 | 0.25 || 8.05% | 1.00% |
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
\f[R]
.fi
.PP
Something is still wrong with TWR computation for Q4, and if you have
been paying attention you know what it is already: big $90 buy-back is
recorded prior to the only transaction that captures the change of value
of Snake Oil that happened in this time period.
Lets combine transactions from 30th and 31st of Dec into one:
.IP
.nf
\f[C]
2019-12-30 Fear of missing out and growth of Snake Oil
assets:cash -$90
investment:snake oil
equity:unrealized gains -$0.25
\f[R]
.fi
.PP
Now growth of investment properly affects its price at the time of
buy-back:
.IP
.nf
\f[C]
$ hledger roi -Q --inv investment --pnl \[dq]unrealized\[dq]
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+======++========+========+
| 1 || 2019-01-01 | 2019-03-31 || 0 | 10 | 10.25 | 0.25 || 9.53% | 10.53% |
| 2 || 2019-04-01 | 2019-06-30 || 10.25 | 0 | 10.50 | 0.25 || 10.15% | 10.15% |
| 3 || 2019-07-01 | 2019-09-30 || 10.50 | 0 | 10.75 | 0.25 || 9.79% | 9.78% |
| 4 || 2019-10-01 | 2019-12-31 || 10.75 | 90 | 101.00 | 0.25 || 8.05% | 9.57% |
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
\f[R]
.fi
.PP
And for annual report, TWR now reports the exact profitability of our
investment:
.IP
.nf
\f[C]
$ hledger roi -Y --inv investment --pnl \[dq]unrealized\[dq]
+---++------------+------------++---------------+----------+-------------+------++-------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+======++=======+========+
| 1 || 2019-01-01 | 2019-12-31 || 0 | 100 | 101.00 | 1.00 || 9.32% | 10.00% |
+---++------------+------------++---------------+----------+-------------+------++-------+--------+
\f[R]
.fi
.SS stats
.PP
stats

View File

@ -3798,13 +3798,238 @@ your investments or withdrawals.
account name) to select your investments with '--inv', and another query
to identify your profit and loss transactions with '--pnl'.
It will compute and display the internalized rate of return (IRR) and
time-weighted rate of return (TWR) for your investments for the time
period requested. Both rates of return are annualized before display,
regardless of the length of reporting interval.
This command will compute and display the internalized rate of return
(IRR) and time-weighted rate of return (TWR) for your investments for
the time period requested. Both rates of return are annualized before
display, regardless of the length of reporting interval.
An example:
https://github.com/simonmichael/hledger/blob/master/examples/roi-unrealised.ledger
Note, in some cases this report can fail, for these reasons:
* Error (NotBracketed): No solution for Internal Rate of Return
(IRR). Possible causes: IRR is huge (>1000000%), balance of
investment becomes negative at some point in time.
* Error (SearchFailed): Failed to find solution for Internal Rate of
Return (IRR). Either search does not converge to a solution, or
converges too slowly.
Examples:
* Using roi to report unrealised gains:
https://github.com/simonmichael/hledger/blob/master/examples/roi-unrealised.ledger
More background:
"ROI" stands for "return on investment". Traditionally this was
computed as a difference between current value of investment and its
initial value, expressed in percentage of the initial value.
However, this approach is only practical in simple cases, where
investments receives no in-flows or out-flows of money, and where rate
of growth is fixed over time. For more complex scenarios you need
different ways to compute rate of return, and this command implements
two of them: IRR and TWR.
Internal rate of return, or "IRR" (also called "money-weighted rate
of return") takes into account effects of in-flows and out-flows.
Naively, if you are withdrawing from your investment, your future gains
would be smaller (in absolute numbers), and will be a smaller percentage
of your initial investment, and if you are adding to your investment,
you will receive bigger absolute gains (but probably at the same rate of
return). IRR is a way to compute rate of return for each period between
in-flow or out-flow of money, and then combine them in a way that gives
you an annual rate of return that investment is expected to generate.
As mentioned before, in-flows and out-flows would be any cash that
you personally put in or withdraw, and for the "roi" command, these are
transactions that involve account(s) matching '--inv' argument and NOT
involve account(s) matching '--pnl' argument.
Presumably, you will also record changes in the value of your
investment, and balance them against "profit and loss" (or "unrealized
gains") account. Note that in order for IRR to compute the precise
effect of your in-flows and out-flows on the rate of return, you will
need to record the value of your investement on or close to the days
when in- or out-flows occur.
Implementation of IRR in hledger should match the 'XIRR' formula in
Excel.
Second way to compute rate of return that 'roi' command implements is
called "time-weighted rate of return" or "TWR". Like IRR, it will also
break the history of your investment into periods between in-flows and
out-flows to compute rate of return per each period and then a compound
rate of return. However, internal workings of TWR are quite different.
In technical terms, IRR uses the same approach as computation of net
present value, and tries to find a discount rate that makes net present
value of all the cash flows of your investment to add up to zero. This
could be hard to wrap your head around, especially if you haven't done
discounted cash flow analysis before.
TWR represents your investment as an imaginary "unit fund" where
in-flows/ out-flows lead to buying or selling "units" of your investment
and changes in its value change the value of "investment unit". Change
in "unit price" over the reporting period gives you rate of return of
your investment.
References: * Explanation of rate of return * Explanation of IRR *
Explanation of TWR * Examples of computing IRR and TWR and discussion of
the limitations of both metrics
More examples:
Lets say that we found an investment in Snake Oil that is proising to
give us 10% annually:
2019-01-01 Investing in Snake Oil
assets:cash -$100
investment:snake oil
2019-12-24 Recording the growth of Snake Oil
investment:snake oil = $110
equity:unrealized gains
For now, basic computation of the rate of return, as well as IRR and
TWR, gives us the expected 10%:
$ hledger roi -Y --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+-----++--------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+=====++========+========+
| 1 || 2019-01-01 | 2019-12-31 || 0 | 100 | 110 | 10 || 10.00% | 10.00% |
+---++------------+------------++---------------+----------+-------------+-----++--------+--------+
However, lets say that shorty after investing in the Snake Oil we
started to have second thoughs, so we prompty withdrew $90, leaving only
$10 in. Before Christmas, though, we started to get the "fear of
mission out", so we put the $90 back in. So for most of the year, our
investment was just $10 dollars, and it gave us just $1 in growth:
2019-01-01 Investing in Snake Oil
assets:cash -$100
investment:snake oil
2019-01-02 Buyers remorse
assets:cash $90
investment:snake oil
2019-12-30 Fear of missing out
assets:cash -$90
investment:snake oil
2019-12-31 Recording the growth of Snake Oil
investment:snake oil = $101
equity:unrealized gains
Now IRR and TWR are drastically different:
$ hledger roi -Y --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+-----++-------+-------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+=====++=======+=======+
| 1 || 2019-01-01 | 2019-12-31 || 0 | 100 | 101 | 1 || 9.32% | 1.00% |
+---++------------+------------++---------------+----------+-------------+-----++-------+-------+
Here, IRR tells us that we made close to 10% on the $10 dollars that
we had in the account most of the time. And TWR is ... just 1%? Why?
Based on the transactions in our journal, TWR "think" that we are
buying back $90 worst of Snake Oil at the same price that it had at the
beginning of they year, and then after that our $100 investment gets $1
increase in value, or 1% of $100. Let's take a closer look at what is
happening here by asking for quarterly reports instead of annual:
$ hledger roi -Q --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+-----++--------+-------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+=====++========+=======+
| 1 || 2019-01-01 | 2019-03-31 || 0 | 10 | 10 | 0 || 0.00% | 0.00% |
| 2 || 2019-04-01 | 2019-06-30 || 10 | 0 | 10 | 0 || 0.00% | 0.00% |
| 3 || 2019-07-01 | 2019-09-30 || 10 | 0 | 10 | 0 || 0.00% | 0.00% |
| 4 || 2019-10-01 | 2019-12-31 || 10 | 90 | 101 | 1 || 37.80% | 4.03% |
+---++------------+------------++---------------+----------+-------------+-----++--------+-------+
Now both IRR and TWR are thrown off by the fact that all of the
growth for our investment happens in Q4 2019. This happes because IRR
computation is still yielding 9.32% and TWR is still 1%, but this time
these are rates for three month period instead of twelve, so in order to
get an annual rate they should be multiplied by four!
Let's try to keep a better record of how Snake Oil grew in value:
2019-01-01 Investing in Snake Oil
assets:cash -$100
investment:snake oil
2019-01-02 Buyers remorse
assets:cash $90
investment:snake oil
2019-02-28 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
2019-06-30 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
2019-09-30 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
2019-12-30 Fear of missing out
assets:cash -$90
investment:snake oil
2019-12-31 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
Would our quartery report look better now? Almost:
$ hledger roi -Q --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+======++========+========+
| 1 || 2019-01-01 | 2019-03-31 || 0 | 10 | 10.25 | 0.25 || 9.53% | 10.53% |
| 2 || 2019-04-01 | 2019-06-30 || 10.25 | 0 | 10.50 | 0.25 || 10.15% | 10.15% |
| 3 || 2019-07-01 | 2019-09-30 || 10.50 | 0 | 10.75 | 0.25 || 9.79% | 9.78% |
| 4 || 2019-10-01 | 2019-12-31 || 10.75 | 90 | 101.00 | 0.25 || 8.05% | 1.00% |
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
Something is still wrong with TWR computation for Q4, and if you have
been paying attention you know what it is already: big $90 buy-back is
recorded prior to the only transaction that captures the change of value
of Snake Oil that happened in this time period. Lets combine
transactions from 30th and 31st of Dec into one:
2019-12-30 Fear of missing out and growth of Snake Oil
assets:cash -$90
investment:snake oil
equity:unrealized gains -$0.25
Now growth of investment properly affects its price at the time of
buy-back:
$ hledger roi -Q --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+======++========+========+
| 1 || 2019-01-01 | 2019-03-31 || 0 | 10 | 10.25 | 0.25 || 9.53% | 10.53% |
| 2 || 2019-04-01 | 2019-06-30 || 10.25 | 0 | 10.50 | 0.25 || 10.15% | 10.15% |
| 3 || 2019-07-01 | 2019-09-30 || 10.50 | 0 | 10.75 | 0.25 || 9.79% | 9.78% |
| 4 || 2019-10-01 | 2019-12-31 || 10.75 | 90 | 101.00 | 0.25 || 8.05% | 9.57% |
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
And for annual report, TWR now reports the exact profitability of our
investment:
$ hledger roi -Y --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+------++-------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+======++=======+========+
| 1 || 2019-01-01 | 2019-12-31 || 0 | 100 | 101.00 | 1.00 || 9.32% | 10.00% |
+---++------------+------------++---------------+----------+-------------+------++-------+--------+

File: hledger.info, Node: stats, Next: tags, Prev: roi, Up: COMMANDS
@ -4290,30 +4515,30 @@ Node: rewrite vs print --auto133861
Ref: #rewrite-vs.-print---auto134040
Node: roi134596
Ref: #roi134694
Node: stats135805
Ref: #stats135904
Node: tags136692
Ref: #tags136790
Node: test137309
Ref: #test137417
Node: Add-on commands138164
Ref: #add-on-commands138281
Node: ui139624
Ref: #ui139712
Node: web139766
Ref: #web139869
Node: iadd139985
Ref: #iadd140096
Node: interest140178
Ref: #interest140285
Node: ENVIRONMENT140525
Ref: #environment140637
Node: FILES141622
Ref: #files-1141725
Node: LIMITATIONS141938
Ref: #limitations142057
Node: TROUBLESHOOTING142799
Ref: #troubleshooting142912
Node: stats146904
Ref: #stats147003
Node: tags147791
Ref: #tags147889
Node: test148408
Ref: #test148516
Node: Add-on commands149263
Ref: #add-on-commands149380
Node: ui150723
Ref: #ui150811
Node: web150865
Ref: #web150968
Node: iadd151084
Ref: #iadd151195
Node: interest151277
Ref: #interest151384
Node: ENVIRONMENT151624
Ref: #environment151736
Node: FILES152721
Ref: #files-1152824
Node: LIMITATIONS153037
Ref: #limitations153156
Node: TROUBLESHOOTING153898
Ref: #troubleshooting154011

End Tag Table

View File

@ -3230,20 +3230,247 @@ COMMANDS
count name) to select your investments with --inv, and another query to
identify your profit and loss transactions with --pnl.
It will compute and display the internalized rate of return (IRR) and
time-weighted rate of return (TWR) for your investments for the time
period requested. Both rates of return are annualized before display,
regardless of the length of reporting interval.
This command will compute and display the internalized rate of return
(IRR) and time-weighted rate of return (TWR) for your investments for
the time period requested. Both rates of return are annualized before
display, regardless of the length of reporting interval.
An example: https://github.com/simonmichael/hledger/blob/master/exam-
ples/roi-unrealised.ledger
Note, in some cases this report can fail, for these reasons:
o Error (NotBracketed): No solution for Internal Rate of Return (IRR).
Possible causes: IRR is huge (>1000000%), balance of investment be-
comes negative at some point in time.
o Error (SearchFailed): Failed to find solution for Internal Rate of
Return (IRR). Either search does not converge to a solution, or con-
verges too slowly.
Examples:
o Using roi to report unrealised gains: https://github.com/simon-
michael/hledger/blob/master/examples/roi-unrealised.ledger
More background:
"ROI" stands for "return on investment". Traditionally this was com-
puted as a difference between current value of investment and its ini-
tial value, expressed in percentage of the initial value.
However, this approach is only practical in simple cases, where invest-
ments receives no in-flows or out-flows of money, and where rate of
growth is fixed over time. For more complex scenarios you need differ-
ent ways to compute rate of return, and this command implements two of
them: IRR and TWR.
Internal rate of return, or "IRR" (also called "money-weighted rate of
return") takes into account effects of in-flows and out-flows.
Naively, if you are withdrawing from your investment, your future gains
would be smaller (in absolute numbers), and will be a smaller percent-
age of your initial investment, and if you are adding to your invest-
ment, you will receive bigger absolute gains (but probably at the same
rate of return). IRR is a way to compute rate of return for each pe-
riod between in-flow or out-flow of money, and then combine them in a
way that gives you an annual rate of return that investment is expected
to generate.
As mentioned before, in-flows and out-flows would be any cash that you
personally put in or withdraw, and for the "roi" command, these are
transactions that involve account(s) matching --inv argument and NOT
involve account(s) matching --pnl argument.
Presumably, you will also record changes in the value of your invest-
ment, and balance them against "profit and loss" (or "unrealized
gains") account. Note that in order for IRR to compute the precise ef-
fect of your in-flows and out-flows on the rate of return, you will
need to record the value of your investement on or close to the days
when in- or out-flows occur.
Implementation of IRR in hledger should match the XIRR formula in Ex-
cel.
Second way to compute rate of return that roi command implements is
called "time-weighted rate of return" or "TWR". Like IRR, it will also
break the history of your investment into periods between in-flows and
out-flows to compute rate of return per each period and then a compound
rate of return. However, internal workings of TWR are quite different.
In technical terms, IRR uses the same approach as computation of net
present value, and tries to find a discount rate that makes net present
value of all the cash flows of your investment to add up to zero. This
could be hard to wrap your head around, especially if you haven't done
discounted cash flow analysis before.
TWR represents your investment as an imaginary "unit fund" where in-
flows/ out-flows lead to buying or selling "units" of your investment
and changes in its value change the value of "investment unit". Change
in "unit price" over the reporting period gives you rate of return of
your investment.
References: * Explanation of rate of return * Explanation of IRR * Ex-
planation of TWR * Examples of computing IRR and TWR and discussion of
the limitations of both metrics
More examples:
Lets say that we found an investment in Snake Oil that is proising to
give us 10% annually:
2019-01-01 Investing in Snake Oil
assets:cash -$100
investment:snake oil
2019-12-24 Recording the growth of Snake Oil
investment:snake oil = $110
equity:unrealized gains
For now, basic computation of the rate of return, as well as IRR and
TWR, gives us the expected 10%:
$ hledger roi -Y --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+-----++--------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+=====++========+========+
| 1 || 2019-01-01 | 2019-12-31 || 0 | 100 | 110 | 10 || 10.00% | 10.00% |
+---++------------+------------++---------------+----------+-------------+-----++--------+--------+
However, lets say that shorty after investing in the Snake Oil we
started to have second thoughs, so we prompty withdrew $90, leaving
only $10 in. Before Christmas, though, we started to get the "fear of
mission out", so we put the $90 back in. So for most of the year, our
investment was just $10 dollars, and it gave us just $1 in growth:
2019-01-01 Investing in Snake Oil
assets:cash -$100
investment:snake oil
2019-01-02 Buyers remorse
assets:cash $90
investment:snake oil
2019-12-30 Fear of missing out
assets:cash -$90
investment:snake oil
2019-12-31 Recording the growth of Snake Oil
investment:snake oil = $101
equity:unrealized gains
Now IRR and TWR are drastically different:
$ hledger roi -Y --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+-----++-------+-------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+=====++=======+=======+
| 1 || 2019-01-01 | 2019-12-31 || 0 | 100 | 101 | 1 || 9.32% | 1.00% |
+---++------------+------------++---------------+----------+-------------+-----++-------+-------+
Here, IRR tells us that we made close to 10% on the $10 dollars that we
had in the account most of the time. And TWR is ... just 1%? Why?
Based on the transactions in our journal, TWR "think" that we are buy-
ing back $90 worst of Snake Oil at the same price that it had at the
beginning of they year, and then after that our $100 investment gets $1
increase in value, or 1% of $100. Let's take a closer look at what is
happening here by asking for quarterly reports instead of annual:
$ hledger roi -Q --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+-----++--------+-------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+=====++========+=======+
| 1 || 2019-01-01 | 2019-03-31 || 0 | 10 | 10 | 0 || 0.00% | 0.00% |
| 2 || 2019-04-01 | 2019-06-30 || 10 | 0 | 10 | 0 || 0.00% | 0.00% |
| 3 || 2019-07-01 | 2019-09-30 || 10 | 0 | 10 | 0 || 0.00% | 0.00% |
| 4 || 2019-10-01 | 2019-12-31 || 10 | 90 | 101 | 1 || 37.80% | 4.03% |
+---++------------+------------++---------------+----------+-------------+-----++--------+-------+
Now both IRR and TWR are thrown off by the fact that all of the growth
for our investment happens in Q4 2019. This happes because IRR compu-
tation is still yielding 9.32% and TWR is still 1%, but this time these
are rates for three month period instead of twelve, so in order to get
an annual rate they should be multiplied by four!
Let's try to keep a better record of how Snake Oil grew in value:
2019-01-01 Investing in Snake Oil
assets:cash -$100
investment:snake oil
2019-01-02 Buyers remorse
assets:cash $90
investment:snake oil
2019-02-28 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
2019-06-30 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
2019-09-30 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
2019-12-30 Fear of missing out
assets:cash -$90
investment:snake oil
2019-12-31 Recording the growth of Snake Oil
investment:snake oil
equity:unrealized gains -$0.25
Would our quartery report look better now? Almost:
$ hledger roi -Q --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+======++========+========+
| 1 || 2019-01-01 | 2019-03-31 || 0 | 10 | 10.25 | 0.25 || 9.53% | 10.53% |
| 2 || 2019-04-01 | 2019-06-30 || 10.25 | 0 | 10.50 | 0.25 || 10.15% | 10.15% |
| 3 || 2019-07-01 | 2019-09-30 || 10.50 | 0 | 10.75 | 0.25 || 9.79% | 9.78% |
| 4 || 2019-10-01 | 2019-12-31 || 10.75 | 90 | 101.00 | 0.25 || 8.05% | 1.00% |
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
Something is still wrong with TWR computation for Q4, and if you have
been paying attention you know what it is already: big $90 buy-back is
recorded prior to the only transaction that captures the change of
value of Snake Oil that happened in this time period. Lets combine
transactions from 30th and 31st of Dec into one:
2019-12-30 Fear of missing out and growth of Snake Oil
assets:cash -$90
investment:snake oil
equity:unrealized gains -$0.25
Now growth of investment properly affects its price at the time of buy-
back:
$ hledger roi -Q --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+======++========+========+
| 1 || 2019-01-01 | 2019-03-31 || 0 | 10 | 10.25 | 0.25 || 9.53% | 10.53% |
| 2 || 2019-04-01 | 2019-06-30 || 10.25 | 0 | 10.50 | 0.25 || 10.15% | 10.15% |
| 3 || 2019-07-01 | 2019-09-30 || 10.50 | 0 | 10.75 | 0.25 || 9.79% | 9.78% |
| 4 || 2019-10-01 | 2019-12-31 || 10.75 | 90 | 101.00 | 0.25 || 8.05% | 9.57% |
+---++------------+------------++---------------+----------+-------------+------++--------+--------+
And for annual report, TWR now reports the exact profitability of our
investment:
$ hledger roi -Y --inv investment --pnl "unrealized"
+---++------------+------------++---------------+----------+-------------+------++-------+--------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+======++=======+========+
| 1 || 2019-01-01 | 2019-12-31 || 0 | 100 | 101.00 | 1.00 || 9.32% | 10.00% |
+---++------------+------------++---------------+----------+-------------+------++-------+--------+
stats
stats
Show some journal statistics.
The stats command displays summary information for the whole journal,
or a matched part of it. With a reporting interval, it shows a report
The stats command displays summary information for the whole journal,
or a matched part of it. With a reporting interval, it shows a report
for each report period.
Example:
@ -3261,35 +3488,35 @@ COMMANDS
Commodities : 1 ($)
Market prices : 12 ($)
This command also supports output destination and output format selec-
This command also supports output destination and output format selec-
tion.
tags
tags
List the unique tag names used in the journal. With a TAGREGEX argu-
List the unique tag names used in the journal. With a TAGREGEX argu-
ment, only tag names matching the regular expression (case insensitive)
are shown. With QUERY arguments, only transactions matching the query
are shown. With QUERY arguments, only transactions matching the query
are considered.
With the --values flag, the tags' unique values are listed instead.
With --parsed flag, all tags or values are shown in the order they are
With --parsed flag, all tags or values are shown in the order they are
parsed from the input data, including duplicates.
With -E/--empty, any blank/empty values will also be shown, otherwise
With -E/--empty, any blank/empty values will also be shown, otherwise
they are omitted.
test
test
Run built-in unit tests.
This command runs the unit tests built in to hledger and hledger-lib,
printing the results on stdout. If any test fails, the exit code will
This command runs the unit tests built in to hledger and hledger-lib,
printing the results on stdout. If any test fails, the exit code will
be non-zero.
This is mainly used by hledger developers, but you can also use it to
sanity-check the installed hledger executable on your platform. All
tests are expected to pass - if you ever see a failure, please report
This is mainly used by hledger developers, but you can also use it to
sanity-check the installed hledger executable on your platform. All
tests are expected to pass - if you ever see a failure, please report
as a bug!
This command also accepts tasty test runner options, written after a --
@ -3298,35 +3525,35 @@ COMMANDS
$ hledger test -- -pData.Amount --color=never
For help on these, see https://github.com/feuerbach/tasty#options (--
For help on these, see https://github.com/feuerbach/tasty#options (--
--help currently doesn't show them).
Add-on commands
hledger also searches for external add-on commands, and will include
hledger also searches for external add-on commands, and will include
these in the commands list. These are programs or scripts in your PATH
whose name starts with hledger- and ends with a recognised file exten-
whose name starts with hledger- and ends with a recognised file exten-
sion (currently: no extension, bat,com,exe, hs,lhs,pl,py,rb,rkt,sh).
Add-ons can be invoked like any hledger command, but there are a few
Add-ons can be invoked like any hledger command, but there are a few
things to be aware of. Eg if the hledger-web add-on is installed,
o hledger -h web shows hledger's help, while hledger web -h shows
o hledger -h web shows hledger's help, while hledger web -h shows
hledger-web's help.
o Flags specific to the add-on must have a preceding -- to hide them
from hledger. So hledger web --serve --port 9000 will be rejected;
o Flags specific to the add-on must have a preceding -- to hide them
from hledger. So hledger web --serve --port 9000 will be rejected;
you must use hledger web -- --serve --port 9000.
o You can always run add-ons directly if preferred: hledger-web --serve
--port 9000.
Add-ons are a relatively easy way to add local features or experiment
with new ideas. They can be written in any language, but haskell
scripts have a big advantage: they can use the same hledger (and
haskell) library functions that built-in commands do, for command-line
Add-ons are a relatively easy way to add local features or experiment
with new ideas. They can be written in any language, but haskell
scripts have a big advantage: they can use the same hledger (and
haskell) library functions that built-in commands do, for command-line
options, journal parsing, reporting, etc.
Two important add-ons are the hledger-ui and hledger-web user inter-
Two important add-ons are the hledger-ui and hledger-web user inter-
faces. These are maintained and released along with hledger:
ui
@ -3345,20 +3572,20 @@ COMMANDS
hledger-interest generates interest transactions for an account accord-
ing to various schemes.
A few more experimental or old add-ons can be found in hledger's bin/
A few more experimental or old add-ons can be found in hledger's bin/
directory. These are typically prototypes and not guaranteed to work.
ENVIRONMENT
LEDGER_FILE The journal file path when not specified with -f. Default:
~/.hledger.journal (on windows, perhaps C:/Users/USER/.hledger.jour-
~/.hledger.journal (on windows, perhaps C:/Users/USER/.hledger.jour-
nal).
A typical value is ~/DIR/YYYY.journal, where DIR is a version-con-
trolled finance directory and YYYY is the current year. Or ~/DIR/cur-
A typical value is ~/DIR/YYYY.journal, where DIR is a version-con-
trolled finance directory and YYYY is the current year. Or ~/DIR/cur-
rent.journal, where current.journal is a symbolic link to YYYY.journal.
On Mac computers, you can set this and other environment variables in a
more thorough way that also affects applications started from the GUI
more thorough way that also affects applications started from the GUI
(say, an Emacs dock icon). Eg on MacOS Catalina I have a ~/.MacOSX/en-
vironment.plist file containing
@ -3368,21 +3595,21 @@ ENVIRONMENT
To see the effect you may need to killall Dock, or reboot.
COLUMNS The screen width used by the register command. Default: the
COLUMNS The screen width used by the register command. Default: the
full terminal width.
NO_COLOR If this variable exists with any value, hledger will not use
ANSI color codes in terminal output. This overrides the
NO_COLOR If this variable exists with any value, hledger will not use
ANSI color codes in terminal output. This overrides the
--color/--colour option.
FILES
Reads data from one or more files in hledger journal, timeclock, time-
dot, or CSV format specified with -f, or $LEDGER_FILE, or
$HOME/.hledger.journal (on windows, perhaps
Reads data from one or more files in hledger journal, timeclock, time-
dot, or CSV format specified with -f, or $LEDGER_FILE, or
$HOME/.hledger.journal (on windows, perhaps
C:/Users/USER/.hledger.journal).
LIMITATIONS
The need to precede addon command options with -- when invoked from
The need to precede addon command options with -- when invoked from
hledger is awkward.
When input data contains non-ascii characters, a suitable system locale
@ -3398,36 +3625,36 @@ LIMITATIONS
In a Cygwin/MSYS/Mintty window, the tab key is not supported in hledger
add.
Not all of Ledger's journal file syntax is supported. See file format
Not all of Ledger's journal file syntax is supported. See file format
differences.
On large data files, hledger is slower and uses more memory than
On large data files, hledger is slower and uses more memory than
Ledger.
TROUBLESHOOTING
Here are some issues you might encounter when you run hledger (and re-
member you can also seek help from the IRC channel, mail list or bug
Here are some issues you might encounter when you run hledger (and re-
member you can also seek help from the IRC channel, mail list or bug
tracker):
Successfully installed, but "No command 'hledger' found"
stack and cabal install binaries into a special directory, which should
be added to your PATH environment variable. Eg on unix-like systems,
be added to your PATH environment variable. Eg on unix-like systems,
that is ~/.local/bin and ~/.cabal/bin respectively.
I set a custom LEDGER_FILE, but hledger is still using the default file
LEDGER_FILE should be a real environment variable, not just a shell
variable. The command env | grep LEDGER_FILE should show it. You may
LEDGER_FILE should be a real environment variable, not just a shell
variable. The command env | grep LEDGER_FILE should show it. You may
need to use export. Here's an explanation.
Getting errors like "Illegal byte sequence" or "Invalid or incomplete
multibyte or wide character" or "commitAndReleaseBuffer: invalid argu-
Getting errors like "Illegal byte sequence" or "Invalid or incomplete
multibyte or wide character" or "commitAndReleaseBuffer: invalid argu-
ment (invalid character)"
Programs compiled with GHC (hledger, haskell build tools, etc.) need to
have a UTF-8-aware locale configured in the environment, otherwise they
will fail with these kinds of errors when they encounter non-ascii
will fail with these kinds of errors when they encounter non-ascii
characters.
To fix it, set the LANG environment variable to some locale which sup-
To fix it, set the LANG environment variable to some locale which sup-
ports UTF-8. The locale you choose must be installed on your system.
Here's an example of setting LANG temporarily, on Ubuntu GNU/Linux:
@ -3442,8 +3669,8 @@ TROUBLESHOOTING
POSIX
$ LANG=en_US.utf8 hledger -f my.journal print # ensure it is used for this command
If available, C.UTF-8 will also work. If your preferred locale isn't
listed by locale -a, you might need to install it. Eg on Ubuntu/De-
If available, C.UTF-8 will also work. If your preferred locale isn't
listed by locale -a, you might need to install it. Eg on Ubuntu/De-
bian:
$ apt-get install language-pack-fr
@ -3463,8 +3690,8 @@ TROUBLESHOOTING
$ echo "export LANG=en_US.utf8" >>~/.bash_profile
$ bash --login
Exact spelling and capitalisation may be important. Note the differ-
ence on MacOS (UTF-8, not utf8). Some platforms (eg ubuntu) allow
Exact spelling and capitalisation may be important. Note the differ-
ence on MacOS (UTF-8, not utf8). Some platforms (eg ubuntu) allow
variant spellings, but others (eg macos) require it to be exact:
$ locale -a | grep -iE en_us.*utf
@ -3474,7 +3701,7 @@ TROUBLESHOOTING
REPORTING BUGS
Report bugs at http://bugs.hledger.org (or on the #hledger IRC channel
Report bugs at http://bugs.hledger.org (or on the #hledger IRC channel
or hledger mail list)
@ -3488,7 +3715,7 @@ COPYRIGHT
SEE ALSO
hledger(1), hledger-ui(1), hledger-web(1), hledger-api(1),
hledger(1), hledger-ui(1), hledger-web(1), hledger-api(1),
hledger_csv(5), hledger_journal(5), hledger_timeclock(5), hledger_time-
dot(5), ledger(1)