diff --git a/hledger/Hledger/Cli/Commands/Roi.hs b/hledger/Hledger/Cli/Commands/Roi.hs index 28c1bb9a3..edf6c6e25 100644 --- a/hledger/Hledger/Cli/Commands/Roi.hs +++ b/hledger/Hledger/Cli/Commands/Roi.hs @@ -110,12 +110,12 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{_rsReportOpts=ReportO e = fromEFDay end cashFlowApplyCostValue = map (\(d,amt) -> (d,mixedAmountValue e d amt)) - valueBefore = + valueBefore = dbg3 "valueBefore" $ mixedAmountValue e b $ total trans (And [ investmentsQuery , Date (DateSpan Nothing (Just begin))]) - valueAfter = + valueAfter = dbg3 "valueAfter" $ mixedAmountValue e e $ total trans (And [investmentsQuery , Date (DateSpan Nothing (Just end))]) @@ -143,8 +143,8 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{_rsReportOpts=ReportO let smallIsZero x = if abs x < 0.01 then 0.0 else x return [ showDate b , showDate (addDays (-1) e) - , T.pack $ showMixedAmount $ styleAmounts styles $ valueBefore - , T.pack $ showMixedAmount $ styleAmounts styles $ cashFlowAmt + , T.pack $ showMixedAmountOneLineWithoutCost False $ styleAmounts styles $ valueBefore + , T.pack $ showMixedAmountOneLineWithoutCost False $ styleAmounts styles $ cashFlowAmt -- , T.pack $ showMixedAmount $ -- -- dbg0With (lbl "cashflow after styling".showMixedAmountOneLine) $ -- mapMixedAmount (amountSetFullPrecisionUpTo (Just defaultMaxPrecision)) $ @@ -152,8 +152,8 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{_rsReportOpts=ReportO -- -- & dbg0With (lbl "styles".show)) -- cashFlowAmt -- -- & dbg0With (lbl "cashflow before styling".showMixedAmountOneLine) - , T.pack $ showMixedAmount $ styleAmounts styles $ valueAfter - , T.pack $ showMixedAmount $ styleAmounts styles $ (valueAfter `maMinus` (valueBefore `maPlus` cashFlowAmt)) + , T.pack $ showMixedAmountOneLineWithoutCost False $ styleAmounts styles $ valueAfter + , T.pack $ showMixedAmountOneLineWithoutCost False $ styleAmounts styles $ (valueAfter `maMinus` (valueBefore `maPlus` cashFlowAmt)) , T.pack $ printf "%0.2f%%" $ smallIsZero irr , T.pack $ printf "%0.2f%%" $ smallIsZero periodTwr , T.pack $ printf "%0.2f%%" $ smallIsZero annualizedTwr ] @@ -278,13 +278,13 @@ timeWeightedReturn styles showCashFlow prettyTables investmentsQuery trans mixed | val <- map showDecimal valuesOnDate | oldBalance <- map showDecimal (0:unitBalances) | balance <- map showDecimal unitBalances - | pnl' <- map (showMixedAmount . styleAmounts styles) pnls - | cashflow <- map (showMixedAmount . styleAmounts styles) cashflows + | pnl' <- map (showMixedAmountOneLineWithoutCost False . styleAmounts styles) pnls + | cashflow <- map (showMixedAmountOneLineWithoutCost False . styleAmounts styles) cashflows | prc <- map showDecimal unitPrices | udelta <- map showDecimal unitsBoughtOrSold ]) printf "Final unit price: %s/%s units = %s\nTotal TWR: %s%%.\nPeriod: %.2f years.\nAnnualized TWR: %.2f%%\n\n" - (showMixedAmount $ styleAmounts styles valueAfter) (showDecimal finalUnitBalance) (showDecimal finalUnitCost) (showDecimal totalTWR) years annualizedTWR + (showMixedAmountOneLineWithoutCost False $ styleAmounts styles valueAfter) (showDecimal finalUnitBalance) (showDecimal finalUnitCost) (showDecimal totalTWR) years annualizedTWR return ((realToFrac totalTWR) :: Double, annualizedTWR) @@ -302,7 +302,7 @@ internalRateOfReturn styles showCashFlow prettyTables (OneSpan begin end valueBe (Table (Tab.Group Tab.NoLine (map (Header . showDate) dates)) (Tab.Group Tab.SingleLine [Header "Amount"]) - (map ((:[]) . T.pack . showMixedAmount . styleAmounts styles) amts)) + (map ((:[]) . T.pack . showMixedAmountOneLineWithoutCost False . styleAmounts styles) amts)) -- 0% is always a solution, so require at least something here case totalCF of @@ -332,11 +332,11 @@ total trans query = sumPostings . filter (matchesPosting query) $ concatMap real unMix :: MixedAmount -> Quantity unMix a = - case (unifyMixedAmount $ mixedAmountCost a) of + case (unifyMixedAmount a) of Just a' -> aquantity a' - Nothing -> error' $ "Amounts could not be converted to a single cost basis: " ++ show (map showAmount $ amounts a) ++ + Nothing -> error' $ "Amounts could not be converted to a single commodity: " ++ show (map showAmount $ amounts a) ++ "\nConsider using --value to force all costs to be in a single commodity." ++ - "\nFor example, \"--cost --value=end, --infer-market-prices\", where commodity is the one that was used to pay for the investment." + "\nFor example, \"--value=end, --infer-market-prices\", where commodity is the one that was used for investment valuations." -- Show Decimal rounded to two decimal places, unless it has less places already. This ensures that "2" won't be shown as "2.00" showDecimal :: Decimal -> String diff --git a/hledger/test/roi.test b/hledger/test/roi.test index 49afdb787..37b2a8f6e 100644 --- a/hledger/test/roi.test +++ b/hledger/test/roi.test @@ -228,14 +228,18 @@ $ hledger -f- roi -p 2019-11 Investment 10 B 2019/11/02 Example - Investment -10 B @@ 100 A + Assets:Checking -100 C + Investment 100 C + +2019/11/02 Example + Investment -9 B @@ 100 A Assets:Checking 101 A Unrealized PnL $ hledger -f- roi -p 2019-11 --inv Investment --pnl PnL >2 -hledger: Error: Amounts could not be converted to a single cost basis: ["10 B","-10 B @@ 100 A"] +hledger: Error: Amounts could not be converted to a single commodity: ["10 B","-9 B @@ 100 A","100 C"] Consider using --value to force all costs to be in a single commodity. -For example, "--cost --value=end, --infer-market-prices", where commodity is the one that was used to pay for the investment. +For example, "--value=end, --infer-market-prices", where commodity is the one that was used for investment valuations. >= 1 # ** 10. Forcing valuation via --value @@ -362,3 +366,24 @@ $ hledger -f - roi --inv stocks --pnl expenses --value=then,€ -Y +---++------------+------------++---------------+----------+-------------+------++---------++------------+----------+ >= 0 + +# ** 15. Correctly work with --value and complex valuation chains +< +P 2023-01-01 B 20A +P 2023-01-01 C 1B + +2023-01-01 + investment 1C @@ 20A + investment 4B @@ 80A + assets + +P 2023-12-31 C 2B + +$ hledger -f - roi --inv investment --pnl income --value='end,B' -b2023 -e2024 ++---++------------+------------++---------------+----------+-------------+-----++--------++------------+----------+ +| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR || TWR/period | TWR/year | ++===++============+============++===============+==========+=============+=====++========++============+==========+ +| 1 || 2023-01-01 | 2023-12-31 || 0 | 5B | 6B | 1B || 20.00% || 20.00% | 20.00% | ++---++------------+------------++---------------+----------+-------------+-----++--------++------------+----------+ + +>= 0