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,
|
showAmountWithoutPrice,
|
||||||
amountSetPrecision,
|
amountSetPrecision,
|
||||||
amountSetPrecisionMin,
|
amountSetPrecisionMin,
|
||||||
|
amountSetPrecisionMax,
|
||||||
withPrecision,
|
withPrecision,
|
||||||
amountSetFullPrecision,
|
amountSetFullPrecision,
|
||||||
amountSetFullPrecisionOr,
|
amountSetFullPrecisionOr,
|
||||||
@ -154,6 +155,8 @@ module Hledger.Data.Amount (
|
|||||||
wbUnpack,
|
wbUnpack,
|
||||||
mixedAmountSetPrecision,
|
mixedAmountSetPrecision,
|
||||||
mixedAmountSetFullPrecision,
|
mixedAmountSetFullPrecision,
|
||||||
|
mixedAmountSetPrecisionMin,
|
||||||
|
mixedAmountSetPrecisionMax,
|
||||||
|
|
||||||
-- * misc.
|
-- * misc.
|
||||||
tests_Amount
|
tests_Amount
|
||||||
@ -395,6 +398,12 @@ amountSetPrecisionMin :: Word8 -> Amount -> Amount
|
|||||||
amountSetPrecisionMin minp a = amountSetPrecision p a
|
amountSetPrecisionMin minp a = amountSetPrecision p a
|
||||||
where p = Precision $ max minp (amountDisplayPrecision 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
|
-- | Increase an amount's display precision, if needed, to enough decimal places
|
||||||
-- to show it exactly (showing all significant decimal digits, without trailing zeros).
|
-- 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.
|
-- 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 :: MixedAmount -> MixedAmount
|
||||||
mixedAmountSetFullPrecision = mapMixedAmountUnsafe amountSetFullPrecision
|
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.
|
-- | Remove all prices from a MixedAmount.
|
||||||
mixedAmountStripPrices :: MixedAmount -> MixedAmount
|
mixedAmountStripPrices :: MixedAmount -> MixedAmount
|
||||||
mixedAmountStripPrices (Mixed ma) =
|
mixedAmountStripPrices (Mixed ma) =
|
||||||
|
|||||||
@ -25,6 +25,7 @@ module Hledger.Data.Valuation (
|
|||||||
,marketPriceReverse
|
,marketPriceReverse
|
||||||
,priceDirectiveToMarketPrice
|
,priceDirectiveToMarketPrice
|
||||||
,amountPriceDirectiveFromCost
|
,amountPriceDirectiveFromCost
|
||||||
|
,valuationTypeValuationCommodity
|
||||||
-- ,priceLookup
|
-- ,priceLookup
|
||||||
,tests_Valuation
|
,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
|
| AtDate Day (Maybe CommoditySymbol) -- ^ convert to default or given valuation commodity, using market prices on some date
|
||||||
deriving (Show,Eq)
|
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
|
-- | A price oracle is a magic memoising function that efficiently
|
||||||
-- looks up market prices (exchange rates) from one commodity to
|
-- looks up market prices (exchange rates) from one commodity to
|
||||||
-- another (or if unspecified, to a default valuation commodity) on a
|
-- 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:
|
-- Manage style and precision of the new amount. Initially:
|
||||||
-- rate is a Decimal with the internal precision of the original market price declaration.
|
-- rate is a Decimal with the internal precision of the original market price declaration.
|
||||||
-- aquantity is a Decimal with a's internal precision.
|
-- aquantity is a Decimal with a's internal precision.
|
||||||
-- The resulting internal precision will be larger than both (their sum ?).
|
-- The calculated value's internal precision may be different from these.
|
||||||
-- The display precision will be that of nullamt (0).
|
-- Its display precision will be that of nullamt (0).
|
||||||
-- Now apply the standard display style for comm
|
-- Now apply the standard display style for comm (if there is one)
|
||||||
& styleAmounts styles
|
& styleAmounts styles
|
||||||
-- and set the display precision to rate's internal precision
|
-- set the display precision to match the internal precision (showing all digits),
|
||||||
-- (unnormalised - don't strip trailing zeros)
|
-- unnormalised (don't strip trailing zeros);
|
||||||
-- & amountSetPrecision (Precision $ decimalPlaces rate)
|
-- but if it looks like an infinite decimal, limit the precision to 8.
|
||||||
& amountSetFullPrecisionOr Nothing -- (Just defaultMaxPrecision)
|
& amountSetFullPrecisionOr Nothing
|
||||||
& dbg9With (lbl "calculated value".showAmount)
|
& 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
|
-- | Calculate the gain of each component amount, that is the difference
|
||||||
-- between the valued amount and the value of the cost basis (see
|
-- 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"
|
-- lbl = lbl_ "roi"
|
||||||
today = _rsDay rspec
|
today = _rsDay rspec
|
||||||
priceOracle = journalPriceOracle infer_prices_ j
|
priceOracle = journalPriceOracle infer_prices_ j
|
||||||
styles = journalCommodityStyles j
|
styles = journalCommodityStylesWith HardRounding j
|
||||||
mixedAmountValue periodlast date =
|
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_
|
. maybe id (mixedAmountToCost styles) conversionop_
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|||||||
@ -257,7 +257,9 @@ $ hledger -f- roi -p 2019-11 --inv Investment --pnl PnL --cost --value=then,A --
|
|||||||
|
|
||||||
>= 0
|
>= 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 2020-12-01 $ 76.20
|
||||||
P 2021-01-01 $ 73.88
|
P 2021-01-01 $ 73.88
|
||||||
@ -269,17 +271,20 @@ P 2021-01-01 $ 73.88
|
|||||||
2021-01-02 get profit
|
2021-01-02 get profit
|
||||||
assets:investment =11000
|
assets:investment =11000
|
||||||
income:investment
|
income:investment
|
||||||
|
|
||||||
$ hledger -f - roi --inv assets:investment --pnl income:investment --value=then,'$'
|
$ hledger -f - roi --inv assets:investment --pnl income:investment --value=then,'$'
|
||||||
+---++------------+------------++---------------+----------+-------------+-----++---------++------------+----------+
|
+---++------------+------------++---------------+---------------+---------------+--------------++---------++------------+----------+
|
||||||
| || Begin | End || Value (begin) | Cashflow | Value (end) | PnL || IRR || TWR/period | TWR/year |
|
| || 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% |
|
| 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 2020-12-01 $ 76.20
|
||||||
P 2021-01-01 $ 73.88
|
P 2021-01-01 $ 73.88
|
||||||
|
|
||||||
@ -290,14 +295,15 @@ P 2021-01-01 $ 73.88
|
|||||||
2021-01-02 get profit
|
2021-01-02 get profit
|
||||||
assets:investment =11000
|
assets:investment =11000
|
||||||
income:investment
|
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
|
# ** 13. Several PnL transactions on a single date are aggregated together
|
||||||
<
|
<
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user