diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,6 +1,10 @@
 Internal/api/developer-ish changes in the hledger-lib (and hledger) packages.
 For user-visible changes, see the hledger package changelog.
 
+# 1.18.1 2020-06-21
+
+- fix some doc typos (Martin Michlmayr)
+
 # 1.18 2020-06-07
 
 - added: getHledgerCliOpts', takes an explicit argument list
diff --git a/Hledger/Data/Journal.hs b/Hledger/Data/Journal.hs
--- a/Hledger/Data/Journal.hs
+++ b/Hledger/Data/Journal.hs
@@ -179,18 +179,18 @@
     ,jparseparentaccounts       = jparseparentaccounts       j2
     ,jparsealiases              = jparsealiases              j2
     -- ,jparsetransactioncount     = jparsetransactioncount     j1 +  jparsetransactioncount     j2
-    ,jparsetimeclockentries     = jparsetimeclockentries j1 <> jparsetimeclockentries j2
-    ,jincludefilestack          = jincludefilestack          j2
+    ,jparsetimeclockentries     = jparsetimeclockentries     j1 <> jparsetimeclockentries     j2
+    ,jincludefilestack          = jincludefilestack j2
     ,jdeclaredaccounts          = jdeclaredaccounts          j1 <> jdeclaredaccounts          j2
     ,jdeclaredaccounttypes      = jdeclaredaccounttypes      j1 <> jdeclaredaccounttypes      j2
     ,jcommodities               = jcommodities               j1 <> jcommodities               j2
     ,jinferredcommodities       = jinferredcommodities       j1 <> jinferredcommodities       j2
-    ,jpricedirectives              = jpricedirectives              j1 <> jpricedirectives              j2
-    ,jtransactionimpliedmarketprices = jtransactionimpliedmarketprices j1 <> jtransactionimpliedmarketprices j2
+    ,jpricedirectives           = jpricedirectives           j1 <> jpricedirectives           j2
+    ,jinferredmarketprices      = jinferredmarketprices      j1 <> jinferredmarketprices      j2
     ,jtxnmodifiers              = jtxnmodifiers              j1 <> jtxnmodifiers              j2
     ,jperiodictxns              = jperiodictxns              j1 <> jperiodictxns              j2
     ,jtxns                      = jtxns                      j1 <> jtxns                      j2
-    ,jfinalcommentlines         = jfinalcommentlines         j2  -- XXX discards j1's ?
+    ,jfinalcommentlines         = jfinalcommentlines j2  -- XXX discards j1's ?
     ,jfiles                     = jfiles                     j1 <> jfiles                     j2
     ,jlastreadtime              = max (jlastreadtime j1) (jlastreadtime j2)
     }
@@ -211,8 +211,8 @@
   ,jdeclaredaccounttypes      = M.empty
   ,jcommodities               = M.empty
   ,jinferredcommodities       = M.empty
-  ,jpricedirectives              = []
-  ,jtransactionimpliedmarketprices = []
+  ,jpricedirectives           = []
+  ,jinferredmarketprices      = []
   ,jtxnmodifiers              = []
   ,jperiodictxns              = []
   ,jtxns                      = []
@@ -1044,16 +1044,16 @@
 -- been balanced and posting amounts have appropriate prices attached.
 journalInferMarketPricesFromTransactions :: Journal -> Journal
 journalInferMarketPricesFromTransactions j =
-  j{jtransactionimpliedmarketprices =
-       dbg4 "jtransactionimpliedmarketprices" $
-       mapMaybe postingImpliedMarketPrice $ journalPostings j
+  j{jinferredmarketprices =
+       dbg4 "jinferredmarketprices" $
+       mapMaybe postingInferredmarketPrice $ journalPostings j
    }
 
 -- | Make a market price equivalent to this posting's amount's unit
 -- price, if any. If the posting amount is multicommodity, only the
 -- first commodity amount is considered.
-postingImpliedMarketPrice :: Posting -> Maybe MarketPrice
-postingImpliedMarketPrice p@Posting{pamount} =
+postingInferredmarketPrice :: Posting -> Maybe MarketPrice
+postingInferredmarketPrice p@Posting{pamount} =
   -- convert any total prices to unit prices
   case mixedAmountTotalPriceToUnitPrice pamount of
     Mixed ( Amount{acommodity=fromcomm, aprice = Just (UnitPrice Amount{acommodity=tocomm, aquantity=rate})} : _) ->
diff --git a/Hledger/Data/Types.hs b/Hledger/Data/Types.hs
--- a/Hledger/Data/Types.hs
+++ b/Hledger/Data/Types.hs
@@ -470,9 +470,9 @@
   ,jdeclaredaccounts      :: [(AccountName,AccountDeclarationInfo)] -- ^ Accounts declared by account directives, in parse order (after journal finalisation)
   ,jdeclaredaccounttypes  :: M.Map AccountType [AccountName]        -- ^ Accounts whose type has been declared in account directives (usually 5 top-level accounts)
   ,jcommodities           :: M.Map CommoditySymbol Commodity        -- ^ commodities and formats declared by commodity directives
-  ,jinferredcommodities   :: M.Map CommoditySymbol AmountStyle      -- ^ commodities and formats inferred from journal amounts  TODO misnamed - jusedstyles
+  ,jinferredcommodities   :: M.Map CommoditySymbol AmountStyle      -- ^ commodities and formats inferred from journal amounts  TODO misnamed, should be eg jusedstyles
   ,jpricedirectives       :: [PriceDirective]                       -- ^ Declarations of market prices by P directives, in parse order (after journal finalisation)
-  ,jtransactionimpliedmarketprices :: [MarketPrice]                 -- ^ Market prices implied by transactions, in parse order (after journal finalisation)
+  ,jinferredmarketprices  :: [MarketPrice]                          -- ^ Market prices implied by transactions, in parse order (after journal finalisation)
   ,jtxnmodifiers          :: [TransactionModifier]
   ,jperiodictxns          :: [PeriodicTransaction]
   ,jtxns                  :: [Transaction]
diff --git a/Hledger/Data/Valuation.hs b/Hledger/Data/Valuation.hs
--- a/Hledger/Data/Valuation.hs
+++ b/Hledger/Data/Valuation.hs
@@ -52,6 +52,17 @@
 ------------------------------------------------------------------------------
 -- Types
 
+-- | What kind of value conversion should be done on amounts ?
+-- CLI: --value=cost|then|end|now|DATE[,COMM]
+data ValuationType =
+    AtCost     (Maybe CommoditySymbol)  -- ^ convert to cost commodity using transaction prices, then optionally to given commodity using market prices at posting date
+  | AtThen     (Maybe CommoditySymbol)  -- ^ convert to default or given valuation commodity, using market prices at each posting's date
+  | AtEnd      (Maybe CommoditySymbol)  -- ^ convert to default or given valuation commodity, using market prices at period end(s)
+  | AtNow      (Maybe CommoditySymbol)  -- ^ convert to default or given valuation commodity, using current market prices
+  | AtDate Day (Maybe CommoditySymbol)  -- ^ convert to default or given valuation commodity, using market prices on some date
+  | AtDefault  (Maybe CommoditySymbol)  -- ^ works like AtNow in single period reports, like AtEnd in multiperiod reports
+  deriving (Show,Data,Eq) -- Typeable
+
 -- | A snapshot of the known exchange rates between commodity pairs at a given date,
 -- as a graph allowing fast lookup and path finding, along with some helper data.
 data PriceGraph = PriceGraph {
@@ -60,9 +71,9 @@
     -- Node labels are commodities and edge labels are exchange rates,
     -- which were either:
     -- declared by P directives,
-    -- implied by transaction prices,
+    -- inferred from transaction prices,
     -- inferred by reversing a declared rate,
-    -- or inferred by reversing a transaction-implied rate.
+    -- or inferred by reversing a transaction-inferred rate.
     -- There will be at most one edge between each directed pair of commodities,
     -- eg there can be one USD->EUR and one EUR->USD.
   ,prNodemap :: NodeMap CommoditySymbol
@@ -71,7 +82,7 @@
     -- ^ The default valuation commodity for each source commodity.
     --   These are used when a valuation commodity is not specified
     --   (-V). They are the destination commodity of the latest
-    --   (declared or transaction-implied, but not reverse) each
+    --   (declared or inferred, but not reverse) each
     --   source commodity's latest market price (on the date of this
     --   graph).
   }
@@ -79,25 +90,38 @@
 
 instance NFData PriceGraph
 
--- | A price oracle is a magic function that looks up market prices
--- (exchange rates) from one commodity to another (or if unspecified,
--- to a default valuation commodity) on a given date, somewhat efficiently.
+-- | 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
+-- given date.
 type PriceOracle = (Day, CommoditySymbol, Maybe CommoditySymbol) -> Maybe (CommoditySymbol, Quantity)
 
--- | What kind of value conversion should be done on amounts ?
--- CLI: --value=cost|then|end|now|DATE[,COMM]
-data ValuationType =
-    AtCost     (Maybe CommoditySymbol)  -- ^ convert to cost commodity using transaction prices, then optionally to given commodity using market prices at posting date
-  | AtThen     (Maybe CommoditySymbol)  -- ^ convert to default or given valuation commodity, using market prices at each posting's date
-  | AtEnd      (Maybe CommoditySymbol)  -- ^ convert to default or given valuation commodity, using market prices at period end(s)
-  | AtNow      (Maybe CommoditySymbol)  -- ^ convert to default or given valuation commodity, using current market prices
-  | AtDate Day (Maybe CommoditySymbol)  -- ^ convert to default or given valuation commodity, using market prices on some date
-  | AtDefault  (Maybe CommoditySymbol)  -- ^ works like AtNow in single period reports, like AtEnd in multiperiod reports
-  deriving (Show,Data,Eq) -- Typeable
+-- | Generate a price oracle (memoising price lookup function) from a
+-- journal's directive-declared and transaction-inferred market
+-- prices. For best performance, generate this only once per journal,
+-- reusing it across reports if there are more than one, as
+-- compoundBalanceCommand does.
+-- The boolean argument is whether to infer market prices from
+-- transactions or not.
+journalPriceOracle :: Bool -> Journal -> PriceOracle
+journalPriceOracle infer Journal{jpricedirectives, jinferredmarketprices} =
+  let
+    declaredprices = map priceDirectiveToMarketPrice jpricedirectives
+    inferredprices = if infer then jinferredmarketprices else []
+    makepricegraph = memo $ makePriceGraph declaredprices inferredprices
+  in
+    memo $ uncurry3 $ priceLookup makepricegraph
 
+priceDirectiveToMarketPrice :: PriceDirective -> MarketPrice
+priceDirectiveToMarketPrice PriceDirective{..} =
+  MarketPrice{ mpdate = pddate
+             , mpfrom = pdcommodity
+             , mpto   = acommodity pdamount
+             , mprate = aquantity pdamount
+             }
 
 ------------------------------------------------------------------------------
--- Valuation
+-- Converting things to value
 
 -- | Apply a specified valuation to this mixed amount, using the
 -- provided price oracle, commodity styles, reference dates, and
@@ -135,8 +159,8 @@
 -- use postingApplyValuation for that.
 -- 
 -- This is all a bit complicated. See the reference doc at
--- https://hledger.org/hledger.html#effect-of-value-on-reports
--- (hledger_options.m4.md "Effect of --value on reports"), and #1083.
+-- https://hledger.org/hledger.html#effect-of-valuation-on-reports
+-- (hledger_options.m4.md "Effect of valuation on reports"), and #1083.
 --
 amountApplyValuation :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Day -> Maybe Day -> Day -> Bool -> ValuationType -> Amount -> Amount
 amountApplyValuation priceoracle styles periodlast mreportlast today ismultiperiod v a =
@@ -189,76 +213,33 @@
 ------------------------------------------------------------------------------
 -- Market price lookup
 
--- From a journal's directive-declared and transaction-implied market
--- prices, generate a memoising function that efficiently looks up
--- exchange rates between commodities on any date. For best performance,
--- you should generate this only once per journal, reusing it across
--- reports if there are more than one (as in compoundBalanceCommand).
-journalPriceOracle :: Journal -> PriceOracle
-journalPriceOracle Journal{jpricedirectives, jtransactionimpliedmarketprices} =
-  -- traceStack "journalPriceOracle" $
-  let
-    pricesatdate =
-      memo $
-      pricesAtDate jpricedirectives jtransactionimpliedmarketprices
-  in
-    memo $
-    uncurry3 $
-    priceLookup pricesatdate
-
--- | Given a list of price directives in parse order, find the market
--- value at the given date of one unit of a given source commodity, in
--- a different specified valuation commodity, or a default valuation
--- commodity.
---
--- When the valuation commodity is specified, this looks for an
--- exchange rate (market price) calculated in any of the following
--- ways, in order of preference:
---
--- 1. a declared market price (DMP) - a P directive giving the
---    exchange rate from source commodity to valuation commodity
---
--- 2. a transaction-implied market price (TMP) - a market price
---    equivalent to the transaction price used in the latest
---    transaction from source commodity to valuation commodity
---    (on or before the valuation date)
---
--- 3. a reverse declared market price (RDMP) - calculated by inverting
---    a DMP
---
--- 4. a reverse transaction-implied market price (RTMP) - calculated
---    by inverting a TMP
---
--- 5. an indirect market price (IMP) - calculated by combining the
---    shortest chain of market prices (any of the above types) leading
---    from source commodity to valuation commodity.
---
--- When the valuation commodity is not specified, this looks for the
--- latest applicable declared or transaction-implied price, and
--- converts to the commodity mentioned in that price (the default
--- valuation commodity).
---
--- Note this default valuation commodity can vary across successive
--- calls for different dates, since it depends on the price
--- declarations in each period.
+-- | Given a memoising price graph generator, a valuation date, a
+-- source commodity and an optional valuation commodity, find the
+-- value on that date of one unit of the source commodity in the
+-- valuation commodity, or in a default valuation commodity. Returns
+-- the valuation commodity that was specified or chosen, and the
+-- quantity of it that one unit of the source commodity is worth. Or
+-- if no applicable market price can be found or calculated, or if the
+-- source commodity and the valuation commodity are the same, returns
+-- Nothing.
 --
--- This returns the valuation commodity that was specified or
--- inferred, and the quantity of it that one unit of the source
--- commodity is worth. Or if no applicable market price or chain of
--- prices can be found, or the source commodity and the valuation
--- commodity are the same, returns Nothing.
+-- See makePriceGraph for how prices are determined.
+-- Note that both market prices and default valuation commodities can
+-- vary with valuation date, since that determines which market prices
+-- are visible.
 --
 priceLookup :: (Day -> PriceGraph) -> Day -> CommoditySymbol -> Maybe CommoditySymbol -> Maybe (CommoditySymbol, Quantity)
-priceLookup pricesatdate d from mto =
+priceLookup makepricegraph d from mto =
   -- trace ("priceLookup ("++show d++", "++show from++", "++show mto++")") $
   let
     -- build a graph of the commodity exchange rates in effect on this day
     -- XXX should hide these fgl details better
-    PriceGraph{prGraph=g, prNodemap=m, prDefaultValuationCommodities=defaultdests} = pricesatdate d
+    PriceGraph{prGraph=g, prNodemap=m, prDefaultValuationCommodities=defaultdests} =
+      traceAt 1 ("valuation date: "++show d) $ makepricegraph d
     fromnode = node m from
     mto' = mto <|> mdefaultto
       where
-        mdefaultto = dbg4 ("default valuation commodity for "++T.unpack from) $
+        mdefaultto = dbg1 ("default valuation commodity for "++T.unpack from) $
                      M.lookup from defaultdests
   in
     case mto' of
@@ -276,18 +257,17 @@
             case sp fromnode tonode g :: Maybe [Node] of
               Nothing    -> Nothing
               Just nodes ->
-                dbg ("market price "++intercalate "->" (map T.unpack comms)) $
+                dbg ("market price for "++intercalate " -> " (map T.unpack comms)) $
                 Just $ product $ pathEdgeLabels g nodes  -- convert to a single exchange rate
                 where comms = catMaybes $ map (lab g) nodes
 
           -- log a message and a Maybe Quantity, hiding Just/Nothing and limiting decimal places
-          dbg msg = dbg4With (((msg++": ")++) . maybe "" (show . roundTo 8))
+          dbg msg = dbg1With (((msg++": ")++) . maybe "" (show . roundTo 8))
 
 tests_priceLookup =
   let
     d = parsedate
-    a q c = amount{acommodity=c, aquantity=q}
-    p date from q to = PriceDirective{pddate=d date, pdcommodity=from, pdamount=a q to}
+    p date from q to = MarketPrice{mpdate=d date, mpfrom=from, mpto=to, mprate=q}
     ps1 = [
        p "2000/01/01" "A" 10 "B"
       ,p "2000/01/01" "B" 10 "C"
@@ -295,78 +275,113 @@
       ,p "2000/01/01" "E"  2 "D"
       ,p "2001/01/01" "A" 11 "B"
       ]
-    pricesatdate = pricesAtDate ps1 []
+    makepricegraph = makePriceGraph ps1 []
   in test "priceLookup" $ do
-    priceLookup pricesatdate (d "1999/01/01") "A" Nothing    @?= Nothing
-    priceLookup pricesatdate (d "2000/01/01") "A" Nothing    @?= Just ("B",10)
-    priceLookup pricesatdate (d "2000/01/01") "B" (Just "A") @?= Just ("A",0.1)
-    priceLookup pricesatdate (d "2000/01/01") "A" (Just "E") @?= Just ("E",500)
-
-------------------------------------------------------------------------------
--- Building the price graph (network of commodity conversions) on a given day.
+    priceLookup makepricegraph (d "1999/01/01") "A" Nothing    @?= Nothing
+    priceLookup makepricegraph (d "2000/01/01") "A" Nothing    @?= Just ("B",10)
+    priceLookup makepricegraph (d "2000/01/01") "B" (Just "A") @?= Just ("A",0.1)
+    priceLookup makepricegraph (d "2000/01/01") "A" (Just "E") @?= Just ("E",500)
 
--- | Convert a list of market price directives in parse order, and a
--- list of transaction-implied market prices in parse order, to a
--- graph of the effective exchange rates between commodity pairs on
--- the given day.
-pricesAtDate :: [PriceDirective] -> [MarketPrice] -> Day -> PriceGraph
-pricesAtDate pricedirectives transactionimpliedmarketprices d =
-  -- trace ("pricesAtDate ("++show d++")") $
+-- | Build the graph of commodity conversion prices for a given day.
+-- Converts a list of declared market prices in parse order, and a
+-- list of transaction-inferred market prices in parse order, to a
+-- graph of all known exchange rates between commodity pairs in effect
+-- on that day. Cf hledger.m4.md -> Valuation:
+--
+-- hledger looks for a market price (exchange rate) from commodity A
+-- to commodity B in one or more of these ways, in this order of
+-- preference:
+--
+-- 1. A *declared market price* or *inferred market price*:
+--    A's latest market price in B on or before the valuation date
+--    as declared by a P directive, or (with the `--infer-value` flag)
+--    inferred from transaction prices.
+--   
+-- 2. A *reverse market price*:
+--    the inverse of a declared or inferred market price from B to A.
+-- 
+-- 3. A *chained market price*:
+--    a synthetic price formed by combining the shortest chain of market
+--    prices (any of the above types) leading from A to B.
+--
+-- 1 and 2 form the edges of the price graph, and we can query it for
+-- 3 (which is the reason we use a graph).
+--
+-- We also identify each commodity's default valuation commodity, if
+-- any. For each commodity A, hledger picks a default valuation
+-- commodity as follows, in this order of preference:
+--
+-- 1. The price commodity from the latest declared market price for A
+--    on or before valuation date.
+--
+-- 2. The price commodity from the latest declared market price for A
+--    on any date. (Allows conversion to proceed if there are inferred
+--    prices before the valuation date.)
+--
+-- 3. If there are no P directives at all (any commodity or date), and
+--    the `--infer-value` flag is used, then the price commodity from
+--    the latest transaction price for A on or before valuation date.
+--
+makePriceGraph :: [MarketPrice] -> [MarketPrice] -> Day -> PriceGraph
+makePriceGraph alldeclaredprices allinferredprices d =
+  dbg9 ("makePriceGraph "++show d) $
   PriceGraph{prGraph=g, prNodemap=m, prDefaultValuationCommodities=defaultdests}
   where
-    declaredandimpliedprices = latestPriceForEachPairOn pricedirectives transactionimpliedmarketprices d
+    -- prices in effect on date d, either declared or inferred
+    visibledeclaredprices = filter ((<=d).mpdate) alldeclaredprices
+    visibleinferredprices = filter ((<=d).mpdate) allinferredprices
+    declaredandinferredprices = dbg2 "declaredandinferredprices" $
+      effectiveMarketPrices visibledeclaredprices visibleinferredprices
 
-    -- infer any additional reverse prices not already declared or implied
-    reverseprices =
-      dbg5 "reverseprices" $
-      map marketPriceReverse declaredandimpliedprices \\ declaredandimpliedprices
+    -- infer any additional reverse prices not already declared or inferred
+    reverseprices = dbg2 "reverseprices" $
+      map marketPriceReverse declaredandinferredprices \\ declaredandinferredprices
 
     -- build the graph and associated node map
     (g, m) =
       mkMapGraph
-      (dbg5 "g nodelabels" $ sort allcomms) -- this must include all nodes mentioned in edges
-      (dbg5 "g edges"      $ [(mpfrom, mpto, mprate) | MarketPrice{..} <- prices])
+      (dbg9 "price graph labels" $ sort allcomms) -- this must include all nodes mentioned in edges
+      (dbg9 "price graph edges" $ [(mpfrom, mpto, mprate) | MarketPrice{..} <- prices])
       :: (Gr CommoditySymbol Quantity, NodeMap CommoditySymbol)
       where
-        prices   = declaredandimpliedprices ++ reverseprices
+        prices   = declaredandinferredprices ++ reverseprices
         allcomms = map mpfrom prices
 
-    -- save the forward prices' destinations as the default valuation
-    -- commodity for those source commodities
-    defaultdests = M.fromList [(mpfrom,mpto) | MarketPrice{..} <- declaredandimpliedprices]
+    -- determine a default valuation commodity for each source commodity
+    -- somewhat but not quite like effectiveMarketPrices
+    defaultdests = M.fromList [(mpfrom,mpto) | MarketPrice{..} <- pricesfordefaultcomms]
+      where
+        pricesfordefaultcomms = dbg2 "prices for choosing default valuation commodities, by date then parse order" $
+          ps
+          & zip [1..]  -- label items with their parse order
+          & sortBy (compare `on` (\(parseorder,MarketPrice{..})->(mpdate,parseorder)))  -- sort by increasing date then increasing parse order
+          & map snd    -- discard labels
+          where
+            ps | not $ null visibledeclaredprices = visibledeclaredprices
+               | not $ null alldeclaredprices     = alldeclaredprices
+               | otherwise                        = visibleinferredprices  -- will be null without --infer-value
 
--- From a list of price directives in parse order, and a list of
--- transaction-implied market prices in parse order, get the effective
--- price on the given date for each commodity pair. That is, the
--- latest declared or transaction-implied price dated on or before
--- that day, with declared prices taking precedence.
-latestPriceForEachPairOn :: [PriceDirective] -> [MarketPrice] -> Day -> [MarketPrice]
-latestPriceForEachPairOn pricedirectives transactionimpliedmarketprices d =
-  dbg5 "latestPriceForEachPairOn" $
+-- | Given a list of P-declared market prices in parse order and a
+-- list of transaction-inferred market prices in parse order, select
+-- just the latest prices that are in effect for each commodity pair.
+-- That is, for each commodity pair, the latest price by date then
+-- parse order, with declared prices having precedence over inferred
+-- prices on the same day.
+effectiveMarketPrices :: [MarketPrice] -> [MarketPrice] -> [MarketPrice]
+effectiveMarketPrices declaredprices inferredprices =
   let
-    -- consider only declarations/transactions before the valuation date
-    declaredprices = map priceDirectiveToMarketPrice $ filter ((<=d).pddate) pricedirectives
-    transactionimpliedmarketprices' = filter ((<=d).mpdate) transactionimpliedmarketprices
-    -- label the items with their precedence and then their parse order
-    declaredprices'                  = [(1, i, p) | (i,p) <- zip [1..] declaredprices]
-    transactionimpliedmarketprices'' = [(0, i, p) | (i,p) <- zip [1..] transactionimpliedmarketprices']
+    -- label each item with its same-day precedence, then parse order
+    declaredprices' = [(1, i, p) | (i,p) <- zip [1..] declaredprices]
+    inferredprices' = [(0, i, p) | (i,p) <- zip [1..] inferredprices]
   in
     -- combine
-    declaredprices' ++ transactionimpliedmarketprices''
-    -- sort by newest date then highest precedence then latest parse order
+    declaredprices' ++ inferredprices'
+    -- sort by decreasing date then decreasing precedence then decreasing parse order
     & sortBy (flip compare `on` (\(precedence,parseorder,mp)->(mpdate mp,precedence,parseorder)))
     -- discard the sorting labels
     & map third3
-    -- keep only the first (ie the newest, highest precedence and latest parsed) price for each pair
+    -- keep only the first (ie the newest, highest precedence, latest parsed) price for each pair
     & nubSortBy (compare `on` (\(MarketPrice{..})->(mpfrom,mpto)))
-
-priceDirectiveToMarketPrice :: PriceDirective -> MarketPrice
-priceDirectiveToMarketPrice PriceDirective{..} =
-  MarketPrice{ mpdate = pddate
-             , mpfrom = pdcommodity
-             , mpto   = acommodity pdamount
-             , mprate = aquantity pdamount
-             }
 
 marketPriceReverse :: MarketPrice -> MarketPrice
 marketPriceReverse mp@MarketPrice{..} = mp{mpfrom=mpto, mpto=mpfrom, mprate=1/mprate}
diff --git a/Hledger/Read.hs b/Hledger/Read.hs
--- a/Hledger/Read.hs
+++ b/Hledger/Read.hs
@@ -111,7 +111,7 @@
 readJournal iopts mpath txt = do
   let r :: Reader IO =
         fromMaybe JournalReader.reader $ findReader (mformat_ iopts) mpath
-  dbg1IO "trying reader" (rFormat r)
+  dbg7IO "trying reader" (rFormat r)
   (runExceptT . (rReadFn r) iopts (fromMaybe "(string)" mpath)) txt
 
 -- | Read the default journal file specified by the environment, or raise an error.
diff --git a/Hledger/Read/CsvReader.hs b/Hledger/Read/CsvReader.hs
--- a/Hledger/Read/CsvReader.hs
+++ b/Hledger/Read/CsvReader.hs
@@ -382,7 +382,7 @@
           }
 
 blankorcommentlinep :: CsvRulesParser ()
-blankorcommentlinep = lift (dbgparse 3 "trying blankorcommentlinep") >> choiceInState [blanklinep, commentlinep]
+blankorcommentlinep = lift (dbgparse 8 "trying blankorcommentlinep") >> choiceInState [blanklinep, commentlinep]
 
 blanklinep :: CsvRulesParser ()
 blanklinep = lift (skipMany spacenonewline) >> newline >> return () <?> "blank line"
@@ -395,7 +395,7 @@
 
 directivep :: CsvRulesParser (DirectiveName, String)
 directivep = (do
-  lift $ dbgparse 3 "trying directive"
+  lift $ dbgparse 8 "trying directive"
   d <- fmap T.unpack $ choiceInState $ map (lift . string . T.pack) directives
   v <- (((char ':' >> lift (many spacenonewline)) <|> lift (some spacenonewline)) >> directivevalp)
        <|> (optional (char ':') >> lift (skipMany spacenonewline) >> lift eolof >> return "")
@@ -418,7 +418,7 @@
 
 fieldnamelistp :: CsvRulesParser [CsvFieldName]
 fieldnamelistp = (do
-  lift $ dbgparse 3 "trying fieldnamelist"
+  lift $ dbgparse 8 "trying fieldnamelist"
   string "fields"
   optional $ char ':'
   lift (skipSome spacenonewline)
@@ -444,7 +444,7 @@
 
 fieldassignmentp :: CsvRulesParser (HledgerFieldName, FieldTemplate)
 fieldassignmentp = do
-  lift $ dbgparse 3 "trying fieldassignmentp"
+  lift $ dbgparse 8 "trying fieldassignmentp"
   f <- journalfieldnamep
   v <- choiceInState [ assignmentseparatorp >> fieldvalp
                      , lift eolof >> return ""
@@ -454,7 +454,7 @@
 
 journalfieldnamep :: CsvRulesParser String
 journalfieldnamep = do
-  lift (dbgparse 2 "trying journalfieldnamep")
+  lift (dbgparse 8 "trying journalfieldnamep")
   T.unpack <$> choiceInState (map (lift . string . T.pack) journalfieldnames)
 
 maxpostings = 99
@@ -489,7 +489,7 @@
 
 assignmentseparatorp :: CsvRulesParser ()
 assignmentseparatorp = do
-  lift $ dbgparse 3 "trying assignmentseparatorp"
+  lift $ dbgparse 8 "trying assignmentseparatorp"
   _ <- choiceInState [ lift (skipMany spacenonewline) >> char ':' >> lift (skipMany spacenonewline)
                      , lift (skipSome spacenonewline)
                      ]
@@ -497,13 +497,13 @@
 
 fieldvalp :: CsvRulesParser String
 fieldvalp = do
-  lift $ dbgparse 2 "trying fieldvalp"
+  lift $ dbgparse 8 "trying fieldvalp"
   anySingle `manyTill` lift eolof
 
 -- A conditional block: one or more matchers, one per line, followed by one or more indented rules.
 conditionalblockp :: CsvRulesParser ConditionalBlock
 conditionalblockp = do
-  lift $ dbgparse 3 "trying conditionalblockp"
+  lift $ dbgparse 8 "trying conditionalblockp"
   string "if" >> lift (skipMany spacenonewline) >> optional newline
   ms <- some matcherp
   as <- many (try $ lift (skipSome spacenonewline) >> fieldassignmentp)
@@ -520,7 +520,7 @@
 -- A pattern on the whole line, not beginning with a csv field reference.
 recordmatcherp :: CsvRulesParser Matcher
 recordmatcherp = do
-  lift $ dbgparse 2 "trying matcherp"
+  lift $ dbgparse 8 "trying matcherp"
   -- pos <- currentPos
   -- _  <- optional (matchoperatorp >> lift (skipMany spacenonewline) >> optional newline)
   r <- regexp
@@ -535,7 +535,7 @@
 -- %description chez jacques
 fieldmatcherp :: CsvRulesParser Matcher
 fieldmatcherp = do
-  lift $ dbgparse 2 "trying fieldmatcher"
+  lift $ dbgparse 8 "trying fieldmatcher"
   -- An optional fieldname (default: "all")
   -- f <- fromMaybe "all" `fmap` (optional $ do
   --        f' <- fieldnamep
@@ -551,7 +551,7 @@
 
 csvfieldreferencep :: CsvRulesParser CsvFieldReference
 csvfieldreferencep = do
-  lift $ dbgparse 3 "trying csvfieldreferencep"
+  lift $ dbgparse 8 "trying csvfieldreferencep"
   char '%'
   f <- fieldnamep
   return $ '%' : quoteIfNeeded f
@@ -559,7 +559,7 @@
 -- A single regular expression
 regexp :: CsvRulesParser RegexpPattern
 regexp = do
-  lift $ dbgparse 3 "trying regexp"
+  lift $ dbgparse 8 "trying regexp"
   -- notFollowedBy matchoperatorp
   c <- lift nonspace
   cs <- anySingle `manyTill` lift eolof
@@ -606,12 +606,12 @@
   rulestext <-
     if rulesfileexists
     then do
-      dbg1IO "using conversion rules file" rulesfile
+      dbg7IO "using conversion rules file" rulesfile
       readFilePortably rulesfile >>= expandIncludes (takeDirectory rulesfile)
     else
       return $ defaultRulesText rulesfile
   rules <- either throwerr return $ parseAndValidateCsvRules rulesfile rulestext
-  dbg2IO "rules" rules
+  dbg7IO "rules" rules
 
   -- parse the skip directive's value, if any
   let skiplines = case getDirective "skip" rules of
@@ -623,12 +623,12 @@
   -- parsec seems to fail if you pass it "-" here TODO: try again with megaparsec
   let parsecfilename = if csvfile == "-" then "(stdin)" else csvfile
   let separator = fromMaybe ',' (getDirective "separator" rules >>= parseSeparator)
-  dbg2IO "separator" separator
+  dbg7IO "separator" separator
   records <- (either throwerr id .
-              dbg2 "validateCsv" . validateCsv rules skiplines .
-              dbg2 "parseCsv")
+              dbg8 "validateCsv" . validateCsv rules skiplines .
+              dbg8 "parseCsv")
              `fmap` parseCsv separator parsecfilename csvdata
-  dbg1IO "first 3 csv records" $ take 3 records
+  dbg7IO "first 3 csv records" $ take 3 records
 
   -- identify header lines
   -- let (headerlines, datalines) = identifyHeaderLines records
@@ -653,10 +653,10 @@
     -- than one date and the first date is more recent than the last):
     -- reverse them to get same-date transactions ordered chronologically.
     txns' =
-      (if newestfirst || mseemsnewestfirst == Just True then reverse else id) txns
+      (if newestfirst || mdataseemsnewestfirst == Just True then reverse else id) txns
       where
-        newestfirst = dbg3 "newestfirst" $ isJust $ getDirective "newest-first" rules
-        mseemsnewestfirst = dbg3 "mseemsnewestfirst" $
+        newestfirst = dbg7 "newestfirst" $ isJust $ getDirective "newest-first" rules
+        mdataseemsnewestfirst = dbg7 "mdataseemsnewestfirst" $
           case nub $ map tdate txns of
             ds | length ds > 1 -> Just $ head ds > last ds
             _                  -> Nothing
@@ -1060,7 +1060,7 @@
 getEffectiveAssignment rules record f = lastMay $ map snd $ assignments
   where
     -- all active assignments to field f, in order
-    assignments = dbg2 "assignments" $ filter ((==f).fst) $ toplevelassignments ++ conditionalassignments
+    assignments = dbg8 "assignments" $ filter ((==f).fst) $ toplevelassignments ++ conditionalassignments
       where
         -- all top level field assignments
         toplevelassignments    = rassignments rules
@@ -1077,20 +1077,20 @@
                 matcherMatches :: Matcher -> Bool
                 matcherMatches (RecordMatcher pat) = regexMatchesCI pat' wholecsvline
                   where
-                    pat' = dbg3 "regex" pat
+                    pat' = dbg8 "regex" pat
                     -- A synthetic whole CSV record to match against. Note, this can be
                     -- different from the original CSV data:
                     -- - any whitespace surrounding field values is preserved
                     -- - any quotes enclosing field values are removed
                     -- - and the field separator is always comma
                     -- which means that a field containing a comma will look like two fields.
-                    wholecsvline = dbg3 "wholecsvline" $ intercalate "," record
+                    wholecsvline = dbg8 "wholecsvline" $ intercalate "," record
                 matcherMatches (FieldMatcher csvfieldref pat) = regexMatchesCI pat csvfieldvalue
                   where
                     -- the value of the referenced CSV field to match against.
-                    csvfieldvalue = dbg3 "csvfieldvalue" $ replaceCsvFieldReference rules record csvfieldref
+                    csvfieldvalue = dbg8 "csvfieldvalue" $ replaceCsvFieldReference rules record csvfieldref
 
--- | Render a field assigment's template, possibly interpolating referenced
+-- | Render a field assignment's template, possibly interpolating referenced
 -- CSV field values. Outer whitespace is removed from interpolated values.
 renderTemplate ::  CsvRules -> CsvRecord -> FieldTemplate -> String
 renderTemplate rules record t = regexReplaceBy "%[A-z0-9_-]+" (replaceCsvFieldReference rules record) t
diff --git a/Hledger/Read/JournalReader.hs b/Hledger/Read/JournalReader.hs
--- a/Hledger/Read/JournalReader.hs
+++ b/Hledger/Read/JournalReader.hs
@@ -296,7 +296,7 @@
       -- on journal. Duplicating readJournal a bit here.
       let r = fromMaybe reader $ findReader Nothing (Just prefixedpath)
           parser = rParser r
-      dbg1IO "trying reader" (rFormat r)
+      dbg7IO "trying reader" (rFormat r)
       updatedChildj <- journalAddFile (filepath, childInput) <$>
                         parseIncludeFile parser initChildj filepath childInput
 
@@ -425,7 +425,7 @@
     pure $ (off, amount)
   lift (skipMany spacenonewline)
   _ <- lift followingcommentp
-  let comm = Commodity{csymbol=acommodity, cformat=Just $ dbg2 "style from commodity directive" astyle}
+  let comm = Commodity{csymbol=acommodity, cformat=Just $ dbg7 "style from commodity directive" astyle}
   if asdecimalpoint astyle == Nothing
   then customFailure $ parseErrorAt off pleaseincludedecimalpoint
   else modify' (\j -> j{jcommodities=M.insert acommodity comm $ jcommodities j})
@@ -469,7 +469,7 @@
     then
       if asdecimalpoint astyle == Nothing
       then customFailure $ parseErrorAt off pleaseincludedecimalpoint
-      else return $ dbg2 "style from format subdirective" astyle
+      else return $ dbg7 "style from format subdirective" astyle
     else customFailure $ parseErrorAt off $
          printf "commodity directive symbol \"%s\" and format directive symbol \"%s\" should be the same" expectedsym acommodity
 
diff --git a/Hledger/Reports/AccountTransactionsReport.hs b/Hledger/Reports/AccountTransactionsReport.hs
--- a/Hledger/Reports/AccountTransactionsReport.hs
+++ b/Hledger/Reports/AccountTransactionsReport.hs
@@ -102,7 +102,7 @@
     ts3 = filter (matchesTransaction thisacctq . filterTransactionPostings (And [realq, statusq])) ts2
 
     -- maybe convert these transactions to cost or value
-    prices = journalPriceOracle j
+    prices = journalPriceOracle (infer_value_ ropts) j
     styles = journalCommodityStyles j
     periodlast =
       fromMaybe (error' "journalApplyValuation: expected a non-empty journal") $ -- XXX shouldn't happen
diff --git a/Hledger/Reports/BalanceReport.hs b/Hledger/Reports/BalanceReport.hs
--- a/Hledger/Reports/BalanceReport.hs
+++ b/Hledger/Reports/BalanceReport.hs
@@ -70,8 +70,9 @@
   (if invert_ then brNegate  else id) $
   (mappedsorteditems, mappedtotal)
     where
-      -- dbg1 = const id -- exclude from debug output
-      dbg1 s = let p = "balanceReport" in Hledger.Utils.dbg1 (p++" "++s)  -- add prefix in debug output
+      -- dbg = const id -- exclude from debug output
+      dbg s = let p = "balanceReport" in Hledger.Utils.dbg4 (p++" "++s)  -- add prefix in debug output
+      dbg' s = let p = "balanceReport" in Hledger.Utils.dbg5 (p++" "++s)  -- add prefix in debug output
 
       -- Get all the summed accounts & balances, according to the query, as an account tree.
       -- If doing cost valuation, amounts will be converted to cost first.
@@ -81,27 +82,31 @@
       -- per hledger_options.m4.md "Effect of --value on reports".
       valuedaccttree = mapAccounts avalue accttree
         where
-          avalue a@Account{..} = a{aebalance=bvalue aebalance, aibalance=bvalue aibalance}
+          avalue a@Account{..} = a{aebalance=maybevalue aebalance, aibalance=maybevalue aibalance}
             where
-              bvalue = maybe id (mixedAmountApplyValuation (journalPriceOracle j) (journalCommodityStyles j) periodlast mreportlast today multiperiod) value_
+              maybevalue = maybe id applyvaluation value_
                 where
-                  periodlast =
-                    fromMaybe (error' "balanceReport: expected a non-empty journal") $ -- XXX shouldn't happen
-                    reportPeriodOrJournalLastDay ropts j
-                  mreportlast = reportPeriodLastDay ropts
-                  today = fromMaybe (error' "balanceReport: could not pick a valuation date, ReportOpts today_ is unset") today_
-                  multiperiod = interval_ /= NoInterval
+                  applyvaluation = mixedAmountApplyValuation priceoracle styles periodlast mreportlast today multiperiod
+                    where
+                      priceoracle = journalPriceOracle infer_value_ j
+                      styles = journalCommodityStyles j
+                      periodlast = fromMaybe
+                                   (error' "balanceReport: expected a non-empty journal") $ -- XXX shouldn't happen
+                                   reportPeriodOrJournalLastDay ropts j
+                      mreportlast = reportPeriodLastDay ropts
+                      today = fromMaybe (error' "balanceReport: could not pick a valuation date, ReportOpts today_ is unset") today_
+                      multiperiod = interval_ /= NoInterval
 
       -- Modify this tree for display - depth limit, boring parents, zeroes - and convert to a list.
       displayaccts :: [Account]
           | queryDepth q == 0 =
-                         dbg1 "displayaccts" $
+                         dbg' "displayaccts" $
                          take 1 $ clipAccountsAndAggregate (queryDepth q) $ flattenAccounts valuedaccttree
-          | flat_ ropts = dbg1 "displayaccts" $
+          | flat_ ropts = dbg' "displayaccts" $
                          filterzeros $
                          filterempty $
                          drop 1 $ clipAccountsAndAggregate (queryDepth q) $ flattenAccounts valuedaccttree
-          | otherwise  = dbg1 "displayaccts" $
+          | otherwise  = dbg' "displayaccts" $
                          filter (not.aboring) $
                          drop 1 $ flattenAccounts $
                          markboring $
@@ -116,7 +121,7 @@
             markboring  = if no_elide_ then id else markBoringParentAccounts
 
       -- Make a report row for each account.
-      items = dbg1 "items" $ map (balanceReportItem ropts q) displayaccts
+      items = dbg "items" $ map (balanceReportItem ropts q) displayaccts
 
       -- Sort report rows (except sorting by amount in tree mode, which was done above).
       sorteditems
@@ -139,17 +144,17 @@
               sortedrows = sortAccountItemsLike sortedanames anamesandrows
 
       -- Calculate the grand total.
-      total | not (flat_ ropts) = dbg1 "total" $ sum [amt | (_,_,indent,amt) <- items, indent == 0]
-            | otherwise         = dbg1 "total" $
+      total | not (flat_ ropts) = dbg "total" $ sum [amt | (_,_,indent,amt) <- items, indent == 0]
+            | otherwise         = dbg "total" $
                                   if flatShowsExclusiveBalance
                                   then sum $ map fourth4 items
                                   else sum $ map aebalance $ clipAccountsAndAggregate 1 displayaccts
       
       -- Calculate percentages if needed.
-      mappedtotal | percent_  = dbg1 "mappedtotal" $ total `perdivide` total
+      mappedtotal | percent_  = dbg "mappedtotal" $ total `perdivide` total
                   | otherwise = total
       mappedsorteditems | percent_ =
-                            dbg1 "mappedsorteditems" $
+                            dbg "mappedsorteditems" $
                             map (\(fname, sname, indent, amount) -> (fname, sname, indent, amount `perdivide` total)) sorteditems
                         | otherwise = sorteditems
 
diff --git a/Hledger/Reports/EntriesReport.hs b/Hledger/Reports/EntriesReport.hs
--- a/Hledger/Reports/EntriesReport.hs
+++ b/Hledger/Reports/EntriesReport.hs
@@ -40,7 +40,7 @@
     tvalue t@Transaction{..} = t{tpostings=map pvalue tpostings}
       where
         pvalue p = maybe p
-          (postingApplyValuation (journalPriceOracle j) (journalCommodityStyles j) periodlast mreportlast today False p)
+          (postingApplyValuation (journalPriceOracle infer_value_ j) (journalCommodityStyles j) periodlast mreportlast today False p)
           value_
           where
             periodlast  = fromMaybe today $ reportPeriodOrJournalLastDay ropts j
diff --git a/Hledger/Reports/MultiBalanceReport.hs b/Hledger/Reports/MultiBalanceReport.hs
--- a/Hledger/Reports/MultiBalanceReport.hs
+++ b/Hledger/Reports/MultiBalanceReport.hs
@@ -72,7 +72,11 @@
 -- hledger's most powerful and useful report, used by the balance
 -- command (in multiperiod mode) and (via multiBalanceReport') by the bs/cf/is commands.
 multiBalanceReport :: Day -> ReportOpts -> Journal -> MultiBalanceReport
-multiBalanceReport today ropts j = multiBalanceReportWith ropts (queryFromOpts today ropts) j (journalPriceOracle j)
+multiBalanceReport today ropts j =
+  multiBalanceReportWith ropts q j (journalPriceOracle infer j)
+  where
+    q = queryFromOpts today ropts
+    infer = infer_value_ ropts
 
 -- | A helper for multiBalanceReport. This one takes an explicit Query
 -- instead of deriving one from ReportOpts, and an extra argument, a
@@ -85,49 +89,52 @@
   (if invert_ then prNegate else id) $
   PeriodicReport colspans mappedsortedrows mappedtotalsrow
     where
-      dbg1 s = let p = "multiBalanceReport" in Hledger.Utils.dbg1 (p++" "++s)  -- add prefix in this function's debug output
-      -- dbg1 = const id  -- exclude this function from debug output
+      -- add a prefix to this function's debug output
+      dbg   s = let p = "multiBalanceReport" in Hledger.Utils.dbg3 (p++" "++s)
+      dbg'  s = let p = "multiBalanceReport" in Hledger.Utils.dbg4 (p++" "++s)
+      dbg'' s = let p = "multiBalanceReport" in Hledger.Utils.dbg5 (p++" "++s)
+      -- dbg = const id  -- exclude this function from debug output
 
       ----------------------------------------------------------------------
       -- 1. Queries, report/column dates.
 
-      symq       = dbg1 "symq"   $ filterQuery queryIsSym $ dbg1 "requested q" q
-      depthq     = dbg1 "depthq" $ filterQuery queryIsDepth q
+      symq       = dbg "symq"   $ filterQuery queryIsSym $ dbg "requested q" q
+      depthq     = dbg "depthq" $ filterQuery queryIsDepth q
       depth      = queryDepth depthq
-      depthless  = dbg1 "depthless" . filterQuery (not . queryIsDepth)
-      datelessq  = dbg1 "datelessq"  $ filterQuery (not . queryIsDateOrDate2) q
+      depthless  = dbg "depthless" . filterQuery (not . queryIsDepth)
+      datelessq  = dbg "datelessq"  $ filterQuery (not . queryIsDateOrDate2) q
       dateqcons  = if date2_ then Date2 else Date
       -- The date span specified by -b/-e/-p options and query args if any.
-      requestedspan  = dbg1 "requestedspan"  $ queryDateSpan date2_ q
+      requestedspan  = dbg "requestedspan"  $ queryDateSpan date2_ q
       -- If the requested span is open-ended, close it using the journal's end dates.
       -- This can still be the null (open) span if the journal is empty.
-      requestedspan' = dbg1 "requestedspan'" $ requestedspan `spanDefaultsFrom` journalDateSpan date2_ j
+      requestedspan' = dbg "requestedspan'" $ requestedspan `spanDefaultsFrom` journalDateSpan date2_ j
       -- The list of interval spans enclosing the requested span.
       -- This list can be empty if the journal was empty,
       -- or if hledger-ui has added its special date:-tomorrow to the query
       -- and all txns are in the future.
-      intervalspans  = dbg1 "intervalspans"  $ splitSpan interval_ requestedspan'
+      intervalspans  = dbg "intervalspans"  $ splitSpan interval_ requestedspan'
       -- The requested span enlarged to enclose a whole number of intervals.
       -- This can be the null span if there were no intervals.
-      reportspan     = dbg1 "reportspan"     $ DateSpan (maybe Nothing spanStart $ headMay intervalspans)
+      reportspan     = dbg "reportspan"     $ DateSpan (maybe Nothing spanStart $ headMay intervalspans)
                                                         (maybe Nothing spanEnd   $ lastMay intervalspans)
       mreportstart = spanStart reportspan
       -- The user's query with no depth limit, and expanded to the report span
       -- if there is one (otherwise any date queries are left as-is, which
       -- handles the hledger-ui+future txns case above).
-      reportq   = dbg1 "reportq" $ depthless $
+      reportq   = dbg "reportq" $ depthless $
         if reportspan == nulldatespan
         then q
         else And [datelessq, reportspandatesq]
           where
-            reportspandatesq = dbg1 "reportspandatesq" $ dateqcons reportspan
+            reportspandatesq = dbg "reportspandatesq" $ dateqcons reportspan
       -- The date spans to be included as report columns.
-      colspans :: [DateSpan] = dbg1 "colspans" $ splitSpan interval_ displayspan
+      colspans :: [DateSpan] = dbg "colspans" $ splitSpan interval_ displayspan
         where
           displayspan
-            | empty_    = dbg1 "displayspan (-E)" reportspan                              -- all the requested intervals
-            | otherwise = dbg1 "displayspan" $ requestedspan `spanIntersect` matchedspan  -- exclude leading/trailing empty intervals
-          matchedspan = dbg1 "matchedspan" . daysSpan $ map snd ps
+            | empty_    = dbg "displayspan (-E)" reportspan                              -- all the requested intervals
+            | otherwise = dbg "displayspan" $ requestedspan `spanIntersect` matchedspan  -- exclude leading/trailing empty intervals
+          matchedspan = dbg "matchedspan" . daysSpan $ map snd ps
 
       -- If doing cost valuation, convert amounts to cost.
       j' = journalSelectingAmountFromOpts ropts j
@@ -137,9 +144,9 @@
 
       -- Balances at report start date, from all earlier postings which otherwise match the query.
       -- These balances are unvalued except maybe converted to cost.
-      startbals :: [(AccountName, MixedAmount)] = dbg1 "startbals" $ map (\(a,_,_,b) -> (a,b)) startbalanceitems
+      startbals :: [(AccountName, MixedAmount)] = dbg' "startbals" $ map (\(a,_,_,b) -> (a,b)) startbalanceitems
         where
-          (startbalanceitems,_) = dbg1 "starting balance report" $ balanceReport ropts''{value_=Nothing, percent_=False} startbalq j'
+          (startbalanceitems,_) = dbg'' "starting balance report" $ balanceReport ropts''{value_=Nothing, percent_=False} startbalq j'
             where
               ropts' | tree_ ropts = ropts{no_elide_=True}
                      | otherwise   = ropts{accountlistmode_=ALFlat}
@@ -149,14 +156,14 @@
               -- q projected back before the report start date.
               -- When there's no report start date, in case there are future txns (the hledger-ui case above),
               -- we use emptydatespan to make sure they aren't counted as starting balance.
-              startbalq = dbg1 "startbalq" $ And [datelessq, dateqcons precedingspan]
+              startbalq = dbg'' "startbalq" $ And [datelessq, dateqcons precedingspan]
                 where
                   precedingspan = case mreportstart of
                                   Just d  -> DateSpan Nothing (Just d)
                                   Nothing -> emptydatespan
       -- The matched accounts with a starting balance. All of these should appear
       -- in the report even if they have no postings during the report period.
-      startaccts = dbg1 "startaccts" $ map fst startbals
+      startaccts = dbg'' "startaccts" $ map fst startbals
       -- Helpers to look up an account's starting balance.
       startingBalanceFor a = fromMaybe nullmixedamt $ lookup a startbals
 
@@ -165,7 +172,7 @@
 
       -- Postings matching the query within the report period.
       ps :: [(Posting, Day)] =
-          dbg1 "ps" $
+          dbg'' "ps" $
           map postingWithDate $
           journalPostings $
           filterJournalAmounts symq $      -- remove amount parts excluded by cur:
@@ -178,7 +185,7 @@
 
       -- Group postings into their columns, with the column end dates.
       colps :: [([Posting], Maybe Day)] =
-          dbg1 "colps"
+          dbg'' "colps"
           [ (posts, end) | (DateSpan _ end, posts) <- M.toList colMap ]
         where
           colMap = foldr addPosting emptyMap ps
@@ -199,7 +206,7 @@
                 | tree_ ropts = filter ((depthq `matchesAccount`).aname) -- exclude deeper balances
                 | otherwise   = clipAccountsAndAggregate depth -- aggregate deeper balances at the depth limit
       colacctchanges :: [[(ClippedAccountName, MixedAmount)]] =
-          dbg1 "colacctchanges" $ map (acctChangesFromPostings . fst) colps
+          dbg'' "colacctchanges" $ map (acctChangesFromPostings . fst) colps
 
       ----------------------------------------------------------------------
       -- 5. Gather the account balance changes into a regular matrix including the accounts
@@ -207,7 +214,7 @@
 
       -- All account names that will be displayed, possibly depth-clipped.
       displayaccts :: [ClippedAccountName] =
-          dbg1 "displayaccts" $
+          dbg'' "displayaccts" $
           (if tree_ ropts then expandAccountNames else id) $
           nub $ map (clipOrEllipsifyAccountName depth) $
           if empty_ || balancetype_ == HistoricalBalance
@@ -215,16 +222,16 @@
           else allpostedaccts
         where
           allpostedaccts :: [AccountName] =
-            dbg1 "allpostedaccts" . sort . accountNamesFromPostings $ map fst ps
+            dbg'' "allpostedaccts" . sort . accountNamesFromPostings $ map fst ps
       -- Each column's balance changes for each account, adding zeroes where needed.
       colallacctchanges :: [[(ClippedAccountName, MixedAmount)]] =
-          dbg1 "colallacctchanges"
+          dbg'' "colallacctchanges"
           [ sortOn fst $ unionBy (\(a,_) (a',_) -> a == a') postedacctchanges zeroes
              | postedacctchanges <- colacctchanges ]
           where zeroes = [(a, nullmixedamt) | a <- displayaccts]
       -- Transpose to get each account's balance changes across all columns.
       acctchanges :: [(ClippedAccountName, [MixedAmount])] =
-          dbg1 "acctchanges"
+          dbg'' "acctchanges"
           [(a, map snd abs) | abs@((a,_):_) <- transpose colallacctchanges] -- never null, or used when null...
 
       ----------------------------------------------------------------------
@@ -232,18 +239,18 @@
 
       -- One row per account, with account name info, row amounts, row total and row average.
       rows :: [MultiBalanceReportRow] =
-          dbg1 "rows" $
+          dbg'' "rows" $
           [ PeriodicReportRow a (accountNameLevel a) valuedrowbals rowtot rowavg
-           | (a,changes) <- dbg1 "acctchanges" acctchanges
+           | (a,changes) <- dbg'' "acctchanges" acctchanges
              -- The row amounts to be displayed: per-period changes,
              -- zero-based cumulative totals, or
              -- starting-balance-based historical balances.
-           , let rowbals = dbg1 "rowbals" $ case balancetype_ of
+           , let rowbals = dbg'' "rowbals" $ case balancetype_ of
                    PeriodChange      -> changes
                    CumulativeChange  -> drop 1 $ scanl (+) 0                      changes
                    HistoricalBalance -> drop 1 $ scanl (+) (startingBalanceFor a) changes
              -- We may be converting amounts to value, per hledger_options.m4.md "Effect of --value on reports".
-           , let valuedrowbals = dbg1 "valuedrowbals" $ [avalue periodlastday amt | (amt,periodlastday) <- zip rowbals lastdays]
+           , let valuedrowbals = dbg'' "valuedrowbals" $ [avalue periodlastday amt | (amt,periodlastday) <- zip rowbals lastdays]
              -- The total and average for the row.
              -- These are always simply the sum/average of the displayed row amounts.
              -- Total for a cumulative/historical report is always zero.
@@ -273,7 +280,7 @@
       -- Sort the rows by amount or by account declaration order. This is a bit tricky.
       -- TODO: is it always ok to sort report rows after report has been generated, as a separate step ?
       sortedrows :: [MultiBalanceReportRow] =
-        dbg1 "sortedrows" $
+        dbg' "sortedrows" $
         sortrows rows
         where
           sortrows
@@ -319,7 +326,7 @@
       colamts = transpose . map prrAmounts $ filter isHighest rows
         where isHighest row = not (tree_ ropts) || prrName row `elem` highestlevelaccts
       coltotals :: [MixedAmount] =
-        dbg1 "coltotals" $ map sum colamts
+        dbg'' "coltotals" $ map sum colamts
       -- Calculate the grand total and average. These are always the sum/average
       -- of the column totals.
       [grandtotal,grandaverage] =
@@ -330,7 +337,7 @@
         in amts
       -- Totals row.
       totalsrow :: PeriodicReportRow () MixedAmount =
-        dbg1 "totalsrow" $ PeriodicReportRow () 0 coltotals grandtotal grandaverage
+        dbg' "totalsrow" $ PeriodicReportRow () 0 coltotals grandtotal grandaverage
 
       ----------------------------------------------------------------------
       -- 9. Map the report rows to percentages if needed
@@ -339,7 +346,7 @@
       -- Perform the divisions to obtain percentages
       mappedsortedrows :: [MultiBalanceReportRow] =
         if not percent_ then sortedrows
-        else dbg1 "mappedsortedrows"
+        else dbg'' "mappedsortedrows"
           [ PeriodicReportRow aname alevel
               (zipWith perdivide rowvals coltotals)
               (rowtotal `perdivide` grandtotal)
@@ -347,7 +354,7 @@
            | PeriodicReportRow aname alevel rowvals rowtotal rowavg <- sortedrows
           ]
       mappedtotalsrow :: PeriodicReportRow () MixedAmount
-        | percent_  = dbg1 "mappedtotalsrow" $ PeriodicReportRow () 0
+        | percent_  = dbg'' "mappedtotalsrow" $ PeriodicReportRow () 0
              (map (\t -> perdivide t t) coltotals)
              (perdivide grandtotal grandtotal)
              (perdivide grandaverage grandaverage)
@@ -360,7 +367,8 @@
 balanceReportFromMultiBalanceReport :: ReportOpts -> Query -> Journal -> BalanceReport
 balanceReportFromMultiBalanceReport opts q j = (rows', total)
   where
-    PeriodicReport _ rows (PeriodicReportRow _ _ totals _ _) = multiBalanceReportWith opts q j (journalPriceOracle j)
+    PeriodicReport _ rows (PeriodicReportRow _ _ totals _ _) =
+      multiBalanceReportWith opts q j (journalPriceOracle (infer_value_ opts) j)
     rows' = [( a
              , if flat_ opts then a else accountLeafName a   -- BalanceReport expects full account name here with --flat
              , if tree_ opts then d-1 else 0  -- BalanceReport uses 0-based account depths
diff --git a/Hledger/Reports/PostingsReport.hs b/Hledger/Reports/PostingsReport.hs
--- a/Hledger/Reports/PostingsReport.hs
+++ b/Hledger/Reports/PostingsReport.hs
@@ -74,7 +74,7 @@
       whichdate   = whichDateFromOpts ropts
       depth       = queryDepth q
       styles      = journalCommodityStyles j
-      priceoracle = journalPriceOracle j
+      priceoracle = journalPriceOracle infer_value_ j
       multiperiod = interval_ /= NoInterval
       today       = fromMaybe (error' "postingsReport: could not pick a valuation date, ReportOpts today_ is unset") today_
 
diff --git a/Hledger/Reports/ReportOptions.hs b/Hledger/Reports/ReportOptions.hs
--- a/Hledger/Reports/ReportOptions.hs
+++ b/Hledger/Reports/ReportOptions.hs
@@ -93,6 +93,7 @@
     ,interval_       :: Interval
     ,statuses_       :: [Status]  -- ^ Zero, one, or two statuses to be matched
     ,value_          :: Maybe ValuationType  -- ^ What value should amounts be converted to ?
+    ,infer_value_    :: Bool      -- ^ Infer market prices from transactions ?
     ,depth_          :: Maybe Int
     ,display_        :: Maybe DisplayExp  -- XXX unused ?
     ,date2_          :: Bool
@@ -161,6 +162,7 @@
     def
     def
     def
+    def
 
 rawOptsToReportOpts :: RawOpts -> IO ReportOpts
 rawOptsToReportOpts rawopts = checkReportOpts <$> do
@@ -173,6 +175,7 @@
     ,interval_    = intervalFromRawOpts rawopts'
     ,statuses_    = statusesFromRawOpts rawopts'
     ,value_       = valuationTypeFromRawOpts rawopts'
+    ,infer_value_ = boolopt "infer-value" rawopts'
     ,depth_       = maybeintopt "depth" rawopts'
     ,display_     = maybedisplayopt d rawopts'
     ,date2_       = boolopt "date2" rawopts'
@@ -317,8 +320,7 @@
 -- | get period expression from --forecast option
 forecastPeriodFromRawOpts :: Day -> RawOpts -> Maybe DateSpan
 forecastPeriodFromRawOpts d opts =
-  case 
-    dbg2 "forecastopt" $ maybestringopt "forecast" opts
+  case maybestringopt "forecast" opts
   of
     Nothing -> Nothing
     Just "" -> Just nulldatespan
@@ -478,13 +480,13 @@
 reportSpan :: Journal -> ReportOpts -> IO DateSpan
 reportSpan j ropts = do
   (mspecifiedstartdate, mspecifiedenddate) <-
-    dbg2 "specifieddates" <$> specifiedStartEndDates ropts
+    dbg3 "specifieddates" <$> specifiedStartEndDates ropts
   let
     DateSpan mjournalstartdate mjournalenddate =
-      dbg2 "journalspan" $ journalDateSpan False j  -- ignore secondary dates
+      dbg3 "journalspan" $ journalDateSpan False j  -- ignore secondary dates
     mstartdate = mspecifiedstartdate <|> mjournalstartdate
     menddate   = mspecifiedenddate   <|> mjournalenddate
-  return $ dbg1 "reportspan" $ DateSpan mstartdate menddate
+  return $ dbg3 "reportspan" $ DateSpan mstartdate menddate
 
 reportStartDate :: Journal -> ReportOpts -> IO (Maybe Day)
 reportStartDate j ropts = spanStart <$> reportSpan j ropts
diff --git a/Hledger/Utils/Debug.hs b/Hledger/Utils/Debug.hs
--- a/Hledger/Utils/Debug.hs
+++ b/Hledger/Utils/Debug.hs
@@ -1,5 +1,33 @@
 {-# LANGUAGE FlexibleContexts, TypeFamilies #-}
--- | Debugging helpers
+{- | Debugging helpers.
+
+You can enable increasingly verbose debug output by adding --debug [1-9]
+to a hledger command line. --debug with no argument means --debug 1.
+This is implemented by calling dbgN or similar helpers, defined below.
+These calls can be found throughout hledger code; they have been added
+organically where it seemed likely they would be needed again.
+The choice of debug level has not been very systematic.
+202006 Here's a start at some guidelines, not yet applied project-wide:
+
+Debug level:  What to show:
+------------  ---------------------------------------------------------
+0             normal command output only (no warnings, eg)
+1 (--debug)   useful warnings, most common troubleshooting info, eg valuation
+2             common troubleshooting info, more detail
+3             report options selection
+4             report generation
+5             report generation, more detail
+6             command line parsing
+7             input file reading
+8             input file reading, more detail
+9             any other rarely needed / more in-depth info
+
+Tip: when debugging with GHCI, the first run after loading Debug.hs sets the
+debug level. If you need to change it, you must touch Debug.hs, :reload in GHCI,
+then run the command with a new --debug value. Or, often it's more convenient
+to add a temporary dbg0 and :reload (dbg0 always prints).
+
+-}
 
 -- more:
 -- http://hackage.haskell.org/packages/archive/TraceUtils/0.1.0.2/doc/html/Debug-TraceUtils.html
diff --git a/hledger-lib.cabal b/hledger-lib.cabal
--- a/hledger-lib.cabal
+++ b/hledger-lib.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 20f17b4cb289218f7b75159b42ad69840906c54c555a2191679edd3842b72e7b
+-- hash: 22c04257dd0778ffcde96603d006e72ff6bf1b3da2ac7c3c12bc4e9df2064863
 
 name:           hledger-lib
-version:        1.18
+version:        1.18.1
 synopsis:       A reusable library providing the core functionality of hledger
 description:    A reusable library containing hledger's core functionality.
                 This is used by most hledger* packages so that they support the same
diff --git a/hledger_csv.5 b/hledger_csv.5
--- a/hledger_csv.5
+++ b/hledger_csv.5
@@ -1,6 +1,6 @@
 .\"t
 
-.TH "hledger_csv" "5" "June 2020" "hledger 1.18" "hledger User Manuals"
+.TH "hledger_csv" "5" "June 2020" "hledger 1.18.1" "hledger User Manuals"
 
 
 
@@ -961,7 +961,7 @@
 .PP
 A posting amount can be set in one of these ways:
 .IP \[bu] 2
-by assigning (with a fields list or field assigment) to
+by assigning (with a fields list or field assignment) to
 \f[C]amountN\f[R] (posting N\[aq]s amount) or \f[C]amount\f[R] (posting
 1\[aq]s amount)
 .IP \[bu] 2
diff --git a/hledger_csv.info b/hledger_csv.info
--- a/hledger_csv.info
+++ b/hledger_csv.info
@@ -3,8 +3,8 @@
 
 File: hledger_csv.info,  Node: Top,  Next: EXAMPLES,  Up: (dir)
 
-hledger_csv(5) hledger 1.18
-***************************
+hledger_csv(5) hledger 1.18.1
+*****************************
 
 CSV - how hledger reads CSV data, and the CSV rules file format
 
@@ -907,7 +907,7 @@
 
 A posting amount can be set in one of these ways:
 
-   * by assigning (with a fields list or field assigment) to 'amountN'
+   * by assigning (with a fields list or field assignment) to 'amountN'
      (posting N's amount) or 'amount' (posting 1's amount)
 
    * by assigning to 'amountN-in' and 'amountN-out' (or 'amount-in' and
@@ -1036,74 +1036,74 @@
 
 Tag Table:
 Node: Top72
-Node: EXAMPLES2174
-Ref: #examples2280
-Node: Basic2488
-Ref: #basic2588
-Node: Bank of Ireland3130
-Ref: #bank-of-ireland3265
-Node: Amazon4727
-Ref: #amazon4845
-Node: Paypal6564
-Ref: #paypal6658
-Node: CSV RULES14302
-Ref: #csv-rules14411
-Node: skip14687
-Ref: #skip14780
-Node: fields15155
-Ref: #fields15277
-Node: Transaction field names16442
-Ref: #transaction-field-names16602
-Node: Posting field names16713
-Ref: #posting-field-names16865
-Node: account16935
-Ref: #account17051
-Node: amount17588
-Ref: #amount17719
-Node: currency18826
-Ref: #currency18961
-Node: balance19167
-Ref: #balance19301
-Node: comment19618
-Ref: #comment19735
-Node: field assignment19898
-Ref: #field-assignment20041
-Node: separator20859
-Ref: #separator20988
-Node: if21399
-Ref: #if21501
-Node: end23657
-Ref: #end23763
-Node: date-format23987
-Ref: #date-format24119
-Node: newest-first24868
-Ref: #newest-first25006
-Node: include25689
-Ref: #include25818
-Node: balance-type26262
-Ref: #balance-type26382
-Node: TIPS27082
-Ref: #tips27164
-Node: Rapid feedback27420
-Ref: #rapid-feedback27537
-Node: Valid CSV27997
-Ref: #valid-csv28127
-Node: File Extension28319
-Ref: #file-extension28471
-Node: Reading multiple CSV files28881
-Ref: #reading-multiple-csv-files29066
-Node: Valid transactions29307
-Ref: #valid-transactions29485
-Node: Deduplicating importing30113
-Ref: #deduplicating-importing30292
-Node: Setting amounts31325
-Ref: #setting-amounts31494
-Node: Setting currency/commodity32480
-Ref: #setting-currencycommodity32672
-Node: Referencing other fields33475
-Ref: #referencing-other-fields33675
-Node: How CSV rules are evaluated34572
-Ref: #how-csv-rules-are-evaluated34745
+Node: EXAMPLES2178
+Ref: #examples2284
+Node: Basic2492
+Ref: #basic2592
+Node: Bank of Ireland3134
+Ref: #bank-of-ireland3269
+Node: Amazon4731
+Ref: #amazon4849
+Node: Paypal6568
+Ref: #paypal6662
+Node: CSV RULES14306
+Ref: #csv-rules14415
+Node: skip14691
+Ref: #skip14784
+Node: fields15159
+Ref: #fields15281
+Node: Transaction field names16446
+Ref: #transaction-field-names16606
+Node: Posting field names16717
+Ref: #posting-field-names16869
+Node: account16939
+Ref: #account17055
+Node: amount17592
+Ref: #amount17723
+Node: currency18830
+Ref: #currency18965
+Node: balance19171
+Ref: #balance19305
+Node: comment19622
+Ref: #comment19739
+Node: field assignment19902
+Ref: #field-assignment20045
+Node: separator20863
+Ref: #separator20992
+Node: if21403
+Ref: #if21505
+Node: end23661
+Ref: #end23767
+Node: date-format23991
+Ref: #date-format24123
+Node: newest-first24872
+Ref: #newest-first25010
+Node: include25693
+Ref: #include25822
+Node: balance-type26266
+Ref: #balance-type26386
+Node: TIPS27086
+Ref: #tips27168
+Node: Rapid feedback27424
+Ref: #rapid-feedback27541
+Node: Valid CSV28001
+Ref: #valid-csv28131
+Node: File Extension28323
+Ref: #file-extension28475
+Node: Reading multiple CSV files28885
+Ref: #reading-multiple-csv-files29070
+Node: Valid transactions29311
+Ref: #valid-transactions29489
+Node: Deduplicating importing30117
+Ref: #deduplicating-importing30296
+Node: Setting amounts31329
+Ref: #setting-amounts31498
+Node: Setting currency/commodity32485
+Ref: #setting-currencycommodity32677
+Node: Referencing other fields33480
+Ref: #referencing-other-fields33680
+Node: How CSV rules are evaluated34577
+Ref: #how-csv-rules-are-evaluated34750
 
 End Tag Table
 
diff --git a/hledger_csv.txt b/hledger_csv.txt
--- a/hledger_csv.txt
+++ b/hledger_csv.txt
@@ -710,7 +710,7 @@
    Setting amounts
        A posting amount can be set in one of these ways:
 
-       o by assigning (with a fields  list  or  field  assigment)  to  amountN
+       o by assigning (with a fields list  or  field  assignment)  to  amountN
          (posting N's amount) or amount (posting 1's amount)
 
        o by  assigning to amountN-in and amountN-out (or amount-in and amount-
@@ -852,4 +852,4 @@
 
 
 
-hledger 1.18                       June 2020                    hledger_csv(5)
+hledger 1.18.1                     June 2020                    hledger_csv(5)
diff --git a/hledger_journal.5 b/hledger_journal.5
--- a/hledger_journal.5
+++ b/hledger_journal.5
@@ -1,6 +1,6 @@
 .\"t
 
-.TH "hledger_journal" "5" "June 2020" "hledger 1.18" "hledger User Manuals"
+.TH "hledger_journal" "5" "June 2020" "hledger 1.18.1" "hledger User Manuals"
 
 
 
@@ -1143,15 +1143,20 @@
 If the file path does not begin with a slash, it is relative to the
 current file\[aq]s folder.
 .PP
-It may contain glob patterns to match multiple files, eg:
+A tilde means home directory, eg: \f[C]include \[ti]/main.journal\f[R].
+.PP
+The path may contain glob patterns to match multiple files, eg:
 \f[C]include *.journal\f[R].
 .PP
-Or a tilde, meaning home directory:
-\f[C]include \[ti]/main.journal\f[R].
+There is limited support for recursive wildcards: \f[C]**/\f[R] (the
+slash is required) matches 0 or more subdirectories.
+It\[aq]s not super convenient since you have to avoid include cycles and
+including directories, but this can be done, eg:
+\f[C]include */**/*.journal\f[R].
 .PP
-It may also be prefixed to force a specific file format, overriding the
-file extension (as described in hledger.1 -> Input files):
-\f[C]include timedot:\[ti]/notes/2020*.md\f[R].
+The path may also be prefixed to force a specific file format,
+overriding the file extension (as described in hledger.1 -> Input
+files): \f[C]include timedot:\[ti]/notes/2020*.md\f[R].
 .SS Default year
 .PP
 You can set a default year to be used for subsequent dates which
diff --git a/hledger_journal.info b/hledger_journal.info
--- a/hledger_journal.info
+++ b/hledger_journal.info
@@ -4,8 +4,8 @@
 
 File: hledger_journal.info,  Node: Top,  Up: (dir)
 
-hledger_journal(5) hledger 1.18
-*******************************
+hledger_journal(5) hledger 1.18.1
+*********************************
 
 Journal - hledger's default file format, representing a General Journal
 
@@ -1023,15 +1023,20 @@
    If the file path does not begin with a slash, it is relative to the
 current file's folder.
 
-   It may contain glob patterns to match multiple files, eg: 'include
-*.journal'.
+   A tilde means home directory, eg: 'include ~/main.journal'.
 
-   Or a tilde, meaning home directory: 'include ~/main.journal'.
+   The path may contain glob patterns to match multiple files, eg:
+'include *.journal'.
 
-   It may also be prefixed to force a specific file format, overriding
-the file extension (as described in hledger.1 -> Input files): 'include
-timedot:~/notes/2020*.md'.
+   There is limited support for recursive wildcards: '**/' (the slash is
+required) matches 0 or more subdirectories.  It's not super convenient
+since you have to avoid include cycles and including directories, but
+this can be done, eg: 'include */**/*.journal'.
 
+   The path may also be prefixed to force a specific file format,
+overriding the file extension (as described in hledger.1 -> Input
+files): 'include timedot:~/notes/2020*.md'.
+
 
 File: hledger_journal.info,  Node: Default year,  Next: Declaring commodities,  Prev: Including other files,  Up: Directives
 
@@ -1823,124 +1828,124 @@
 
 Tag Table:
 Node: Top76
-Node: Transactions1869
-Ref: #transactions1961
-Node: Dates3245
-Ref: #dates3344
-Node: Simple dates3409
-Ref: #simple-dates3535
-Node: Secondary dates4044
-Ref: #secondary-dates4198
-Node: Posting dates5534
-Ref: #posting-dates5663
-Node: Status7035
-Ref: #status7156
-Node: Description8864
-Ref: #description8998
-Node: Payee and note9318
-Ref: #payee-and-note9432
-Node: Comments9767
-Ref: #comments9893
-Node: Tags11087
-Ref: #tags11202
-Node: Postings12595
-Ref: #postings12723
-Node: Virtual postings13749
-Ref: #virtual-postings13866
-Node: Account names15171
-Ref: #account-names15312
-Node: Amounts15799
-Ref: #amounts15938
-Node: Digit group marks17046
-Ref: #digit-group-marks17194
-Node: Amount display style18132
-Ref: #amount-display-style18286
-Node: Transaction prices19723
-Ref: #transaction-prices19895
-Node: Lot prices and lot dates22227
-Ref: #lot-prices-and-lot-dates22424
-Node: Balance assertions22912
-Ref: #balance-assertions23098
-Node: Assertions and ordering24131
-Ref: #assertions-and-ordering24319
-Node: Assertions and included files25019
-Ref: #assertions-and-included-files25262
-Node: Assertions and multiple -f options25595
-Ref: #assertions-and-multiple--f-options25851
-Node: Assertions and commodities25983
-Ref: #assertions-and-commodities26215
-Node: Assertions and prices27372
-Ref: #assertions-and-prices27586
-Node: Assertions and subaccounts28026
-Ref: #assertions-and-subaccounts28255
-Node: Assertions and virtual postings28579
-Ref: #assertions-and-virtual-postings28821
-Node: Assertions and precision28963
-Ref: #assertions-and-precision29156
-Node: Balance assignments29423
-Ref: #balance-assignments29597
-Node: Balance assignments and prices30761
-Ref: #balance-assignments-and-prices30933
-Node: Directives31157
-Ref: #directives31316
-Node: Directives and multiple files37007
-Ref: #directives-and-multiple-files37190
-Node: Comment blocks37854
-Ref: #comment-blocks38037
-Node: Including other files38213
-Ref: #including-other-files38393
-Node: Default year39044
-Ref: #default-year39213
-Node: Declaring commodities39620
-Ref: #declaring-commodities39803
-Node: Default commodity41609
-Ref: #default-commodity41795
-Node: Declaring market prices42684
-Ref: #declaring-market-prices42879
-Node: Declaring accounts43736
-Ref: #declaring-accounts43922
-Node: Account comments44847
-Ref: #account-comments45010
-Node: Account subdirectives45434
-Ref: #account-subdirectives45629
-Node: Account types45942
-Ref: #account-types46126
-Node: Account display order47765
-Ref: #account-display-order47935
-Node: Rewriting accounts49086
-Ref: #rewriting-accounts49271
-Node: Basic aliases50028
-Ref: #basic-aliases50174
-Node: Regex aliases50878
-Ref: #regex-aliases51050
-Node: Combining aliases51768
-Ref: #combining-aliases51961
-Node: Aliases and multiple files53237
-Ref: #aliases-and-multiple-files53446
-Node: end aliases54025
-Ref: #end-aliases54182
-Node: Default parent account54283
-Ref: #default-parent-account54451
-Node: Periodic transactions55335
-Ref: #periodic-transactions55510
-Node: Periodic rule syntax57382
-Ref: #periodic-rule-syntax57588
-Node: Two spaces between period expression and description!58292
-Ref: #two-spaces-between-period-expression-and-description58611
-Node: Forecasting with periodic transactions59295
-Ref: #forecasting-with-periodic-transactions59600
-Node: Budgeting with periodic transactions61655
-Ref: #budgeting-with-periodic-transactions61894
-Node: Auto postings62343
-Ref: #auto-postings62483
-Node: Auto postings and multiple files64662
-Ref: #auto-postings-and-multiple-files64866
-Node: Auto postings and dates65075
-Ref: #auto-postings-and-dates65349
-Node: Auto postings and transaction balancing / inferred amounts / balance assertions65524
-Ref: #auto-postings-and-transaction-balancing-inferred-amounts-balance-assertions65875
-Node: Auto posting tags66217
-Ref: #auto-posting-tags66432
+Node: Transactions1873
+Ref: #transactions1965
+Node: Dates3249
+Ref: #dates3348
+Node: Simple dates3413
+Ref: #simple-dates3539
+Node: Secondary dates4048
+Ref: #secondary-dates4202
+Node: Posting dates5538
+Ref: #posting-dates5667
+Node: Status7039
+Ref: #status7160
+Node: Description8868
+Ref: #description9002
+Node: Payee and note9322
+Ref: #payee-and-note9436
+Node: Comments9771
+Ref: #comments9897
+Node: Tags11091
+Ref: #tags11206
+Node: Postings12599
+Ref: #postings12727
+Node: Virtual postings13753
+Ref: #virtual-postings13870
+Node: Account names15175
+Ref: #account-names15316
+Node: Amounts15803
+Ref: #amounts15942
+Node: Digit group marks17050
+Ref: #digit-group-marks17198
+Node: Amount display style18136
+Ref: #amount-display-style18290
+Node: Transaction prices19727
+Ref: #transaction-prices19899
+Node: Lot prices and lot dates22231
+Ref: #lot-prices-and-lot-dates22428
+Node: Balance assertions22916
+Ref: #balance-assertions23102
+Node: Assertions and ordering24135
+Ref: #assertions-and-ordering24323
+Node: Assertions and included files25023
+Ref: #assertions-and-included-files25266
+Node: Assertions and multiple -f options25599
+Ref: #assertions-and-multiple--f-options25855
+Node: Assertions and commodities25987
+Ref: #assertions-and-commodities26219
+Node: Assertions and prices27376
+Ref: #assertions-and-prices27590
+Node: Assertions and subaccounts28030
+Ref: #assertions-and-subaccounts28259
+Node: Assertions and virtual postings28583
+Ref: #assertions-and-virtual-postings28825
+Node: Assertions and precision28967
+Ref: #assertions-and-precision29160
+Node: Balance assignments29427
+Ref: #balance-assignments29601
+Node: Balance assignments and prices30765
+Ref: #balance-assignments-and-prices30937
+Node: Directives31161
+Ref: #directives31320
+Node: Directives and multiple files37011
+Ref: #directives-and-multiple-files37194
+Node: Comment blocks37858
+Ref: #comment-blocks38041
+Node: Including other files38217
+Ref: #including-other-files38397
+Node: Default year39321
+Ref: #default-year39490
+Node: Declaring commodities39897
+Ref: #declaring-commodities40080
+Node: Default commodity41886
+Ref: #default-commodity42072
+Node: Declaring market prices42961
+Ref: #declaring-market-prices43156
+Node: Declaring accounts44013
+Ref: #declaring-accounts44199
+Node: Account comments45124
+Ref: #account-comments45287
+Node: Account subdirectives45711
+Ref: #account-subdirectives45906
+Node: Account types46219
+Ref: #account-types46403
+Node: Account display order48042
+Ref: #account-display-order48212
+Node: Rewriting accounts49363
+Ref: #rewriting-accounts49548
+Node: Basic aliases50305
+Ref: #basic-aliases50451
+Node: Regex aliases51155
+Ref: #regex-aliases51327
+Node: Combining aliases52045
+Ref: #combining-aliases52238
+Node: Aliases and multiple files53514
+Ref: #aliases-and-multiple-files53723
+Node: end aliases54302
+Ref: #end-aliases54459
+Node: Default parent account54560
+Ref: #default-parent-account54728
+Node: Periodic transactions55612
+Ref: #periodic-transactions55787
+Node: Periodic rule syntax57659
+Ref: #periodic-rule-syntax57865
+Node: Two spaces between period expression and description!58569
+Ref: #two-spaces-between-period-expression-and-description58888
+Node: Forecasting with periodic transactions59572
+Ref: #forecasting-with-periodic-transactions59877
+Node: Budgeting with periodic transactions61932
+Ref: #budgeting-with-periodic-transactions62171
+Node: Auto postings62620
+Ref: #auto-postings62760
+Node: Auto postings and multiple files64939
+Ref: #auto-postings-and-multiple-files65143
+Node: Auto postings and dates65352
+Ref: #auto-postings-and-dates65626
+Node: Auto postings and transaction balancing / inferred amounts / balance assertions65801
+Ref: #auto-postings-and-transaction-balancing-inferred-amounts-balance-assertions66152
+Node: Auto posting tags66494
+Ref: #auto-posting-tags66709
 
 End Tag Table
 
diff --git a/hledger_journal.txt b/hledger_journal.txt
--- a/hledger_journal.txt
+++ b/hledger_journal.txt
@@ -792,18 +792,23 @@
        If  the  file  path  does not begin with a slash, it is relative to the
        current file's folder.
 
-       It may contain glob patterns  to  match  multiple  files,  eg:  include
+       A tilde means home directory, eg: include ~/main.journal.
+
+       The path may contain glob patterns to match multiple files, eg: include
        *.journal.
 
-       Or a tilde, meaning home directory: include ~/main.journal.
+       There is limited support for recursive wildcards: **/ (the slash is re-
+       quired) matches 0 or more subdirectories.  It's  not  super  convenient
+       since  you  have to avoid include cycles and including directories, but
+       this can be done, eg: include */**/*.journal.
 
-       It may also be prefixed to force a specific file format, overriding the
-       file extension (as described in  hledger.1  ->  Input  files):  include
-       timedot:~/notes/2020*.md.
+       The path may also be prefixed to force a specific file format, overrid-
+       ing  the file extension (as described in hledger.1 -> Input files): in-
+       clude timedot:~/notes/2020*.md.
 
    Default year
-       You  can set a default year to be used for subsequent dates which don't
-       specify a year.  This is a line beginning with Y followed by the  year.
+       You can set a default year to be used for subsequent dates which  don't
+       specify  a year.  This is a line beginning with Y followed by the year.
        Eg:
 
               Y2009  ; set default year to 2009
@@ -825,19 +830,19 @@
    Declaring commodities
        The commodity directive has several functions:
 
-       1. It  declares  commodities which may be used in the journal.  This is
+       1. It declares commodities which may be used in the journal.   This  is
           currently not enforced, but can serve as documentation.
 
-       2. It declares what decimal mark character (period or comma) to  expect
-          when  parsing  input  -  useful to disambiguate international number
-          formats in your data.  (Without this, hledger will parse both  1,000
+       2. It  declares what decimal mark character (period or comma) to expect
+          when parsing input - useful  to  disambiguate  international  number
+          formats  in your data.  (Without this, hledger will parse both 1,000
           and 1.000 as 1).
 
-       3. It  declares the amount display style to use in output - decimal and
+       3. It declares the amount display style to use in output - decimal  and
           digit group marks, number of decimal places, symbol placement etc.
 
-       You are likely to run into one of the problems solved by commodity  di-
-       rectives,  sooner or later, so it's a good idea to just always use them
+       You  are likely to run into one of the problems solved by commodity di-
+       rectives, sooner or later, so it's a good idea to just always use  them
        to declare your commodities.
 
        A commodity directive is just the word commodity followed by an amount.
@@ -850,8 +855,8 @@
               ; separating thousands with comma.
               commodity 1,000.0000 AAAA
 
-       or  on  multiple lines, using the "format" subdirective.  (In this case
-       the commodity symbol appears twice and  should  be  the  same  in  both
+       or on multiple lines, using the "format" subdirective.  (In  this  case
+       the  commodity  symbol  appears  twice  and  should be the same in both
        places.):
 
               ; commodity SYMBOL
@@ -864,22 +869,22 @@
                 format INR 1,00,00,000.00
 
        The quantity of the amount does not matter; only the format is signifi-
-       cant.  The number must include a decimal mark: either  a  period  or  a
+       cant.   The  number  must  include a decimal mark: either a period or a
        comma, followed by 0 or more decimal digits.
 
-       Note  hledger  normally  uses  banker's rounding, so 0.5 displayed with
+       Note hledger normally uses banker's rounding,  so  0.5  displayed  with
        zero decimal digits is "0".  (More at Amount display style.)
 
    Default commodity
-       The D directive sets a default commodity, to be used for amounts  with-
+       The  D directive sets a default commodity, to be used for amounts with-
        out a commodity symbol (ie, plain numbers).  This commodity will be ap-
        plied to all subsequent commodity-less amounts, or until the next D di-
        rective.  (Note, this is different from Ledger's D.)
 
-       For  compatibility/historical reasons, D also acts like a commodity di-
+       For compatibility/historical reasons, D also acts like a commodity  di-
        rective, setting the commodity's display style (for output) and decimal
        mark (for parsing input).  As with commodity, the amount must always be
-       written with a decimal mark (period or comma).  If both directives  are
+       written  with a decimal mark (period or comma).  If both directives are
        used, commodity's style takes precedence.
 
        The syntax is D AMOUNT.  Eg:
@@ -893,9 +898,9 @@
                 b
 
    Declaring market prices
-       The  P directive declares a market price, which is an exchange rate be-
-       tween two commodities on a certain date.  (In Ledger, they  are  called
-       "historical  prices".)  These are often obtained from a stock exchange,
+       The P directive declares a market price, which is an exchange rate  be-
+       tween  two  commodities on a certain date.  (In Ledger, they are called
+       "historical prices".) These are often obtained from a  stock  exchange,
        cryptocurrency exchange, or the foreign exchange market.
 
        Here is the format:
@@ -906,16 +911,16 @@
 
        o COMMODITYA is the symbol of the commodity being priced
 
-       o COMMODITYBAMOUNT is an amount (symbol and quantity) in a second  com-
+       o COMMODITYBAMOUNT  is an amount (symbol and quantity) in a second com-
          modity, giving the price in commodity B of one unit of commodity A.
 
-       These  two  market price directives say that one euro was worth 1.35 US
+       These two market price directives say that one euro was worth  1.35  US
        dollars during 2009, and $1.40 from 2010 onward:
 
               P 2009/1/1 EUR $1.35
               P 2010/1/1 EUR $1.40
 
-       The -V, -X and --value flags use these market  prices  to  show  amount
+       The  -V,  -X  and  --value flags use these market prices to show amount
        values in another commodity.  See Valuation.
 
    Declaring accounts
@@ -925,20 +930,20 @@
        o They can document your intended chart of accounts, providing a refer-
          ence.
 
-       o They  can  store  extra  information about accounts (account numbers,
+       o They can store extra information  about  accounts  (account  numbers,
          notes, etc.)
 
-       o They can help hledger know your accounts'  types  (asset,  liability,
-         equity,  revenue,  expense), useful for reports like balancesheet and
+       o They  can  help  hledger know your accounts' types (asset, liability,
+         equity, revenue, expense), useful for reports like  balancesheet  and
          incomestatement.
 
-       o They control account display order in  reports,  allowing  non-alpha-
+       o They  control  account  display order in reports, allowing non-alpha-
          betic sorting (eg Revenues to appear above Expenses).
 
-       o They  help  with account name completion in the add command, hledger-
+       o They help with account name completion in the add  command,  hledger-
          iadd, hledger-web, ledger-mode etc.
 
-       The simplest form is just the word account followed by a  hledger-style
+       The  simplest form is just the word account followed by a hledger-style
        account name, eg:
 
               account assets:bank:checking
@@ -946,7 +951,7 @@
    Account comments
        Comments, beginning with a semicolon, can be added:
 
-       o on  the  same line, after two or more spaces (because ; is allowed in
+       o on the same line, after two or more spaces (because ; is  allowed  in
          account names)
 
        o on the next lines, indented
@@ -960,7 +965,7 @@
        Same-line comments are not supported by Ledger, or hledger <1.13.
 
    Account subdirectives
-       We also allow (and ignore) Ledger-style  indented  subdirectives,  just
+       We  also  allow  (and ignore) Ledger-style indented subdirectives, just
        for compatibility.:
 
               account assets:bank:checking
@@ -973,18 +978,18 @@
                 [LEDGER-STYLE SUBDIRECTIVES, IGNORED]
 
    Account types
-       hledger  recognises  five types (or classes) of account: Asset, Liabil-
-       ity, Equity, Revenue, Expense.  This is used by a few  accounting-aware
+       hledger recognises five types (or classes) of account:  Asset,  Liabil-
+       ity,  Equity, Revenue, Expense.  This is used by a few accounting-aware
        reports such as balancesheet, incomestatement and cashflow.
 
    Auto-detected account types
        If you name your top-level accounts with some variation of assets, lia-
-       bilities/debts, equity, revenues/income, or expenses, their  types  are
+       bilities/debts,  equity,  revenues/income, or expenses, their types are
        detected automatically.
 
    Account types declared with tags
-       More  generally,  you can declare an account's type with an account di-
-       rective, by writing a type: tag in a comment, followed by  one  of  the
+       More generally, you can declare an account's type with an  account  di-
+       rective,  by  writing  a type: tag in a comment, followed by one of the
        words Asset, Liability, Equity, Revenue, Expense, or one of the letters
        ALERX (case insensitive):
 
@@ -995,8 +1000,8 @@
               account expenses     ; type:Expense
 
    Account types declared with account type codes
-       Or, you can write one of those letters separated from the account  name
-       by  two  or  more spaces, but this should probably be considered depre-
+       Or,  you can write one of those letters separated from the account name
+       by two or more spaces, but this should probably  be  considered  depre-
        cated as of hledger 1.13:
 
               account assets       A
@@ -1006,7 +1011,7 @@
               account expenses     X
 
    Overriding auto-detected types
-       If you ever override the types of those auto-detected  english  account
+       If  you  ever override the types of those auto-detected english account
        names mentioned above, you might need to help the reports a bit.  Eg:
 
               ; make "liabilities" not have the liability type - who knows why
@@ -1017,8 +1022,8 @@
               account -            ; type:L
 
    Account display order
-       Account  directives also set the order in which accounts are displayed,
-       eg in reports, the hledger-ui  accounts  screen,  and  the  hledger-web
+       Account directives also set the order in which accounts are  displayed,
+       eg  in  reports,  the  hledger-ui  accounts screen, and the hledger-web
        sidebar.  By default accounts are listed in alphabetical order.  But if
        you have these account directives in the journal:
 
@@ -1040,20 +1045,20 @@
 
        Undeclared accounts, if any, are displayed last, in alphabetical order.
 
-       Note  that  sorting  is  done at each level of the account tree (within
-       each group of sibling accounts under the same parent).  And  currently,
+       Note that sorting is done at each level of  the  account  tree  (within
+       each  group of sibling accounts under the same parent).  And currently,
        this directive:
 
               account other:zoo
 
-       would  influence the position of zoo among other's subaccounts, but not
+       would influence the position of zoo among other's subaccounts, but  not
        the position of other among the top-level accounts.  This means:
 
-       o you will sometimes declare parent accounts (eg account  other  above)
+       o you  will  sometimes declare parent accounts (eg account other above)
          that you don't intend to post to, just to customize their display or-
          der
 
-       o sibling accounts stay together (you couldn't display x:y  in  between
+       o sibling  accounts  stay together (you couldn't display x:y in between
          a:b and a:c).
 
    Rewriting accounts
@@ -1071,14 +1076,14 @@
        o customising reports
 
        Account aliases also rewrite account names in account directives.  They
-       do  not  affect account names being entered via hledger add or hledger-
+       do not affect account names being entered via hledger add  or  hledger-
        web.
 
        See also Rewrite account names.
 
    Basic aliases
-       To set an account alias, use the alias directive in your journal  file.
-       This  affects all subsequent journal entries in the current file or its
+       To  set an account alias, use the alias directive in your journal file.
+       This affects all subsequent journal entries in the current file or  its
        included files.  The spaces around the = are optional:
 
               alias OLD = NEW
@@ -1086,49 +1091,49 @@
        Or, you can use the --alias 'OLD=NEW' option on the command line.  This
        affects all entries.  It's useful for trying out aliases interactively.
 
-       OLD  and  NEW  are case sensitive full account names.  hledger will re-
-       place any occurrence of the old account name with the new one.   Subac-
+       OLD and NEW are case sensitive full account names.   hledger  will  re-
+       place  any occurrence of the old account name with the new one.  Subac-
        counts are also affected.  Eg:
 
               alias checking = assets:bank:wells fargo:checking
               ; rewrites "checking" to "assets:bank:wells fargo:checking", or "checking:a" to "assets:bank:wells fargo:checking:a"
 
    Regex aliases
-       There  is  also a more powerful variant that uses a regular expression,
+       There is also a more powerful variant that uses a  regular  expression,
        indicated by the forward slashes:
 
               alias /REGEX/ = REPLACEMENT
 
        or --alias '/REGEX/=REPLACEMENT'.
 
-       REGEX is a case-insensitive regular expression.   Anywhere  it  matches
-       inside  an  account name, the matched part will be replaced by REPLACE-
-       MENT.  If REGEX contains parenthesised match groups, these can be  ref-
+       REGEX  is  a  case-insensitive regular expression.  Anywhere it matches
+       inside an account name, the matched part will be replaced  by  REPLACE-
+       MENT.   If REGEX contains parenthesised match groups, these can be ref-
        erenced by the usual numeric backreferences in REPLACEMENT.  Eg:
 
               alias /^(.+):bank:([^:]+)(.*)/ = \1:\2 \3
               ; rewrites "assets:bank:wells fargo:checking" to  "assets:wells fargo checking"
 
-       Also  note that REPLACEMENT continues to the end of line (or on command
-       line, to end of option argument), so it  can  contain  trailing  white-
+       Also note that REPLACEMENT continues to the end of line (or on  command
+       line,  to  end  of  option argument), so it can contain trailing white-
        space.
 
    Combining aliases
-       You  can  define  as many aliases as you like, using journal directives
+       You can define as many aliases as you like,  using  journal  directives
        and/or command line options.
 
-       Recursive aliases - where an account name is rewritten  by  one  alias,
-       then  by  another  alias, and so on - are allowed.  Each alias sees the
+       Recursive  aliases  -  where an account name is rewritten by one alias,
+       then by another alias, and so on - are allowed.  Each  alias  sees  the
        effect of previously applied aliases.
 
-       In such cases it can be important to understand which aliases  will  be
-       applied  and  in  which order.  For (each account name in) each journal
+       In  such  cases it can be important to understand which aliases will be
+       applied and in which order.  For (each account name  in)  each  journal
        entry, we apply:
 
-       1. alias directives preceding the journal entry, most  recently  parsed
+       1. alias  directives  preceding the journal entry, most recently parsed
           first (ie, reading upward from the journal entry, bottom to top)
 
-       2. --alias  options,  in  the  order  they appeared on the command line
+       2. --alias options, in the order they  appeared  on  the  command  line
           (left to right).
 
        In other words, for (an account name in) a given journal entry:
@@ -1139,20 +1144,20 @@
 
        o aliases defined after/below the entry do not affect it.
 
-       This gives nearby aliases precedence over distant ones, and helps  pro-
-       vide  semantic stability - aliases will keep working the same way inde-
+       This  gives nearby aliases precedence over distant ones, and helps pro-
+       vide semantic stability - aliases will keep working the same way  inde-
        pendent of which files are being read and in which order.
 
-       In case of trouble, adding --debug=6 to  the  command  line  will  show
+       In  case  of  trouble,  adding  --debug=6 to the command line will show
        which aliases are being applied when.
 
    Aliases and multiple files
-       As  explained at Directives and multiple files, alias directives do not
+       As explained at Directives and multiple files, alias directives do  not
        affect parent or sibling files.  Eg in this command,
 
               hledger -f a.aliases -f b.journal
 
-       account aliases defined in a.aliases will not  affect  b.journal.   In-
+       account  aliases  defined  in a.aliases will not affect b.journal.  In-
        cluding the aliases doesn't work either:
 
               include a.aliases
@@ -1174,14 +1179,14 @@
               include c.journal  ; also affected
 
    end aliases
-       You can clear (forget) all  currently  defined  aliases  with  the  end
+       You  can  clear  (forget)  all  currently  defined aliases with the end
        aliases directive:
 
               end aliases
 
    Default parent account
-       You  can  specify  a  parent account which will be prepended to all ac-
-       counts within a section of the journal.  Use the apply account and  end
+       You can specify a parent account which will be  prepended  to  all  ac-
+       counts  within a section of the journal.  Use the apply account and end
        apply account directives like so:
 
               apply account home
@@ -1198,7 +1203,7 @@
                   home:food           $10
                   home:cash          $-10
 
-       If  end  apply  account  is omitted, the effect lasts to the end of the
+       If end apply account is omitted, the effect lasts to  the  end  of  the
        file.  Included files are also affected, eg:
 
               apply account business
@@ -1207,50 +1212,50 @@
               apply account personal
               include personal.journal
 
-       Prior to hledger 1.0, legacy account and end spellings were  also  sup-
+       Prior  to  hledger 1.0, legacy account and end spellings were also sup-
        ported.
 
-       A  default parent account also affects account directives.  It does not
-       affect account names being entered via hledger add or hledger-web.   If
-       account  aliases are present, they are applied after the default parent
+       A default parent account also affects account directives.  It does  not
+       affect  account names being entered via hledger add or hledger-web.  If
+       account aliases are present, they are applied after the default  parent
        account.
 
    Periodic transactions
-       Periodic transaction rules describe transactions that recur.  They  al-
-       low  hledger  to  generate  temporary  future transactions to help with
-       forecasting, so you don't have to write out each one  in  the  journal,
-       and  it's easy to try out different forecasts.  Secondly, they are also
+       Periodic  transaction rules describe transactions that recur.  They al-
+       low hledger to generate temporary  future  transactions  to  help  with
+       forecasting,  so  you  don't have to write out each one in the journal,
+       and it's easy to try out different forecasts.  Secondly, they are  also
        used to define the budgets shown in budget reports.
 
-       Periodic transactions can be a little tricky, so before you  use  them,
+       Periodic  transactions  can be a little tricky, so before you use them,
        read this whole section - or at least these tips:
 
-       1. Two  spaces  accidentally  added or omitted will cause you trouble -
+       1. Two spaces accidentally added or omitted will cause  you  trouble  -
           read about this below.
 
-       2. For troubleshooting, show the generated  transactions  with  hledger
-          print   --forecast  tag:generated  or  hledger  register  --forecast
+       2. For  troubleshooting,  show  the generated transactions with hledger
+          print  --forecast  tag:generated  or  hledger  register   --forecast
           tag:generated.
 
-       3. Forecasted transactions will begin only  after  the  last  non-fore-
+       3. Forecasted  transactions  will  begin  only after the last non-fore-
           casted transaction's date.
 
-       4. Forecasted  transactions  will  end 6 months from today, by default.
+       4. Forecasted transactions will end 6 months from  today,  by  default.
           See below for the exact start/end rules.
 
-       5. period expressions can be tricky.   Their  documentation  needs  im-
+       5. period  expressions  can  be  tricky.  Their documentation needs im-
           provement, but is worth studying.
 
-       6. Some  period  expressions  with a repeating interval must begin on a
-          natural boundary of that interval.  Eg in  weekly  from  DATE,  DATE
-          must  be a monday.  ~ weekly from 2019/10/1 (a tuesday) will give an
+       6. Some period expressions with a repeating interval must  begin  on  a
+          natural  boundary  of  that  interval.  Eg in weekly from DATE, DATE
+          must be a monday.  ~ weekly from 2019/10/1 (a tuesday) will give  an
           error.
 
        7. Other period expressions with an interval are automatically expanded
-          to  cover a whole number of that interval.  (This is done to improve
+          to cover a whole number of that interval.  (This is done to  improve
           reports, but it also affects periodic transactions.  Yes, it's a bit
-          inconsistent  with  the  above.)  Eg: ~ every 10th day of month from
-          2020/01, which is equivalent to ~  every  10th  day  of  month  from
+          inconsistent with the above.) Eg: ~ every 10th  day  of  month  from
+          2020/01,  which  is  equivalent  to  ~  every 10th day of month from
           2020/01/01, will be adjusted to start on 2019/12/10.
 
    Periodic rule syntax
@@ -1262,17 +1267,17 @@
                   expenses:rent          $2000
                   assets:bank:checking
 
-       There  is  an additional constraint on the period expression: the start
-       date must fall on a natural boundary of the interval.  Eg monthly  from
+       There is an additional constraint on the period expression:  the  start
+       date  must fall on a natural boundary of the interval.  Eg monthly from
        2018/1/1 is valid, but monthly from 2018/1/15 is not.
 
-       Partial  or  relative dates (M/D, D, tomorrow, last week) in the period
-       expression can work (useful or not).  They will be relative to  today's
-       date,  unless  a  Y  default year directive is in effect, in which case
+       Partial or relative dates (M/D, D, tomorrow, last week) in  the  period
+       expression  can work (useful or not).  They will be relative to today's
+       date, unless a Y default year directive is in  effect,  in  which  case
        they will be relative to Y/1/1.
 
    Two spaces between period expression and description!
-       If the period expression is  followed  by  a  transaction  description,
+       If  the  period  expression  is  followed by a transaction description,
        these must be separated by two or more spaces.  This helps hledger know
        where the period expression ends, so that descriptions can not acciden-
        tally alter their meaning, as in this example:
@@ -1286,68 +1291,68 @@
 
        So,
 
-       o Do  write two spaces between your period expression and your transac-
+       o Do write two spaces between your period expression and your  transac-
          tion description, if any.
 
-       o Don't accidentally write two spaces in the middle of your period  ex-
+       o Don't  accidentally write two spaces in the middle of your period ex-
          pression.
 
    Forecasting with periodic transactions
-       The  --forecast  flag  activates  any periodic transaction rules in the
-       journal.  They will generate temporary  recurring  transactions,  which
-       are  not  saved  in  the  journal,  but  will appear in all reports (eg
+       The --forecast flag activates any periodic  transaction  rules  in  the
+       journal.   They  will  generate temporary recurring transactions, which
+       are not saved in the journal,  but  will  appear  in  all  reports  (eg
        print).  This can be useful for estimating balances into the future, or
-       experimenting  with  different scenarios.  Or, it can be used as a data
+       experimenting with different scenarios.  Or, it can be used as  a  data
        entry aid: describe recurring transactions, and every so often copy the
        output of print --forecast into the journal.
 
-       These  transactions  will  have  an extra tag indicating which periodic
+       These transactions will have an extra  tag  indicating  which  periodic
        rule generated them: generated-transaction:~ PERIODICEXPR.  And a simi-
-       lar,  hidden  tag  (beginning  with  an underscore) which, because it's
-       never displayed by print, can be used to match  transactions  generated
+       lar, hidden tag (beginning with  an  underscore)  which,  because  it's
+       never  displayed  by print, can be used to match transactions generated
        "just now": _generated-transaction:~ PERIODICEXPR.
 
-       Periodic  transactions  are  generated within some forecast period.  By
+       Periodic transactions are generated within some  forecast  period.   By
        default, this
 
        o begins on the later of
 
          o the report start date if specified with -b/-p/date:
 
-         o the day after the latest normal (non-periodic) transaction  in  the
+         o the  day  after the latest normal (non-periodic) transaction in the
            journal, or today if there are no normal transactions.
 
-       o ends  on  the  report  end  date  if specified with -e/-p/date:, or 6
+       o ends on the report end date  if  specified  with  -e/-p/date:,  or  6
          months (180 days) from today.
 
-       This means that periodic transactions will begin only after the  latest
-       recorded  transaction.   And a recorded transaction dated in the future
-       can prevent generation of periodic transactions.  (You can  avoid  that
+       This  means that periodic transactions will begin only after the latest
+       recorded transaction.  And a recorded transaction dated in  the  future
+       can  prevent  generation of periodic transactions.  (You can avoid that
        by writing the future transaction as a one-time periodic rule instead -
        put tilde before the date, eg ~ YYYY-MM-DD ...).
 
        Or, you can set your own arbitrary "forecast period", which can overlap
-       recorded  transactions,  and need not be in the future, by providing an
-       option argument, like --forecast=PERIODEXPR.  Note the equals  sign  is
+       recorded transactions, and need not be in the future, by  providing  an
+       option  argument,  like --forecast=PERIODEXPR.  Note the equals sign is
        required, a space won't work.  PERIODEXPR is a period expression, which
-       can specify the start date, end date, or both, like in a  date:  query.
-       (See  also  hledger.1  ->  Report  start  &  end date).  Some examples:
+       can  specify  the start date, end date, or both, like in a date: query.
+       (See also hledger.1 ->  Report  start  &  end  date).   Some  examples:
        --forecast=202001-202004, --forecast=jan-, --forecast=2020.
 
    Budgeting with periodic transactions
-       With the --budget flag, currently supported  by  the  balance  command,
-       each  periodic transaction rule declares recurring budget goals for the
-       specified accounts.  Eg the first example  above  declares  a  goal  of
-       spending  $2000  on  rent  (and  also,  a goal of depositing $2000 into
-       checking) every month.  Goals and actual performance can then  be  com-
+       With  the  --budget  flag,  currently supported by the balance command,
+       each periodic transaction rule declares recurring budget goals for  the
+       specified  accounts.   Eg  the  first  example above declares a goal of
+       spending $2000 on rent (and also,  a  goal  of  depositing  $2000  into
+       checking)  every  month.  Goals and actual performance can then be com-
        pared in budget reports.
 
-       For  more  details, see: balance: Budget report and Budgeting and Fore-
+       For more details, see: balance: Budget report and Budgeting  and  Fore-
        casting.
 
    Auto postings
-       "Automated postings" or "auto postings" are extra  postings  which  get
-       added  automatically  to  transactions which match certain queries, de-
+       "Automated  postings"  or  "auto postings" are extra postings which get
+       added automatically to transactions which match  certain  queries,  de-
        fined by "auto posting rules", when you use the --auto flag.
 
        An auto posting rule looks a bit like a transaction:
@@ -1357,27 +1362,27 @@
                   ...
                   ACCOUNT  [AMOUNT]
 
-       except the first line is an equals sign (mnemonic:  =  suggests  match-
-       ing),  followed  by a query (which matches existing postings), and each
-       "posting" line describes a posting to be  generated,  and  the  posting
+       except  the  first  line is an equals sign (mnemonic: = suggests match-
+       ing), followed by a query (which matches existing postings),  and  each
+       "posting"  line  describes  a  posting to be generated, and the posting
        amounts can be:
 
-       o a  normal  amount  with a commodity symbol, eg $2.  This will be used
+       o a normal amount with a commodity symbol, eg $2.  This  will  be  used
          as-is.
 
        o a number, eg 2.  The commodity symbol (if any) from the matched post-
          ing will be added to this.
 
-       o a  numeric  multiplier,  eg  *2 (a star followed by a number N).  The
+       o a numeric multiplier, eg *2 (a star followed by  a  number  N).   The
          matched posting's amount (and total price, if any) will be multiplied
          by N.
 
-       o a  multiplier  with a commodity symbol, eg *$2 (a star, number N, and
+       o a multiplier with a commodity symbol, eg *$2 (a star, number  N,  and
          symbol S).  The matched posting's amount will be multiplied by N, and
          its commodity symbol will be replaced with S.
 
-       Any  query  term containing spaces must be enclosed in single or double
-       quotes, as on the command line.  Eg, note the quotes around the  second
+       Any query term containing spaces must be enclosed in single  or  double
+       quotes,  as on the command line.  Eg, note the quotes around the second
        query term below:
 
               = expenses:groceries 'expenses:dining out'
@@ -1416,24 +1421,24 @@
 
    Auto postings and multiple files
        An auto posting rule can affect any transaction in the current file, or
-       in any parent file or child file.  Note, currently it will  not  affect
+       in  any  parent file or child file.  Note, currently it will not affect
        sibling files (when multiple -f/--file are used - see #1212).
 
    Auto postings and dates
-       A  posting  date (or secondary date) in the matched posting, or (taking
-       precedence) a posting date in the auto posting rule itself,  will  also
+       A posting date (or secondary date) in the matched posting,  or  (taking
+       precedence)  a  posting date in the auto posting rule itself, will also
        be used in the generated posting.
 
    Auto postings and transaction balancing / inferred amounts / balance asser-
        tions
        Currently, auto postings are added:
 
-       o after missing amounts are inferred, and transactions are checked  for
+       o after  missing amounts are inferred, and transactions are checked for
          balancedness,
 
        o but before balance assertions are checked.
 
-       Note  this  means that journal entries must be balanced both before and
+       Note this means that journal entries must be balanced both  before  and
        after auto postings are added.  This changed in hledger 1.12+; see #893
        for background.
 
@@ -1443,11 +1448,11 @@
        o generated-posting:= QUERY - shows this was generated by an auto post-
          ing rule, and the query
 
-       o _generated-posting:= QUERY - a hidden tag, which does not  appear  in
+       o _generated-posting:=  QUERY  - a hidden tag, which does not appear in
          hledger's output.  This can be used to match postings generated "just
          now", rather than generated in the past and saved to the journal.
 
-       Also, any transaction that has been changed by auto posting rules  will
+       Also,  any transaction that has been changed by auto posting rules will
        have these tags added:
 
        o modified: - this transaction was modified
@@ -1458,7 +1463,7 @@
 
 
 REPORTING BUGS
-       Report bugs at http://bugs.hledger.org (or on the #hledger IRC  channel
+       Report  bugs at http://bugs.hledger.org (or on the #hledger IRC channel
        or hledger mail list)
 
 
@@ -1472,7 +1477,7 @@
 
 
 SEE ALSO
-       hledger(1),      hledger-ui(1),     hledger-web(1),     hledger-api(1),
+       hledger(1),     hledger-ui(1),     hledger-web(1),      hledger-api(1),
        hledger_csv(5), hledger_journal(5), hledger_timeclock(5), hledger_time-
        dot(5), ledger(1)
 
@@ -1480,4 +1485,4 @@
 
 
 
-hledger 1.18                       June 2020                hledger_journal(5)
+hledger 1.18.1                     June 2020                hledger_journal(5)
diff --git a/hledger_timeclock.5 b/hledger_timeclock.5
--- a/hledger_timeclock.5
+++ b/hledger_timeclock.5
@@ -1,5 +1,5 @@
 
-.TH "hledger_timeclock" "5" "June 2020" "hledger 1.18" "hledger User Manuals"
+.TH "hledger_timeclock" "5" "June 2020" "hledger 1.18.1" "hledger User Manuals"
 
 
 
diff --git a/hledger_timeclock.info b/hledger_timeclock.info
--- a/hledger_timeclock.info
+++ b/hledger_timeclock.info
@@ -4,8 +4,8 @@
 
 File: hledger_timeclock.info,  Node: Top,  Up: (dir)
 
-hledger_timeclock(5) hledger 1.18
-*********************************
+hledger_timeclock(5) hledger 1.18.1
+***********************************
 
 Timeclock - the time logging format of timeclock.el, as read by hledger
 
diff --git a/hledger_timeclock.txt b/hledger_timeclock.txt
--- a/hledger_timeclock.txt
+++ b/hledger_timeclock.txt
@@ -78,4 +78,4 @@
 
 
 
-hledger 1.18                       June 2020              hledger_timeclock(5)
+hledger 1.18.1                     June 2020              hledger_timeclock(5)
diff --git a/hledger_timedot.5 b/hledger_timedot.5
--- a/hledger_timedot.5
+++ b/hledger_timedot.5
@@ -1,5 +1,5 @@
 
-.TH "hledger_timedot" "5" "June 2020" "hledger 1.18" "hledger User Manuals"
+.TH "hledger_timedot" "5" "June 2020" "hledger 1.18.1" "hledger User Manuals"
 
 
 
diff --git a/hledger_timedot.info b/hledger_timedot.info
--- a/hledger_timedot.info
+++ b/hledger_timedot.info
@@ -4,8 +4,8 @@
 
 File: hledger_timedot.info,  Node: Top,  Up: (dir)
 
-hledger_timedot(5) hledger 1.18
-*******************************
+hledger_timedot(5) hledger 1.18.1
+*********************************
 
 Timedot - hledger's human-friendly time logging format
 
diff --git a/hledger_timedot.txt b/hledger_timedot.txt
--- a/hledger_timedot.txt
+++ b/hledger_timedot.txt
@@ -161,4 +161,4 @@
 
 
 
-hledger 1.18                       June 2020                hledger_timedot(5)
+hledger 1.18.1                     June 2020                hledger_timedot(5)
