diff --git a/hledger/Hledger/Cli/Commands/Roi.hs b/hledger/Hledger/Cli/Commands/Roi.hs index 530a8b11f..5dd6b738c 100644 --- a/hledger/Hledger/Cli/Commands/Roi.hs +++ b/hledger/Hledger/Cli/Commands/Roi.hs @@ -19,7 +19,6 @@ import Data.Time.Calendar import Text.Printf import Data.Function (on) import Data.List -import Data.Maybe (fromMaybe) import Numeric.RootFinding import Data.Decimal import qualified Data.Text as T @@ -61,8 +60,10 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{rsOpts=ReportOpts{..} d <- getCurrentDay -- We may be converting posting amounts to value, per hledger_options.m4.md "Effect of --value on reports". let - tvalue = transactionApplyCostValuation (journalPriceOracle infer_value_ j) (journalCommodityStyles j) periodlast (rsToday rspec) cost_ value_ - where periodlast = fromMaybe (rsToday rspec) $ reportPeriodOrJournalLastDay rspec j + priceOracle = (journalPriceOracle infer_value_ j) + styles = (journalCommodityStyles j) + today = rsToday rspec + mixedAmountValue periodlast date = mixedAmountApplyCostValuation priceOracle styles periodlast today date cost_ value_ let ropts = rsOpts rspec showCashFlow = boolopt "cashflow" rawopts @@ -75,7 +76,7 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{rsOpts=ReportOpts{..} pnlQuery <- makeQuery "pnl" let - trans = dbg3 "investments" $ map tvalue $ jtxns $ filterJournalTransactions investmentsQuery j + trans = dbg3 "investments" $ jtxns $ filterJournalTransactions investmentsQuery j journalSpan = let dates = map transactionDate2 trans in @@ -93,26 +94,31 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{rsOpts=ReportOpts{..} let spans = case requestedInterval of NoInterval -> [wholeSpan] interval -> - splitSpan interval $ - spanIntersect journalSpan wholeSpan + splitSpan interval wholeSpan tableBody <- forM spans $ \(DateSpan (Just spanBegin) (Just spanEnd)) -> do -- Spans are [spanBegin,spanEnd), and spanEnd is 1 day after then actual end date we are interested in let + cashFlowApplyCostValue = map (\(d,amt) -> (d,mixedAmountValue spanEnd d amt)) + valueBefore = + mixedAmountValue spanEnd spanBegin $ total trans (And [ investmentsQuery , Date (DateSpan Nothing (Just spanBegin))]) valueAfter = + mixedAmountValue spanEnd spanEnd $ total trans (And [investmentsQuery , Date (DateSpan Nothing (Just spanEnd))]) cashFlow = + cashFlowApplyCostValue $ calculateCashFlow trans (And [ Not investmentsQuery , Not pnlQuery , Date (DateSpan (Just spanBegin) (Just spanEnd)) ] ) pnl = + cashFlowApplyCostValue $ calculateCashFlow trans (And [ Not investmentsQuery , pnlQuery , Date (DateSpan (Just spanBegin) (Just spanEnd)) ] ) @@ -121,7 +127,7 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{rsOpts=ReportOpts{..} OneSpan spanBegin spanEnd valueBefore valueAfter cashFlow pnl irr <- internalRateOfReturn showCashFlow prettyTables thisSpan - twr <- timeWeightedReturn showCashFlow prettyTables investmentsQuery trans thisSpan + twr <- timeWeightedReturn showCashFlow prettyTables investmentsQuery trans mixedAmountValue thisSpan let cashFlowAmt = negate $ sum $ map snd cashFlow let smallIsZero x = if abs x < 0.01 then 0.0 else x return [ showDate spanBegin @@ -143,7 +149,7 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{rsOpts=ReportOpts{..} TL.putStrLn $ Ascii.render prettyTables id id id table -timeWeightedReturn showCashFlow prettyTables investmentsQuery trans (OneSpan spanBegin spanEnd valueBeforeAmt valueAfter cashFlow pnl) = do +timeWeightedReturn showCashFlow prettyTables investmentsQuery trans mixedAmountValue (OneSpan spanBegin spanEnd valueBeforeAmt valueAfter cashFlow pnl) = do let valueBefore = unMix valueBeforeAmt let initialUnitPrice = 100 :: Decimal let initialUnits = valueBefore / initialUnitPrice @@ -166,7 +172,7 @@ timeWeightedReturn showCashFlow prettyTables investmentsQuery trans (OneSpan spa tail $ scanl (\(_, _, unitPrice, unitBalance) (date, amt) -> - let valueOnDate = unMix $ total trans (And [investmentsQuery, Date (DateSpan Nothing (Just date))]) + let valueOnDate = unMix $ mixedAmountValue spanEnd date $ total trans (And [investmentsQuery, Date (DateSpan Nothing (Just date))]) in case amt of Right amt -> diff --git a/hledger/test/roi.test b/hledger/test/roi.test index 0df44502f..0eef6a013 100644 --- a/hledger/test/roi.test +++ b/hledger/test/roi.test @@ -263,8 +263,30 @@ hledger -f- roi -p 2019-11 --inv Investment --pnl PnL --cost --value=then,A --in >>>=0 -# 11. Dont use crazy amount of decimal places -hledger -f - roi --inv assets:investment --pnl income:investment -X '$' +# 11. Use "then" prices. 10000/76.20 = 131.23, 11000/73.88=148.89 +hledger -f - roi --inv assets:investment --pnl income:investment --value=then,'$' +<<< +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 | $131 | $149 | $18 || 321.99% | 321.81% | ++---++------------+------------++---------------+----------+-------------+-----++---------+---------+ + +>>>=0 + +# 12. Use "end" prices. 10000/73.88=135.35 +hledger -f - roi --inv assets:investment --pnl income:investment --value=end,'$' <<< P 2020-12-01 $ 76.20 P 2021-01-01 $ 73.88