roi: fix insane precision bug, discovered in #1417

This commit is contained in:
Dmitry Astapov 2021-01-12 21:41:10 +00:00 committed by Simon Michael
parent db3fe16645
commit 14a3b9833c
2 changed files with 44 additions and 15 deletions

View File

@ -131,10 +131,10 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{rsOpts=ReportOpts{..}
let smallIsZero x = if abs x < 0.01 then 0.0 else x
return [ showDate spanBegin
, showDate (addDays (-1) spanEnd)
, T.pack $ show valueBefore
, T.pack $ show cashFlowAmt
, T.pack $ show valueAfter
, T.pack $ show (valueAfter - (valueBefore + cashFlowAmt))
, T.pack $ showDecimal valueBefore
, T.pack $ showDecimal cashFlowAmt
, T.pack $ showDecimal valueAfter
, T.pack $ showDecimal (valueAfter - (valueBefore + cashFlowAmt))
, T.pack $ printf "%0.2f%%" $ smallIsZero irr
, T.pack $ printf "%0.2f%%" $ smallIsZero twr ]
@ -193,7 +193,6 @@ timeWeightedReturn showCashFlow prettyTables investmentsQuery trans (OneSpan spa
years = fromIntegral (diffDays spanEnd spanBegin) / 365 :: Double
annualizedTWR = 100*((1+(realToFrac totalTWR/100))**(1/years)-1) :: Double
let s d = show $ roundTo 2 d
when showCashFlow $ do
printf "\nTWR cash flow for %s - %s\n" (showDate spanBegin) (showDate (addDays (-1) spanEnd))
let (dates', amounts) = unzip changes
@ -216,19 +215,19 @@ timeWeightedReturn showCashFlow prettyTables investmentsQuery trans (OneSpan spa
, Tbl.Group SingleLine [Header "Pnl", Header "Cashflow", Header "Unit price", Header "Units"]
, Tbl.Group SingleLine [Header "New Unit Balance"]])
[ [value, oldBalance, pnl, cashflow, prc, udelta, balance]
| value <- map s valuesOnDate
| oldBalance <- map s (0:unitBalances)
| balance <- map s unitBalances
| pnl <- map s pnls
| cashflow <- map s cashflows
| prc <- map s unitPrices
| udelta <- map s unitsBoughtOrSold ])
| value <- map showDecimal valuesOnDate
| oldBalance <- map showDecimal (0:unitBalances)
| balance <- map showDecimal unitBalances
| pnl <- map showDecimal pnls
| cashflow <- map showDecimal 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" (s valueAfter) (s finalUnitBalance) (s finalUnitPrice) (s totalTWR) years annualizedTWR
printf "Final unit price: %s/%s units = %s\nTotal TWR: %s%%.\nPeriod: %.2f years.\nAnnualized TWR: %.2f%%\n\n"
(showDecimal valueAfter) (showDecimal finalUnitBalance) (showDecimal finalUnitPrice) (showDecimal totalTWR) years annualizedTWR
return annualizedTWR
internalRateOfReturn showCashFlow prettyTables (OneSpan spanBegin spanEnd valueBefore valueAfter cashFlow _pnl) = do
let prefix = (spanBegin, negate valueBefore)
@ -243,7 +242,7 @@ internalRateOfReturn showCashFlow prettyTables (OneSpan spanBegin spanEnd valueB
(Table
(Tbl.Group NoLine (map (Header . showDate) dates))
(Tbl.Group SingleLine [Header "Amount"])
(map ((:[]) . T.pack . show) amounts))
(map ((:[]) . T.pack . showDecimal) amounts))
-- 0% is always a solution, so require at least something here
case totalCF of
@ -279,3 +278,11 @@ unMix a =
Nothing -> error' $ "Amounts could not be converted to a single cost basis: " ++ show (map showAmount $ amounts a) ++
"\nConsider using --value to force all costs to be in a single commodity." ++
"\nFor example, \"--value cost,<commodity> --infer-value\", where commodity is the one that was used to pay for the investment."
-- 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
showDecimal d = if d == rounded then show d else show rounded
where
rounded = roundTo 2 d

View File

@ -262,3 +262,25 @@ hledger -f- roi -p 2019-11 --inv Investment --pnl PnL --value cost,A --infer-val
+---++------------+------------++---------------+----------+-------------+-----++----------+-------+
>>>=0
# 11. Dont use crazy amount of decimal places
hledger -f - roi --inv assets:investment --pnl income:investment -X '$'
<<<
P 2020-12-01 $ 76.20
P 2021-01-01 $ 73.88
2020-12-02 invest
assets:investment 10000
assets
2021-01-02 get profit
assets:investment =11000
income:investment
>>>
+---++------------+------------++---------------+----------+-------------+-------++---------+---------+
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR | TWR |
+===++============+============++===============+==========+=============+=======++=========+=========+
| 1 || 2020-12-02 | 2021-01-02 || 0 | 135.35 | 148.89 | 13.54 || 196.58% | 196.58% |
+---++------------+------------++---------------+----------+-------------+-------++---------+---------+
>>>=0