Visitar URL original
Issues with TWR calculation · Issue #2391 · hledgerorg/hledger · GitHub
Skip to content

Issues with TWR calculation #2391

Closed
Closed

Description

@TPolzer

I am observing some results that I can't explain in the roi's TWR calculation.

With the following example ledger, the roi output looks plausible:

commodity 1,000.00 CHF 

P 2024-11-08 B 1 CHF 

2024-11-26 buying B
  assets  -20000 CHF 
  investments:B  19986 B @@ 20000 CHF 

P 2024-12-31 B 1.0018 CHF
$ hledger roi -Q --value then,CHF --inv '"investments:"' --pnl STR
+---++------------+------------++---------------+---------------+---------------+-----------++-------++------------+----------+
|   ||      Begin |        End || Value (begin) |      Cashflow |   Value (end) |       PnL ||   IRR || TWR/period | TWR/year |
+===++============+============++===============+===============+===============+===========++=======++============+==========+
| 1 || 2024-10-01 | 2024-12-31 ||             0 | 20,000.00 CHF | 20,021.97 CHF | 21.97 CHF || 1.12% ||      0.18% |    0.72% |
+---++------------+------------++---------------+---------------+---------------+-----------++-------++------------+----------+

If I now add a small other investment that doesn't move in price at all, TWR goes to almost -100%?

commodity 1,000.00 CHF 

P 2024-11-07 A 1 CHF 
P 2024-11-08 B 1 CHF 

2024-11-07 buying A
  assets  -20 CHF
  investments:A  20 A @@ 20 CHF

2024-11-26 buying B
  assets  -20000 CHF 
  investments:B  19986 B @@ 20000 CHF 

P 2024-12-31 B 1.0018 CHF
$ hledger -f test.ledger roi -Q --value then,CHF --inv '"investments:"' --pnl STR
+---++------------+------------++---------------+---------------+---------------+-----------++-------++------------+----------+
|   ||      Begin |        End || Value (begin) |      Cashflow |   Value (end) |       PnL ||   IRR || TWR/period | TWR/year |
+===++============+============++===============+===============+===============+===========++=======++============+==========+
| 1 || 2024-10-01 | 2024-12-31 ||             0 | 20,020.00 CHF | 20,041.97 CHF | 21.97 CHF || 1.12% ||    -69.95% |  -99.16% |
+---++------------+------------++---------------+---------------+---------------+-----------++-------++------------+----------

That doesn't seem right?

I compiled hledger from git (8b027a4).

Activity

  1. simonmichael commented on May 24, 2025

    @simonmichael
    Member
  2. added
    A-BUGSomething wrong, confusing or sub-standard in the software, docs, or user experience.
    on May 24, 2025
  3. adept commented on May 25, 2025

    @adept
    Contributor

    @TPolzer this should be fixed by #2392

    @simonmichael yet another "computing intra-day valuations are hard" bug :( I hope that the day will come when finally all of them are properly squashed

  4. added a commit that references this issue on May 25, 2025
    306e942
  5. TPolzer commented on May 25, 2025

    @TPolzer
    Author

    I've tried 306e942 and it fixes the initial example, but I think something is still off. Note the difference between these two cases (again, adding just a purchase of a fixed value investment B):

    P 2024-11-07 "A" 1 CHF 
    P 2024-11-29 "A" 0.972 CHF
    P 2024-11-08 "B" 1 "CHF"
    
    2024-11-07 buying A
      assets  -1 CHF 
      investments  1 "A" @@ 1 CHF 
    
    2024-11-15 dividend A
            assets  0.03 CHF 
            equity:profit and loss
            investments  0
    
    2024-12-01 selling A
      assets  0.97 CHF 
      investments  -1 "A" @@ 0.97 CHF 
    
    $ hledger -f test.ledger roi --value then,CHF -Q --inv inv --pnl profit
    +---++------------+------------++---------------+----------+-------------+-----++-------++------------+----------+
    |   ||      Begin |        End || Value (begin) | Cashflow | Value (end) | PnL ||   IRR || TWR/period | TWR/year |
    +===++============+============++===============+==========+=============+=====++=======++============+==========+
    | 1 || 2024-10-01 | 2024-12-31 ||             0 |        0 |           0 |   0 || 0.00% ||      0.12% |    0.46% |
    +---++------------+------------++---------------+----------+-------------+-----++-------++------------+----------+
    
    P 2024-11-07 "A" 1 CHF 
    P 2024-11-29 "A" 0.972 CHF
    P 2024-11-08 "B" 1 "CHF"
    
    2024-11-07 buying A
      assets  -1 CHF 
      investments  1 "A" @@ 1 CHF 
    
    2024-11-15 dividend A
            assets  0.03 CHF 
            equity:profit and loss
            investments  0
    
    2024-11-26 buying B
      assets  -1 CHF
      investments  1 "B" @@ 1 CHF
    
    2024-12-01 selling A
      assets  0.97 CHF 
      investments  -1 "A" @@ 0.97 CHF 
    
    $ hledger -f test.ledger roi --value then,CHF -Q --inv inv --pnl profit
    +---++------------+------------++---------------+-----------+-------------+-----++-------++------------+----------+
    |   ||      Begin |        End || Value (begin) |  Cashflow | Value (end) | PnL ||   IRR || TWR/period | TWR/year |
    +===++============+============++===============+===========+=============+=====++=======++============+==========+
    | 1 || 2024-10-01 | 2024-12-31 ||             0 | 1.000 CHF |   1.000 CHF |   0 || 0.00% ||      1.56% |    6.34% |
    +---++------------+------------++---------------+-----------+-------------+-----++-------++------------+----------+
    
  6. adept commented on May 25, 2025

    @adept
    Contributor

    I dont see any issues with this at a first glance

    In the first case:

    • Initial value is 0
    • 1 A is purchased @ 1 CHF, rate of return for period leading up to this purchase is zero
    • 0.03 CHF is accrued, rate of return for this period is 3%
    • 0.03 CHR is paid out, RoR is 0%
    • 1 A is sold for 0.97 CHF, rate of return for period leading up to this cashflow is -2.8% (we started the period with value of 1 CHF, and ended with value of 0.972 CHF), (0.972/1 - 1)*100 = -2.8%
    • RoR until the end of the reporting period is 0%

    Chaining it all up: ((1+0)*(1+0.03)*(1+0)*(1-0.028)*(1+0)-1) = 0.00116, or multiplying by 100 and rounding up to two digits, 0.12% for 1/4 year, which gives 0.46% annualized.

    In the second case:

    • Initial value is 0
    • 1 A is purchased @ 1 CHF, rate of return for period leading up to this purchase is zero
    • 0.03 CHF is accrued, rate of return for this period is 3%
    • 0.03 CHR is paid out, RoR is 0%
    • 1 B is bought @ 1 CHF, rate of return for this period is 0%
    • 1 A is sold for 0.97 CHF, rate of return for period leading up to this cashflow is -1.4% (we started the period with value of 2 CHF, and ended with value of 1.972 CHF), (1.972/2-1)*100 = -1.4%
    • RoR until the end of the reporting period is 0%

    Chaining it all up: ((1+0)*(1+0.03)*(1+0)*(1+0)*(1-0.014)*(1+0)-1) = 0.01558, or multiplying by 100 and rounding up to two digits, 1.56% for 1/4 year, which gives 6.34% annualized.

    The difference between two cases is that both A and B contribute to the value of your investment, and in the second case the underperformance of A was compensated somewhat by the stable B, which leads to better TWR.

  7. TPolzer commented on May 25, 2025

    @TPolzer
    Author

    Hm, it's entirely possible that my intuition of how TWR "should" behave is off... In that case, thank you for the quick fix and explanation.

  8. simonmichael commented on May 27, 2025

    @simonmichael
    Member

    Thank you both!

  9. added a commit that references this issue on May 27, 2025
    f38bc34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-BUGSomething wrong, confusing or sub-standard in the software, docs, or user experience.roi

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions