imp: roi: limit large decimals to 8 digits by default (precisiongeddon)
With valuation now preserving more decimal digits, roi could show excessively precise decimals if there was no known display precision for the valuation commodity. Now in that situation it limits the precision to a maximum of 8 digits.
This commit is contained in:
parent
f8ffd9cdda
commit
e035730afb
@ -91,6 +91,7 @@ module Hledger.Data.Amount (
|
||||
showAmountWithoutPrice,
|
||||
amountSetPrecision,
|
||||
amountSetPrecisionMin,
|
||||
amountSetPrecisionMax,
|
||||
withPrecision,
|
||||
amountSetFullPrecision,
|
||||
amountSetFullPrecisionOr,
|
||||
@ -154,6 +155,8 @@ module Hledger.Data.Amount (
|
||||
wbUnpack,
|
||||
mixedAmountSetPrecision,
|
||||
mixedAmountSetFullPrecision,
|
||||
mixedAmountSetPrecisionMin,
|
||||
mixedAmountSetPrecisionMax,
|
||||
|
||||
-- * misc.
|
||||
tests_Amount
|
||||
@ -395,6 +398,12 @@ amountSetPrecisionMin :: Word8 -> Amount -> Amount
|
||||
amountSetPrecisionMin minp a = amountSetPrecision p a
|
||||
where p = Precision $ max minp (amountDisplayPrecision a)
|
||||
|
||||
-- | Ensure an amount's display precision is at most the given maximum precision.
|
||||
-- Always sets an explicit Precision.
|
||||
amountSetPrecisionMax :: Word8 -> Amount -> Amount
|
||||
amountSetPrecisionMax maxp a = amountSetPrecision p a
|
||||
where p = Precision $ min maxp (amountDisplayPrecision a)
|
||||
|
||||
-- | Increase an amount's display precision, if needed, to enough decimal places
|
||||
-- to show it exactly (showing all significant decimal digits, without trailing zeros).
|
||||
-- If the amount's display precision is unset, it will be treated as precision 0.
|
||||
@ -1189,6 +1198,16 @@ mixedAmountSetPrecision p = mapMixedAmountUnsafe (amountSetPrecision p)
|
||||
mixedAmountSetFullPrecision :: MixedAmount -> MixedAmount
|
||||
mixedAmountSetFullPrecision = mapMixedAmountUnsafe amountSetFullPrecision
|
||||
|
||||
-- | In each component amount, ensure the display precision is at least the given value.
|
||||
-- Makes all amounts have an explicit Precision.
|
||||
mixedAmountSetPrecisionMin :: Word8 -> MixedAmount -> MixedAmount
|
||||
mixedAmountSetPrecisionMin p = mapMixedAmountUnsafe (amountSetPrecisionMin p)
|
||||
|
||||
-- | In each component amount, ensure the display precision is at most the given value.
|
||||
-- Makes all amounts have an explicit Precision.
|
||||
mixedAmountSetPrecisionMax :: Word8 -> MixedAmount -> MixedAmount
|
||||
mixedAmountSetPrecisionMax p = mapMixedAmountUnsafe (amountSetPrecisionMax p)
|
||||
|
||||
-- | Remove all prices from a MixedAmount.
|
||||
mixedAmountStripPrices :: MixedAmount -> MixedAmount
|
||||
mixedAmountStripPrices (Mixed ma) =
|
||||
|
||||
@ -25,6 +25,7 @@ module Hledger.Data.Valuation (
|
||||
,marketPriceReverse
|
||||
,priceDirectiveToMarketPrice
|
||||
,amountPriceDirectiveFromCost
|
||||
,valuationTypeValuationCommodity
|
||||
-- ,priceLookup
|
||||
,tests_Valuation
|
||||
)
|
||||
@ -68,6 +69,14 @@ data ValuationType =
|
||||
| AtDate Day (Maybe CommoditySymbol) -- ^ convert to default or given valuation commodity, using market prices on some date
|
||||
deriving (Show,Eq)
|
||||
|
||||
valuationTypeValuationCommodity :: ValuationType -> Maybe CommoditySymbol
|
||||
valuationTypeValuationCommodity = \case
|
||||
AtThen (Just c) -> Just c
|
||||
AtEnd (Just c) -> Just c
|
||||
AtNow (Just c) -> Just c
|
||||
AtDate _ (Just c) -> Just c
|
||||
_ -> Nothing
|
||||
|
||||
-- | A price oracle is a magic memoising function that efficiently
|
||||
-- looks up market prices (exchange rates) from one commodity to
|
||||
-- another (or if unspecified, to a default valuation commodity) on a
|
||||
@ -193,17 +202,15 @@ amountValueAtDate priceoracle styles mto d a =
|
||||
-- Manage style and precision of the new amount. Initially:
|
||||
-- rate is a Decimal with the internal precision of the original market price declaration.
|
||||
-- aquantity is a Decimal with a's internal precision.
|
||||
-- The resulting internal precision will be larger than both (their sum ?).
|
||||
-- The display precision will be that of nullamt (0).
|
||||
-- Now apply the standard display style for comm
|
||||
-- The calculated value's internal precision may be different from these.
|
||||
-- Its display precision will be that of nullamt (0).
|
||||
-- Now apply the standard display style for comm (if there is one)
|
||||
& styleAmounts styles
|
||||
-- and set the display precision to rate's internal precision
|
||||
-- (unnormalised - don't strip trailing zeros)
|
||||
-- & amountSetPrecision (Precision $ decimalPlaces rate)
|
||||
& amountSetFullPrecisionOr Nothing -- (Just defaultMaxPrecision)
|
||||
-- set the display precision to match the internal precision (showing all digits),
|
||||
-- unnormalised (don't strip trailing zeros);
|
||||
-- but if it looks like an infinite decimal, limit the precision to 8.
|
||||
& amountSetFullPrecisionOr Nothing
|
||||
& dbg9With (lbl "calculated value".showAmount)
|
||||
-- & dbg9With (lbl "precision of value".show.amountDisplayPrecision)
|
||||
-- see also print-styles.test, valuation2.test
|
||||
|
||||
-- | Calculate the gain of each component amount, that is the difference
|
||||
-- between the valued amount and the value of the cost basis (see
|
||||
|
||||
@ -65,9 +65,15 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{_rsReportOpts=ReportO
|
||||
-- lbl = lbl_ "roi"
|
||||
today = _rsDay rspec
|
||||
priceOracle = journalPriceOracle infer_prices_ j
|
||||
styles = journalCommodityStyles j
|
||||
styles = journalCommodityStylesWith HardRounding j
|
||||
mixedAmountValue periodlast date =
|
||||
maybe id (mixedAmountApplyValuation priceOracle styles periodlast today date) value_
|
||||
-- These calculations can generate very precise decimals. To avoid showing too many digits:
|
||||
-- If we have no style for the valuation commodity, generate one that will limit the precision ?
|
||||
-- But it's not easy to find out the valuation commodity (or commodities) here if it's implicit,
|
||||
-- as that information is buried in the price graph.
|
||||
-- Instead, do what we don't like to do: hard code a max precision, overriding commodity styles.
|
||||
mixedAmountSetPrecisionMax defaultMaxPrecision
|
||||
. maybe id (mixedAmountApplyValuation priceOracle styles periodlast today date) value_
|
||||
. maybe id (mixedAmountToCost styles) conversionop_
|
||||
|
||||
let
|
||||
|
||||
@ -257,7 +257,9 @@ $ hledger -f- roi -p 2019-11 --inv Investment --pnl PnL --cost --value=then,A --
|
||||
|
||||
>= 0
|
||||
|
||||
# ** 11. Use "then" prices. 10000/76.20 = 131.23, 11000/73.88=148.89
|
||||
# ** 11. Use "then" prices. 10000/76.20 = 131.23, 11000/73.88=148.89.
|
||||
# Also note that large decimals are limited to 8 digits if there's no
|
||||
# standard display precision for them (P directives do not set display precision).
|
||||
<
|
||||
P 2020-12-01 $ 76.20
|
||||
P 2021-01-01 $ 73.88
|
||||
@ -269,17 +271,20 @@ P 2021-01-01 $ 73.88
|
||||
2021-01-02 get profit
|
||||
assets:investment =11000
|
||||
income:investment
|
||||
|
||||
$ hledger -f - roi --inv assets:investment --pnl income:investment --value=then,'$'
|
||||
+---++------------+------------++---------------+----------+-------------+-----++---------++------------+----------+
|
||||
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR || TWR/period | TWR/year |
|
||||
+===++============+============++===============+==========+=============+=====++=========++============+==========+
|
||||
| 1 || 2020-12-02 | 2021-01-02 || 0 | $131 | $149 | $18 || 321.99% || 13.45% | 323.47% |
|
||||
+---++------------+------------++---------------+----------+-------------+-----++---------++------------+----------+
|
||||
+---++------------+------------++---------------+---------------+---------------+--------------++---------++------------+----------+
|
||||
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR || TWR/period | TWR/year |
|
||||
+===++============+============++===============+===============+===============+==============++=========++============+==========+
|
||||
| 1 || 2020-12-02 | 2021-01-02 || 0 | $131.23359580 | $148.89009204 | $17.65649624 || 321.99% || 13.45% | 323.47% |
|
||||
+---++------------+------------++---------------+---------------+---------------+--------------++---------++------------+----------+
|
||||
|
||||
>= 0
|
||||
>=
|
||||
|
||||
# ** 12. Use "end" prices. 10000/73.88=135.35
|
||||
# ** 12. Use "end" prices. 10000/73.88=135.35.
|
||||
# And, large decimals can be rounded further with a commodity directive.
|
||||
<
|
||||
commodity $1000.00
|
||||
P 2020-12-01 $ 76.20
|
||||
P 2021-01-01 $ 73.88
|
||||
|
||||
@ -290,14 +295,15 @@ P 2021-01-01 $ 73.88
|
||||
2021-01-02 get profit
|
||||
assets:investment =11000
|
||||
income:investment
|
||||
$ hledger -f - roi --inv assets:investment --pnl income:investment --value=end,'$'
|
||||
+---++------------+------------++---------------+----------+-------------+-----++---------++------------+----------+
|
||||
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR || TWR/period | TWR/year |
|
||||
+===++============+============++===============+==========+=============+=====++=========++============+==========+
|
||||
| 1 || 2020-12-02 | 2021-01-02 || 0 | $135 | $149 | $14 || 196.58% || 10.00% | 197.46% |
|
||||
+---++------------+------------++---------------+----------+-------------+-----++---------++------------+----------+
|
||||
|
||||
>= 0
|
||||
$ hledger -f - roi --inv assets:investment --pnl income:investment --value=end,'$'
|
||||
+---++------------+------------++---------------+----------+-------------+--------++---------++------------+----------+
|
||||
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR || TWR/period | TWR/year |
|
||||
+===++============+============++===============+==========+=============+========++=========++============+==========+
|
||||
| 1 || 2020-12-02 | 2021-01-02 || 0 | $135.35 | $148.89 | $13.54 || 196.58% || 10.00% | 197.46% |
|
||||
+---++------------+------------++---------------+----------+-------------+--------++---------++------------+----------+
|
||||
|
||||
>=
|
||||
|
||||
# ** 13. Several PnL transactions on a single date are aggregated together
|
||||
<
|
||||
|
||||
Loading…
Reference in New Issue
Block a user