parsing: infer a conversion price in unpriced two-commodity transactions
This commit is contained in:
parent
c8614b9a15
commit
33bedcbab0
@ -360,20 +360,28 @@ Or, you can write `@@ TOTALPRICE`, which is sometimes more convenient:
|
|||||||
assets:cash
|
assets:cash
|
||||||
|
|
||||||
Or, you can set the price for this commodity as of a certain date, using a
|
Or, you can set the price for this commodity as of a certain date, using a
|
||||||
historical price directive as shown here:
|
historical price directive (P) as shown:
|
||||||
|
|
||||||
; the exchange rate for euro is $1.35 on 2009/1/1 (and thereafter, until a newer price directive is found)
|
; the exchange rate for euro is $1.35 on 2009/1/1 (and thereafter, until a newer price directive is found)
|
||||||
; four space-separated fields: P, date, commodity symbol, unit price in 2nd commodity
|
; four space-separated fields: P, date, commodity symbol, unit price in 2nd commodity
|
||||||
P 2009/1/1 € $1.35
|
P 2009/1/1 € $1.35
|
||||||
|
|
||||||
2009/1/2 x
|
2009/1/2
|
||||||
expenses:foreign currency €100
|
expenses:foreign currency €100
|
||||||
assets
|
assets
|
||||||
|
|
||||||
The print command shows any prices in effect. Either example above will show:
|
Or, you can write a transaction in two commodities, without prices but
|
||||||
|
with all amounts specified, and a conversion price will be inferred so as
|
||||||
|
to balance the transaction:
|
||||||
|
|
||||||
|
2009/1/2
|
||||||
|
expenses:foreign currency €100
|
||||||
|
assets $-135
|
||||||
|
|
||||||
|
The print command shows any prices in effect. So the first example above gives:
|
||||||
|
|
||||||
$ hledger print
|
$ hledger print
|
||||||
2009/01/02 x
|
2009/01/02
|
||||||
expenses:foreign currency €100 @ $1.35
|
expenses:foreign currency €100 @ $1.35
|
||||||
assets €-100 @ $1.35
|
assets €-100 @ $1.35
|
||||||
|
|
||||||
@ -385,8 +393,8 @@ with any command:
|
|||||||
expenses:foreign currency $135.00
|
expenses:foreign currency $135.00
|
||||||
assets $-135.00
|
assets $-135.00
|
||||||
|
|
||||||
The `--cost/-B` flag does only one lookup step, ie it will not look up the
|
In other words the `--cost/-B` flag converts amounts to their price's
|
||||||
price of a price's commodity.
|
commodity. (It will not look up the price of a price.)
|
||||||
|
|
||||||
Note hledger handles prices differently from c++ ledger in this respect:
|
Note hledger handles prices differently from c++ ledger in this respect:
|
||||||
we assume unit prices do not vary over time. This is good for simple
|
we assume unit prices do not vary over time. This is good for simple
|
||||||
@ -1110,8 +1118,9 @@ entries, and the following c++ ledger options and commands:
|
|||||||
it does not print multi-commodity transactions in valid journal format.)
|
it does not print multi-commodity transactions in valid journal format.)
|
||||||
|
|
||||||
- hledger's default commodity directive (D) sets the commodity for
|
- hledger's default commodity directive (D) sets the commodity for
|
||||||
subsequent commodityless amounts. ledger uses it only to set commodity
|
subsequent commodityless amounts, and contributes to that commodity's
|
||||||
display settings and for the entry command.
|
display settings. ledger uses D only for commodity display settings
|
||||||
|
and for the entry command.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@ -1241,10 +1250,8 @@ Here are some issues you might encounter when you run hledger:
|
|||||||
the current list of things we know we don't parse (see also
|
the current list of things we know we don't parse (see also
|
||||||
[file format compatibility](#file-format-compatibility):
|
[file format compatibility](#file-format-compatibility):
|
||||||
|
|
||||||
- AMOUNT1 = AMOUNT2 (balance assertion ? price specification ?)
|
- AMOUNT1 = AMOUNT2 (balance assertion/price specification ?)
|
||||||
- specifying prices via postings in different commodities
|
- ... AMOUNT {...}
|
||||||
- comma decimal point and period thousands separator, or any number
|
|
||||||
format other than the US standard
|
|
||||||
|
|
||||||
## Examples and recipes
|
## Examples and recipes
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import Hledger.Data.Types
|
|||||||
import Hledger.Data.Dates
|
import Hledger.Data.Dates
|
||||||
import Hledger.Data.Posting
|
import Hledger.Data.Posting
|
||||||
import Hledger.Data.Amount
|
import Hledger.Data.Amount
|
||||||
import Hledger.Data.Commodity (dollars, dollar, unknown)
|
import Hledger.Data.Commodity
|
||||||
|
|
||||||
instance Show Transaction where show = showTransactionUnelided
|
instance Show Transaction where show = showTransactionUnelided
|
||||||
|
|
||||||
@ -133,29 +133,87 @@ isTransactionBalanced canonicalcommoditymap t =
|
|||||||
rsum' = canonicaliseMixedAmount canonicalcommoditymap $ costOfMixedAmount rsum
|
rsum' = canonicaliseMixedAmount canonicalcommoditymap $ costOfMixedAmount rsum
|
||||||
bvsum' = canonicaliseMixedAmount canonicalcommoditymap $ costOfMixedAmount bvsum
|
bvsum' = canonicaliseMixedAmount canonicalcommoditymap $ costOfMixedAmount bvsum
|
||||||
|
|
||||||
-- | Ensure that this entry is balanced, possibly auto-filling a missing
|
-- | Ensure this transaction is balanced, possibly inferring a missing
|
||||||
-- amount first. We can auto-fill if there is just one non-virtual
|
-- amount or a conversion price first, or return an error message.
|
||||||
-- transaction without an amount. The auto-filled balance will be
|
--
|
||||||
-- converted to cost basis if possible. If the entry can not be balanced,
|
-- Balancing is affected by the provided commodities' display precisions.
|
||||||
-- return an error message instead.
|
--
|
||||||
|
-- We can infer an amount when there are multiple real postings and
|
||||||
|
-- exactly one of them is amountless; likewise for balanced virtual
|
||||||
|
-- postings. Inferred amounts are converted to cost basis when possible.
|
||||||
|
--
|
||||||
|
-- We can infer a price when all amounts were specified and the sum of
|
||||||
|
-- real postings' amounts is exactly two non-explicitly-priced amounts in
|
||||||
|
-- different commodities; likewise for balanced virtual postings.
|
||||||
balanceTransaction :: Maybe (Map.Map String Commodity) -> Transaction -> Either String Transaction
|
balanceTransaction :: Maybe (Map.Map String Commodity) -> Transaction -> Either String Transaction
|
||||||
balanceTransaction canonicalcommoditymap t@Transaction{tpostings=ps}
|
balanceTransaction canonicalcommoditymap t@Transaction{tpostings=ps}
|
||||||
| length rwithoutamounts > 1 || length bvwithoutamounts > 1
|
| length rwithoutamounts > 1 || length bvwithoutamounts > 1
|
||||||
= Left $ printerr "could not balance this transaction (too many missing amounts)"
|
= Left $ printerr "could not balance this transaction (too many missing amounts)"
|
||||||
| not $ isTransactionBalanced canonicalcommoditymap t' = Left $ printerr $ nonzerobalanceerror t'
|
| not $ isTransactionBalanced canonicalcommoditymap t''' = Left $ printerr $ nonzerobalanceerror t'''
|
||||||
| otherwise = Right t'
|
| otherwise = Right t'''
|
||||||
where
|
where
|
||||||
rps = filter isReal ps
|
-- maybe infer missing amounts
|
||||||
bvps = filter isBalancedVirtual ps
|
(rwithamounts, rwithoutamounts) = partition hasAmount $ realPostings t
|
||||||
(rwithamounts, rwithoutamounts) = partition hasAmount rps
|
(bvwithamounts, bvwithoutamounts) = partition hasAmount $ balancedVirtualPostings t
|
||||||
(bvwithamounts, bvwithoutamounts) = partition hasAmount bvps
|
ramounts = map pamount rwithamounts
|
||||||
t' = t{tpostings=map balance ps}
|
bvamounts = map pamount bvwithamounts
|
||||||
|
t' = t{tpostings=map inferamount ps}
|
||||||
where
|
where
|
||||||
balance p | not (hasAmount p) && isReal p
|
inferamount p | not (hasAmount p) && isReal p = p{pamount = (- sum ramounts)}
|
||||||
= p{pamount = (-(sum $ map pamount rwithamounts))}
|
| not (hasAmount p) && isBalancedVirtual p = p{pamount = (- sum bvamounts)}
|
||||||
| not (hasAmount p) && isBalancedVirtual p
|
| otherwise = p
|
||||||
= p{pamount = (-(sum $ map pamount bvwithamounts))}
|
|
||||||
| otherwise = p
|
-- maybe infer conversion prices, for real postings
|
||||||
|
rmixedamountsinorder = map pamount $ realPostings t'
|
||||||
|
ramountsinorder = concatMap amounts rmixedamountsinorder
|
||||||
|
rcommoditiesinorder = map commodity ramountsinorder
|
||||||
|
rsumamounts = amounts $ sum rmixedamountsinorder
|
||||||
|
-- assumption: the sum of mixed amounts is normalised (one simple amount per commodity)
|
||||||
|
t'' = if length rsumamounts == 2 && all (isNothing.price) rsumamounts && t'==t
|
||||||
|
then t'{tpostings=map inferprice ps}
|
||||||
|
else t'
|
||||||
|
where
|
||||||
|
-- assumption: a posting's mixed amount contains one simple amount
|
||||||
|
inferprice p@Posting{pamount=Mixed [a@Amount{commodity=c,price=Nothing}], ptype=RegularPosting}
|
||||||
|
= p{pamount=Mixed [a{price=conversionprice c}]}
|
||||||
|
where
|
||||||
|
conversionprice c | c == unpricedcommodity
|
||||||
|
-- assign a balancing price. Use @@ for more exact output when possible.
|
||||||
|
= if length ramountsinunpricedcommodity == 1
|
||||||
|
then Just $ TotalPrice $ Mixed [setAmountPrecision maxprecision $ negate $ targetcommodityamount]
|
||||||
|
else Just $ UnitPrice $ Mixed [setAmountPrecision maxprecision $ negate $ targetcommodityamount `divideAmount` (quantity unpricedamount)]
|
||||||
|
| otherwise = Nothing
|
||||||
|
where
|
||||||
|
unpricedcommodity = head $ filter (`elem` (map commodity rsumamounts)) rcommoditiesinorder
|
||||||
|
unpricedamount = head $ filter ((==unpricedcommodity).commodity) rsumamounts
|
||||||
|
targetcommodityamount = head $ filter ((/=unpricedcommodity).commodity) rsumamounts
|
||||||
|
ramountsinunpricedcommodity = filter ((==unpricedcommodity).commodity) ramountsinorder
|
||||||
|
inferprice p = p
|
||||||
|
|
||||||
|
-- maybe infer prices for balanced virtual postings. Just duplicates the above for now.
|
||||||
|
bvmixedamountsinorder = map pamount $ balancedVirtualPostings t''
|
||||||
|
bvamountsinorder = concatMap amounts bvmixedamountsinorder
|
||||||
|
bvcommoditiesinorder = map commodity bvamountsinorder
|
||||||
|
bvsumamounts = amounts $ sum bvmixedamountsinorder
|
||||||
|
t''' = if length bvsumamounts == 2 && all (isNothing.price) bvsumamounts && t'==t -- XXX could check specifically for bv amount inferring
|
||||||
|
then t''{tpostings=map inferprice ps}
|
||||||
|
else t''
|
||||||
|
where
|
||||||
|
inferprice p@Posting{pamount=Mixed [a@Amount{commodity=c,price=Nothing}], ptype=BalancedVirtualPosting}
|
||||||
|
= p{pamount=Mixed [a{price=conversionprice c}]}
|
||||||
|
where
|
||||||
|
conversionprice c | c == unpricedcommodity
|
||||||
|
= if length bvamountsinunpricedcommodity == 1
|
||||||
|
then Just $ TotalPrice $ Mixed [setAmountPrecision maxprecision $ negate $ targetcommodityamount]
|
||||||
|
else Just $ UnitPrice $ Mixed [setAmountPrecision maxprecision $ negate $ targetcommodityamount `divideAmount` (quantity unpricedamount)]
|
||||||
|
| otherwise = Nothing
|
||||||
|
where
|
||||||
|
unpricedcommodity = head $ filter (`elem` (map commodity bvsumamounts)) bvcommoditiesinorder
|
||||||
|
unpricedamount = head $ filter ((==unpricedcommodity).commodity) bvsumamounts
|
||||||
|
targetcommodityamount = head $ filter ((/=unpricedcommodity).commodity) bvsumamounts
|
||||||
|
bvamountsinunpricedcommodity = filter ((==unpricedcommodity).commodity) bvamountsinorder
|
||||||
|
inferprice p = p
|
||||||
|
|
||||||
printerr s = intercalate "\n" [s, showTransactionUnelided t]
|
printerr s = intercalate "\n" [s, showTransactionUnelided t]
|
||||||
|
|
||||||
nonzerobalanceerror :: Transaction -> String
|
nonzerobalanceerror :: Transaction -> String
|
||||||
@ -172,7 +230,6 @@ nonzerobalanceerror t = printf "could not balance this transaction (%s%s%s)" rms
|
|||||||
journalTransactionWithDate :: WhichDate -> Transaction -> Transaction
|
journalTransactionWithDate :: WhichDate -> Transaction -> Transaction
|
||||||
journalTransactionWithDate ActualDate t = t
|
journalTransactionWithDate ActualDate t = t
|
||||||
journalTransactionWithDate EffectiveDate t = txnTieKnot t{tdate=fromMaybe (tdate t) (teffectivedate t)}
|
journalTransactionWithDate EffectiveDate t = txnTieKnot t{tdate=fromMaybe (tdate t) (teffectivedate t)}
|
||||||
|
|
||||||
|
|
||||||
-- | Ensure a transaction's postings refer back to it.
|
-- | Ensure a transaction's postings refer back to it.
|
||||||
txnTieKnot :: Transaction -> Transaction
|
txnTieKnot :: Transaction -> Transaction
|
||||||
@ -268,25 +325,39 @@ tests_Hledger_Data_Transaction = TestList [
|
|||||||
assertBool "detect unbalanced entry, sign error"
|
assertBool "detect unbalanced entry, sign error"
|
||||||
(isLeft $ balanceTransaction Nothing
|
(isLeft $ balanceTransaction Nothing
|
||||||
(Transaction (parsedate "2007/01/28") Nothing False "" "test" "" []
|
(Transaction (parsedate "2007/01/28") Nothing False "" "test" "" []
|
||||||
[Posting False "a" (Mixed [dollars 1]) "" RegularPosting [] Nothing,
|
[Posting False "a" (Mixed [dollars 1]) "" RegularPosting [] Nothing,
|
||||||
Posting False "b" (Mixed [dollars 1]) "" RegularPosting [] Nothing
|
Posting False "b" (Mixed [dollars 1]) "" RegularPosting [] Nothing
|
||||||
] ""))
|
] ""))
|
||||||
assertBool "detect unbalanced entry, multiple missing amounts"
|
assertBool "detect unbalanced entry, multiple missing amounts"
|
||||||
(isLeft $ balanceTransaction Nothing
|
(isLeft $ balanceTransaction Nothing
|
||||||
(Transaction (parsedate "2007/01/28") Nothing False "" "test" "" []
|
(Transaction (parsedate "2007/01/28") Nothing False "" "test" "" []
|
||||||
[Posting False "a" missingamt "" RegularPosting [] Nothing,
|
[Posting False "a" missingamt "" RegularPosting [] Nothing,
|
||||||
Posting False "b" missingamt "" RegularPosting [] Nothing
|
Posting False "b" missingamt "" RegularPosting [] Nothing
|
||||||
] ""))
|
] ""))
|
||||||
let e = balanceTransaction Nothing (Transaction (parsedate "2007/01/28") Nothing False "" "test" "" []
|
let e = balanceTransaction Nothing (Transaction (parsedate "2007/01/28") Nothing False "" "" "" []
|
||||||
[Posting False "a" (Mixed [dollars 1]) "" RegularPosting [] Nothing,
|
[Posting False "a" (Mixed [dollars 1]) "" RegularPosting [] Nothing,
|
||||||
Posting False "b" missingamt "" RegularPosting [] Nothing
|
Posting False "b" missingamt "" RegularPosting [] Nothing
|
||||||
] "")
|
] "")
|
||||||
assertBool "one missing amount should be ok" (isRight e)
|
assertBool "balanceTransaction allows one missing amount" (isRight e)
|
||||||
assertEqual "balancing amount is added"
|
assertEqual "balancing amount is inferred"
|
||||||
(Mixed [dollars (-1)])
|
(Mixed [dollars (-1)])
|
||||||
(case e of
|
(case e of
|
||||||
Right e' -> (pamount $ last $ tpostings e')
|
Right e' -> (pamount $ last $ tpostings e')
|
||||||
Left _ -> error' "should not happen")
|
Left _ -> error' "should not happen")
|
||||||
|
let e = balanceTransaction Nothing (Transaction (parsedate "2011/01/01") Nothing False "" "" "" []
|
||||||
|
[Posting False "a" (Mixed [dollars 1.35]) "" RegularPosting [] Nothing,
|
||||||
|
Posting False "b" (Mixed [euros (-1)]) "" RegularPosting [] Nothing
|
||||||
|
] "")
|
||||||
|
assertBool "balanceTransaction can infer conversion price" (isRight e)
|
||||||
|
assertEqual "balancing conversion price is inferred"
|
||||||
|
(Mixed [Amount{commodity=dollar{precision=2},
|
||||||
|
quantity=1.35,
|
||||||
|
price=(Just $ TotalPrice $ Mixed [Amount{commodity=euro{precision=maxprecision},
|
||||||
|
quantity=1,
|
||||||
|
price=Nothing}])}])
|
||||||
|
(case e of
|
||||||
|
Right e' -> (pamount $ head $ tpostings e')
|
||||||
|
Left _ -> error' "should not happen")
|
||||||
|
|
||||||
,"isTransactionBalanced" ~: do
|
,"isTransactionBalanced" ~: do
|
||||||
let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" []
|
let t = Transaction (parsedate "2009/01/01") Nothing False "" "a" "" []
|
||||||
|
|||||||
123
tests/prices.test
Normal file
123
tests/prices.test
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
# price-related tests
|
||||||
|
# 1. print a transaction with an explicit unit price
|
||||||
|
bin/hledger -f- print
|
||||||
|
<<<
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency €100 @ $1.35
|
||||||
|
assets
|
||||||
|
>>>
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency €100 @ $1.35
|
||||||
|
assets €-100 @ $1.35
|
||||||
|
|
||||||
|
# 2. convert to cost basis
|
||||||
|
bin/hledger -f- print -B
|
||||||
|
<<<
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency €100 @ $1.35
|
||||||
|
assets
|
||||||
|
>>>
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency $135.00
|
||||||
|
assets $-135.00
|
||||||
|
|
||||||
|
# 3. with a historical price directive
|
||||||
|
bin/hledger -f- print -B
|
||||||
|
<<<
|
||||||
|
P 2010/12/31 € $1.34
|
||||||
|
P 2011/01/01 € $1.35
|
||||||
|
P 2011/01/02 € $1.36
|
||||||
|
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency €100
|
||||||
|
assets
|
||||||
|
|
||||||
|
>>>
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency $135.00
|
||||||
|
assets $-135.00
|
||||||
|
|
||||||
|
# 4. with a total price
|
||||||
|
bin/hledger -f - print
|
||||||
|
<<<
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency €100 @@ $135
|
||||||
|
assets
|
||||||
|
>>>
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency €100 @@ $135
|
||||||
|
assets €-100 @@ $135
|
||||||
|
|
||||||
|
# 5. when the balance has exactly two commodities, both unpriced, infer an
|
||||||
|
# implicit conversion price for the first one in terms of the second.
|
||||||
|
bin/hledger -f - print
|
||||||
|
<<<
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency €100
|
||||||
|
misc $2.1
|
||||||
|
assets $-135.00
|
||||||
|
misc €1
|
||||||
|
misc €-1
|
||||||
|
misc $-2.1
|
||||||
|
>>>
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency €100 @ $1.35
|
||||||
|
misc $2.10
|
||||||
|
assets $-135.00
|
||||||
|
misc €1 @ $1.35
|
||||||
|
misc €-1 @ $1.35
|
||||||
|
misc $-2.10
|
||||||
|
|
||||||
|
# # 6. when the *cost-basis* balance has exactly two commodities, both
|
||||||
|
# # unpriced, infer an implicit conversion price for the first one in terms
|
||||||
|
# # of the second.
|
||||||
|
# bin/hledger -f - print
|
||||||
|
# <<<
|
||||||
|
# 2011/01/01
|
||||||
|
# expenses:foreign currency €100
|
||||||
|
# assets $-135.00
|
||||||
|
# misc $3.1 @ 2 bob
|
||||||
|
# misc $-3.1 @ 2 bob
|
||||||
|
# misc £1 @@ 2 shekels
|
||||||
|
# misc £-1 @@ 2 shekels
|
||||||
|
# >>>
|
||||||
|
# 2011/01/01
|
||||||
|
# expenses:foreign currency €100 @ $1.35
|
||||||
|
# assets €-100 @ $1.35
|
||||||
|
# misc $3.1 @ 2 bob
|
||||||
|
# misc $-3.1 @ 2 bob
|
||||||
|
# misc £1 @@ 2 shekels
|
||||||
|
# misc £-1 @@ 2 shekels
|
||||||
|
#
|
||||||
|
## 7. another, from ledger tests. Just one posting to price so uses @@.
|
||||||
|
bin/hledger -f - print
|
||||||
|
<<<
|
||||||
|
2002/09/30 * 1a1a6305d06ce4b284dba0d267c23f69d70c20be
|
||||||
|
c56a21d23a6535184e7152ee138c28974f14280c 866.231000 GGGGG
|
||||||
|
a35e82730cf91569c302b313780e5895f75a62b9 $-17,783.72
|
||||||
|
>>>
|
||||||
|
2002/09/30 * 1a1a6305d06ce4b284dba0d267c23f69d70c20be
|
||||||
|
c56a21d23a6535184e7152ee138c28974f14280c 866.231000 GGGGG @@ $17,783.72
|
||||||
|
a35e82730cf91569c302b313780e5895f75a62b9 $-17,783.72
|
||||||
|
|
||||||
|
# 8. when the balance has more than two commodities, don't bother
|
||||||
|
bin/hledger -f - print
|
||||||
|
<<<
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency €100
|
||||||
|
assets $-135
|
||||||
|
expenses:other £200
|
||||||
|
>>>= !0
|
||||||
|
# 9. another
|
||||||
|
bin/hledger -f - balance -B
|
||||||
|
<<<
|
||||||
|
2011/01/01
|
||||||
|
expenses:foreign currency €99
|
||||||
|
assets $-130
|
||||||
|
expenses:foreign currency €1
|
||||||
|
assets $-5
|
||||||
|
>>>
|
||||||
|
$-135 assets
|
||||||
|
$135 expenses:foreign currency
|
||||||
|
--------------------
|
||||||
|
$0
|
||||||
@ -1,66 +0,0 @@
|
|||||||
# price-related tests
|
|
||||||
# 1. print a transaction with an explicit unit price
|
|
||||||
bin/hledger -f- print
|
|
||||||
<<<
|
|
||||||
2011/01/01
|
|
||||||
expenses:foreign currency €100 @ $1.35
|
|
||||||
assets
|
|
||||||
>>>
|
|
||||||
2011/01/01
|
|
||||||
expenses:foreign currency €100 @ $1.35
|
|
||||||
assets €-100 @ $1.35
|
|
||||||
|
|
||||||
# 2. convert to cost basis
|
|
||||||
bin/hledger -f- print -B
|
|
||||||
<<<
|
|
||||||
2011/01/01
|
|
||||||
expenses:foreign currency €100 @ $1.35
|
|
||||||
assets
|
|
||||||
>>>
|
|
||||||
2011/01/01
|
|
||||||
expenses:foreign currency $135.00
|
|
||||||
assets $-135.00
|
|
||||||
|
|
||||||
# 2. with a historical price directive
|
|
||||||
bin/hledger -f- print -B
|
|
||||||
<<<
|
|
||||||
P 2010/12/31 € $1.34
|
|
||||||
P 2011/01/01 € $1.35
|
|
||||||
P 2011/01/02 € $1.36
|
|
||||||
|
|
||||||
2011/01/01
|
|
||||||
expenses:foreign currency €100
|
|
||||||
assets
|
|
||||||
|
|
||||||
>>>
|
|
||||||
2011/01/01
|
|
||||||
expenses:foreign currency $135.00
|
|
||||||
assets $-135.00
|
|
||||||
|
|
||||||
# 3. with a total price
|
|
||||||
bin/hledger -f - print
|
|
||||||
<<<
|
|
||||||
2011/01/01
|
|
||||||
expenses:foreign currency €100 @@ $135
|
|
||||||
assets
|
|
||||||
>>>
|
|
||||||
2011/01/01
|
|
||||||
expenses:foreign currency €100 @@ $135
|
|
||||||
assets €-100 @@ $135
|
|
||||||
|
|
||||||
# 4. with an implicit price
|
|
||||||
# bin/hledger -f - print
|
|
||||||
# <<<
|
|
||||||
# 2011/01/01
|
|
||||||
# expenses:foreign currency €100 @ $1.35
|
|
||||||
# assets $-135.00
|
|
||||||
# >>>
|
|
||||||
# 2011/01/01
|
|
||||||
# expenses:foreign currency €100 @ $1.35
|
|
||||||
# assets
|
|
||||||
#
|
|
||||||
# 2009/1/1 opening balance
|
|
||||||
# Assets:Brokerage 1 AAPL
|
|
||||||
# Assets:Checking $-20.00
|
|
||||||
#
|
|
||||||
# >>>= 0
|
|
||||||
Loading…
Reference in New Issue
Block a user